# HG changeset patch # User Thierry Florac # Date 1530110521 -7200 # Node ID d8261b6287871e0eb1448fdff2c6758a4e58850e # Parent 37891d35596b4d20476d4cd72cdd4bd996133d14# Parent 5ee242d90312088b82c38198ad6104c7d6ced3da ??? diff -r 5ee242d90312 -r d8261b628787 .hgtags --- a/.hgtags Wed Jun 27 16:34:12 2018 +0200 +++ b/.hgtags Wed Jun 27 16:42:01 2018 +0200 @@ -15,3 +15,6 @@ d73905f6a2eb2949b3979671bf261965473bb7b9 0.1.11 5d94baef6923642af27a9f30f377d45f67f04bbf 0.1.12 cf2d19055dd754ce3ed30be24f83dae351b3ae5c 0.1.13 +95026785904d443509d93895ddf761b7967d9d46 0.1.14 +95026785904d443509d93895ddf761b7967d9d46 0.1.14 +1978e4dad1d8f950411807ed2df23fd030a39b60 0.1.14 diff -r 5ee242d90312 -r d8261b628787 buildout.cfg --- a/buildout.cfg Wed Jun 27 16:34:12 2018 +0200 +++ b/buildout.cfg Wed Jun 27 16:42:01 2018 +0200 @@ -7,12 +7,6 @@ show-picked-versions = true newest = false -allow-hosts = - bitbucket.org - *.python.org - *.sourceforge.net - github.com - versions = versions newest = false #allow-picked-versions = false @@ -92,4 +86,4 @@ eggs = pyams_content [test] [versions] -pyams_content = 0.1.14 +pyams_content = 0.1.15 diff -r 5ee242d90312 -r d8261b628787 docs/HISTORY.txt --- a/docs/HISTORY.txt Wed Jun 27 16:34:12 2018 +0200 +++ b/docs/HISTORY.txt Wed Jun 27 16:42:01 2018 +0200 @@ -1,6 +1,24 @@ History ======= +0.1.15 +------ + - added "basic" and "navigation" illustration components + - added pictogram selection widget + - added optional pictogram to links + - added generic menu feature + - added key numbers portlet + - added site container "rename" view to change object URL + - include quick search results table in main dashboard view + +0.1.14 +------ + - added header and footer management features + - added renderer for each kind of paragraphs + - added preview for a each paragraph one by one + - added optional checks before publishing content + - updated groups management in forms + 0.1.13 ------ - renamed factories to use snake_case on functions diff -r 5ee242d90312 -r d8261b628787 setup.py --- a/setup.py Wed Jun 27 16:34:12 2018 +0200 +++ b/setup.py Wed Jun 27 16:42:01 2018 +0200 @@ -22,7 +22,7 @@ README = os.path.join(DOCS, 'README.txt') HISTORY = os.path.join(DOCS, 'HISTORY.txt') -version = '0.1.14' +version = '0.1.15' long_description = open(README).read() + '\n\n' + open(HISTORY).read() tests_require = [] diff -r 5ee242d90312 -r d8261b628787 src/pyams_content.egg-info/PKG-INFO --- a/src/pyams_content.egg-info/PKG-INFO Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content.egg-info/PKG-INFO Wed Jun 27 16:42:01 2018 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyams-content -Version: 0.1.13 +Version: 0.1.15 Summary: PyAMS base content interfaces and classes Home-page: http://hg.ztfy.org/pyams/pyams_content Author: Thierry Florac @@ -73,6 +73,21 @@ History ======= + 0.1.15 + ------ + - added "basic" illustration component + - added pictogram selection widget + - added optional pictogram to links + - added generic menu feature + + 0.1.14 + ------ + - added header and footer management features + - added renderer for each kind of paragraphs + - added preview for a each paragraph one by one + - added optional checks before publishing content + - updated groups management in forms + 0.1.13 ------ - renamed factories to use snake_case on functions diff -r 5ee242d90312 -r d8261b628787 src/pyams_content.egg-info/SOURCES.txt --- a/src/pyams_content.egg-info/SOURCES.txt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content.egg-info/SOURCES.txt Wed Jun 27 16:42:01 2018 +0200 @@ -43,6 +43,13 @@ src/pyams_content/component/illustration/zmi/paragraph.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 +src/pyams_content/component/keynumber/interfaces/__init__.py +src/pyams_content/component/keynumber/portlet/__init__.py +src/pyams_content/component/keynumber/portlet/interfaces/__init__.py +src/pyams_content/component/keynumber/portlet/zmi/__init__.py +src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt +src/pyams_content/component/keynumber/zmi/__init__.py src/pyams_content/component/links/__init__.py src/pyams_content/component/links/interfaces/__init__.py src/pyams_content/component/links/zmi/__init__.py @@ -50,6 +57,7 @@ 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 src/pyams_content/component/paragraph/contact.py src/pyams_content/component/paragraph/container.py src/pyams_content/component/paragraph/frame.py @@ -62,6 +70,7 @@ src/pyams_content/component/paragraph/verbatim.py src/pyams_content/component/paragraph/video.py src/pyams_content/component/paragraph/interfaces/__init__.py +src/pyams_content/component/paragraph/interfaces/audio.py src/pyams_content/component/paragraph/interfaces/contact.py src/pyams_content/component/paragraph/interfaces/frame.py src/pyams_content/component/paragraph/interfaces/header.py @@ -73,6 +82,7 @@ src/pyams_content/component/paragraph/interfaces/verbatim.py src/pyams_content/component/paragraph/interfaces/video.py src/pyams_content/component/paragraph/zmi/__init__.py +src/pyams_content/component/paragraph/zmi/audio.py src/pyams_content/component/paragraph/zmi/contact.py src/pyams_content/component/paragraph/zmi/container.py src/pyams_content/component/paragraph/zmi/frame.py @@ -87,10 +97,8 @@ src/pyams_content/component/paragraph/zmi/verbatim.py src/pyams_content/component/paragraph/zmi/video.py src/pyams_content/component/paragraph/zmi/templates/associations.pt -src/pyams_content/component/paragraph/zmi/templates/html-render.pt src/pyams_content/component/paragraph/zmi/templates/paragraph-title-icon.pt src/pyams_content/component/paragraph/zmi/templates/paragraph-title-toolbar.pt -src/pyams_content/component/paragraph/zmi/templates/raw-render.pt src/pyams_content/component/theme/__init__.py src/pyams_content/component/theme/portlet.py src/pyams_content/component/theme/interfaces/__init__.py @@ -113,7 +121,6 @@ src/pyams_content/component/video/provider/zmi/templates/youtube-render.pt src/pyams_content/component/video/zmi/__init__.py src/pyams_content/component/video/zmi/paragraph.py -src/pyams_content/component/video/zmi/templates/video-render.pt src/pyams_content/component/video/zmi/templates/video-settings.pt src/pyams_content/doctests/README.txt src/pyams_content/features/__init__.py @@ -125,6 +132,33 @@ src/pyams_content/features/checker/__init__.py src/pyams_content/features/checker/interfaces.py src/pyams_content/features/checker/zmi/__init__.py +src/pyams_content/features/footer/__init__.py +src/pyams_content/features/footer/interfaces/__init__.py +src/pyams_content/features/footer/skin/__init__.py +src/pyams_content/features/footer/zmi/__init__.py +src/pyams_content/features/footer/zmi/__init__.py.orig +src/pyams_content/features/footer/zmi/templates/renderer-settings.pt +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/zmi/__init__.py +src/pyams_content/features/header/zmi/templates/renderer-settings.pt +src/pyams_content/features/menu/__init__.py +src/pyams_content/features/menu/interfaces/__init__.py +src/pyams_content/features/menu/portlet/__init__.py +src/pyams_content/features/menu/portlet/navigation/__init__.py +src/pyams_content/features/menu/portlet/navigation/double.py +src/pyams_content/features/menu/portlet/navigation/simple.py +src/pyams_content/features/menu/portlet/navigation/interfaces/__init__.py +src/pyams_content/features/menu/portlet/navigation/interfaces/double.py +src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py +src/pyams_content/features/menu/portlet/navigation/zmi/__init__.py +src/pyams_content/features/menu/portlet/navigation/zmi/double.py +src/pyams_content/features/menu/portlet/navigation/zmi/simple.py +src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt +src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt +src/pyams_content/features/menu/zmi/__init__.py +src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt src/pyams_content/features/preview/__init__.py src/pyams_content/features/preview/interfaces.py src/pyams_content/features/preview/zmi/__init__.py @@ -132,6 +166,7 @@ src/pyams_content/features/preview/zmi/templates/preview.pt src/pyams_content/features/renderer/__init__.py src/pyams_content/features/renderer/interfaces/__init__.py +src/pyams_content/features/renderer/skin/__init__.py src/pyams_content/features/renderer/zmi/__init__.py src/pyams_content/features/renderer/zmi/widget.py src/pyams_content/features/renderer/zmi/templates/renderer-input.pt @@ -159,7 +194,9 @@ src/pyams_content/reference/pictograms/interfaces/__init__.py src/pyams_content/reference/pictograms/zmi/__init__.py src/pyams_content/reference/pictograms/zmi/manager.py +src/pyams_content/reference/pictograms/zmi/widget.py src/pyams_content/reference/pictograms/zmi/templates/manager-selection.pt +src/pyams_content/reference/pictograms/zmi/templates/pictogram-header.pt src/pyams_content/reference/zmi/__init__.py src/pyams_content/reference/zmi/table.py src/pyams_content/root/__init__.py @@ -179,17 +216,25 @@ src/pyams_content/shared/blog/zmi/manager.py src/pyams_content/shared/common/__init__.py src/pyams_content/shared/common/manager.py +src/pyams_content/shared/common/portal.py src/pyams_content/shared/common/security.py src/pyams_content/shared/common/types.py src/pyams_content/shared/common/interfaces/__init__.py src/pyams_content/shared/common/interfaces/types.py src/pyams_content/shared/common/interfaces/zmi.py +src/pyams_content/shared/common/portlet/__init__.py +src/pyams_content/shared/common/portlet/content/__init__.py +src/pyams_content/shared/common/portlet/content/interfaces/__init__.py +src/pyams_content/shared/common/portlet/content/skin/__init__.py +src/pyams_content/shared/common/portlet/content/zmi/__init__.py +src/pyams_content/shared/common/portlet/content/zmi/preview.pt src/pyams_content/shared/common/zmi/__init__.py src/pyams_content/shared/common/zmi/dashboard.py src/pyams_content/shared/common/zmi/header.py src/pyams_content/shared/common/zmi/i18n.py src/pyams_content/shared/common/zmi/manager.py src/pyams_content/shared/common/zmi/owner.py +src/pyams_content/shared/common/zmi/portal.py src/pyams_content/shared/common/zmi/properties.py src/pyams_content/shared/common/zmi/search.py src/pyams_content/shared/common/zmi/security.py @@ -198,8 +243,10 @@ src/pyams_content/shared/common/zmi/types.py src/pyams_content/shared/common/zmi/workflow.py src/pyams_content/shared/common/zmi/templates/advanced-search.pt +src/pyams_content/shared/common/zmi/templates/check-input.pt src/pyams_content/shared/common/zmi/templates/dashboard.pt src/pyams_content/shared/common/zmi/templates/header.pt +src/pyams_content/shared/common/zmi/templates/preview-input.pt src/pyams_content/shared/common/zmi/templates/wf-archive-message.pt src/pyams_content/shared/common/zmi/templates/wf-archiving-message.pt src/pyams_content/shared/common/zmi/templates/wf-cancel-archiving-message.pt @@ -236,12 +283,9 @@ src/pyams_content/shared/imagemap/zmi/container.py src/pyams_content/shared/imagemap/zmi/paragraph.py src/pyams_content/shared/imagemap/zmi/properties.py -src/pyams_content/shared/imagemap/zmi/render.py src/pyams_content/shared/imagemap/zmi/widget.py src/pyams_content/shared/imagemap/zmi/templates/container.pt src/pyams_content/shared/imagemap/zmi/templates/imagemap-preview.pt -src/pyams_content/shared/imagemap/zmi/templates/paragraph-render.pt -src/pyams_content/shared/imagemap/zmi/templates/render.pt src/pyams_content/shared/imagemap/zmi/templates/widget-input.pt src/pyams_content/shared/logo/__init__.py src/pyams_content/shared/logo/manager.py @@ -275,16 +319,12 @@ src/pyams_content/shared/view/interfaces/__init__.py src/pyams_content/shared/view/portlet/__init__.py src/pyams_content/shared/view/portlet/interfaces.py -src/pyams_content/shared/view/portlet/templates/view-items-list.pt -src/pyams_content/shared/view/portlet/templates/view-with-images-list.pt src/pyams_content/shared/view/portlet/zmi/__init__.py src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt src/pyams_content/shared/view/zmi/__init__.py src/pyams_content/shared/view/zmi/properties.py src/pyams_content/shared/view/zmi/reference.py -src/pyams_content/shared/view/zmi/render.py src/pyams_content/shared/view/zmi/theme.py -src/pyams_content/shared/view/zmi/templates/render.pt src/pyams_content/skin/__init__.py src/pyams_content/skin/routes.py src/pyams_content/skin/resources/css/pyams_content.css diff -r 5ee242d90312 -r d8261b628787 src/pyams_content.egg-info/requires.txt --- a/src/pyams_content.egg-info/requires.txt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content.egg-info/requires.txt Wed Jun 27 16:42:01 2018 +0200 @@ -4,7 +4,7 @@ persistent pyams_catalog pyams_file -pyams_form +pyams_form>=0.1.13 pyams_i18n pyams_mail pyams_pagelet @@ -14,7 +14,7 @@ pyams_skin pyams_template pyams_thesaurus -pyams_utils +pyams_utils>=0.1.15 pyams_viewlet pyams_workflow pyams_zmi diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/__init__.py --- a/src/pyams_content/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -27,7 +27,7 @@ CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, COMMENT_CONTENT_PERMISSION, PUBLISH_CONTENT_PERMISSION from pyams_content.interfaces import WEBMASTER_ROLE, PILOT_ROLE, MANAGER_ROLE, OWNER_ROLE, CONTRIBUTOR_ROLE, \ READER_ROLE, OPERATOR_ROLE, GUEST_ROLE - from pyams_security.interfaces import ADMIN_USER_ID + from pyams_security.interfaces import ADMIN_USER_ID, SYSTEM_ADMIN_ROLE from pyams_thesaurus.interfaces import CREATE_THESAURUS_PERMISSION, ADMIN_THESAURUS_PERMISSION from pyams_utils.interfaces import PUBLIC_PERMISSION, VIEW_PERMISSION, MANAGE_PERMISSION, \ VIEW_SYSTEM_PERMISSION, MANAGE_ROLES_PERMISSION, MANAGE_SKIN_PERMISSION @@ -57,7 +57,9 @@ MANAGE_SITE_ROOT_PERMISSION, MANAGE_SITE_PERMISSION, MANAGE_TOOL_PERMISSION, CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, MANAGE_SKIN_PERMISSION, COMMENT_CONTENT_PERMISSION, PUBLISH_CONTENT_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager', 'role:pyams.Webmaster'}}) + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE), + 'role:{0}'.format(WEBMASTER_ROLE)}}) config.register_role({'id': PILOT_ROLE, 'title': _("Pilot (role)"), 'permissions': {PUBLIC_PERMISSION, VIEW_PERMISSION, MANAGE_PERMISSION, @@ -65,13 +67,17 @@ MANAGE_SITE_PERMISSION, MANAGE_TOOL_PERMISSION, MANAGE_CONTENT_PERMISSION, COMMENT_CONTENT_PERMISSION, PUBLISH_CONTENT_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager', 'role:pyams.Webmaster'}}) + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE), + 'role:{0}'.format(WEBMASTER_ROLE)}}) config.register_role({'id': MANAGER_ROLE, 'title': _("Manager (role)"), 'permissions': {PUBLIC_PERMISSION, VIEW_PERMISSION, MANAGE_PERMISSION, VIEW_SYSTEM_PERMISSION, MANAGE_CONTENT_PERMISSION, COMMENT_CONTENT_PERMISSION, PUBLISH_CONTENT_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager', 'role:pyams.Webmaster', + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE), + 'role:{0}'.format(WEBMASTER_ROLE), 'role:pyams.Pilot'}}) config.register_role({'id': OWNER_ROLE, 'title': _("Owner (role)"), @@ -84,20 +90,32 @@ VIEW_SYSTEM_PERMISSION, CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, COMMENT_CONTENT_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager', 'role:pyams.Webmaster', - 'role:pyams.Pilot', 'role:pyams.Owner'}}) + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE), + 'role:{0}'.format(WEBMASTER_ROLE), + 'role:pyams.Pilot', + 'role:pyams.Owner'}}) config.register_role({'id': READER_ROLE, 'title': _("Reader (role)"), 'permissions': {PUBLIC_PERMISSION, VIEW_PERMISSION, MANAGE_PERMISSION, VIEW_SYSTEM_PERMISSION, COMMENT_CONTENT_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager', 'role:pyams.Webmaster', - 'role:pyams.Pilot', 'role:pyams.Manager', 'role:pyams.Contributor'}}) + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE), + 'role:{0}'.format(WEBMASTER_ROLE), + 'role:pyams.Pilot', + 'role:pyams.Manager', + 'role:pyams.Contributor'}}) config.register_role({'id': OPERATOR_ROLE, 'title': _("Operator (role)"), 'permissions': {PUBLIC_PERMISSION, VIEW_PERMISSION, VIEW_SYSTEM_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager'}}) + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE)}}) config.register_role({'id': GUEST_ROLE, 'title': _("Guest user (role)"), 'permissions': {PUBLIC_PERMISSION, VIEW_PERMISSION}, - 'managers': {ADMIN_USER_ID, 'role:system.Manager', 'role:pyams.Webmaster', - 'role:pyams.Pilot', 'role:pyams.Manager', 'role:pyams.Contributor'}}) + 'managers': {ADMIN_USER_ID, + 'role:{0}'.format(SYSTEM_ADMIN_ROLE), + 'role:{0}'.format(WEBMASTER_ROLE), + 'role:pyams.Pilot', + 'role:pyams.Manager', + 'role:pyams.Contributor'}}) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/association/__init__.py --- a/src/pyams_content/component/association/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/association/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationItem, IAssociationTarget +from pyams_content.component.association.interfaces import IAssociationItem, IAssociationContainerTarget from pyams_form.interfaces.form import IFormContextPermissionChecker from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent @@ -52,14 +52,14 @@ @property def edit_permission(self): - content = get_parent(self.context, IAssociationTarget) + content = get_parent(self.context, IAssociationContainerTarget) return IFormContextPermissionChecker(content).edit_permission @subscriber(IObjectAddedEvent, context_selector=IAssociationItem) def handle_added_association(event): """Handle added association item""" - content = get_parent(event.object, IAssociationTarget) + content = get_parent(event.object, IAssociationContainerTarget) if content is not None: get_current_registry().notify(ObjectModifiedEvent(content)) @@ -67,7 +67,7 @@ @subscriber(IObjectModifiedEvent, context_selector=IAssociationItem) def handle_modified_association(event): """Handle modified association item""" - content = get_parent(event.object, IAssociationTarget) + content = get_parent(event.object, IAssociationContainerTarget) if content is not None: get_current_registry().notify(ObjectModifiedEvent(content)) @@ -75,6 +75,6 @@ @subscriber(IObjectRemovedEvent, context_selector=IAssociationItem) def handle_removed_association(event): """Handle removed association item""" - content = get_parent(event.object, IAssociationTarget) + content = get_parent(event.object, IAssociationContainerTarget) if content is not None: get_current_registry().notify(ObjectModifiedEvent(content)) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/association/container.py --- a/src/pyams_content/component/association/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/association/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationContainer, IAssociationTarget, \ +from pyams_content.component.association.interfaces import IAssociationContainer, IAssociationContainerTarget, \ ASSOCIATION_CONTAINER_KEY, IAssociationItem, IAssociationInfo from pyams_content.features.checker.interfaces import IContentChecker from zope.location.interfaces import ISublocations @@ -58,13 +58,13 @@ return filter(lambda x: IAssociationItem(x).visible, self.values()) -@adapter_config(context=IAssociationTarget, provides=IAssociationContainer) +@adapter_config(context=IAssociationContainerTarget, provides=IAssociationContainer) def association_container_factory(target): """Associations container factory""" return get_annotation_adapter(target, ASSOCIATION_CONTAINER_KEY, AssociationContainer, name='++ass++') -@adapter_config(name='ass', context=IAssociationTarget, provides=ITraversable) +@adapter_config(name='ass', context=IAssociationContainerTarget, provides=ITraversable) class AssociationContainerNamespace(ContextAdapter): """Associations container ++ass++ namespace""" @@ -73,7 +73,7 @@ return registry.queryAdapter(self.context, IAssociationContainer, name=name or '') -@adapter_config(name='associations', context=IAssociationTarget, provides=ISublocations) +@adapter_config(name='associations', context=IAssociationContainerTarget, provides=ISublocations) class AssociationContainerSublocations(ContextAdapter): """Associations container sub-locations adapter""" @@ -81,7 +81,7 @@ return IAssociationContainer(self.context).values() -@adapter_config(name='associations', context=IAssociationTarget, provides=IContentChecker) +@adapter_config(name='associations', context=IAssociationContainerTarget, provides=IContentChecker) class AssociationsContentChecker(BaseContentChecker): """Associations content checker""" @@ -110,7 +110,7 @@ def __init__(self, context=None): terms = [] - target = get_parent(context, IAssociationTarget) + target = get_parent(context, IAssociationContainerTarget) if target is not None: terms = [SimpleTerm(link.__name__, title=IAssociationInfo(link).inner_title) for link in IAssociationContainer(target).values()] diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/association/interfaces/__init__.py --- a/src/pyams_content/component/association/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/association/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -74,7 +74,7 @@ """Get list of visible items""" -class IAssociationTarget(IAttributeAnnotatable): +class IAssociationContainerTarget(IAttributeAnnotatable): """Associations container target interface""" @@ -82,6 +82,10 @@ """Association renderer adapter interface""" +# +# Associations paragraph +# + ASSOCIATION_PARAGRAPH_TYPE = 'Associations' ASSOCIATION_PARAGRAPH_NAME = _("Associations") ASSOCIATION_PARAGRAPH_RENDERERS = 'PyAMS.associations.renderers' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/association/zmi/__init__.py --- a/src/pyams_content/component/association/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/association/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -17,7 +17,8 @@ import json # import interfaces -from pyams_content.component.association.interfaces import IAssociationTarget, IAssociationContainer, IAssociationInfo +from pyams_content.component.association.interfaces import IAssociationContainerTarget, IAssociationContainer, \ + IAssociationInfo from pyams_content.component.association.zmi.interfaces import IAssociationsParentForm, IAssociationsView from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION from pyams_form.interfaces.form import IInnerSubForm @@ -73,7 +74,7 @@ """Association item properties edit form, JSON renderer""" def get_associations_table(self): - target = get_parent(self.context, IAssociationTarget) + target = get_parent(self.context, IAssociationContainerTarget) return { 'status': 'success', 'message': self.request.localizer.translate(self.successMessage), @@ -87,7 +88,7 @@ # Content associations view # -@viewlet_config(name='associations.menu', context=IAssociationTarget, layer=IPyAMSLayer, +@viewlet_config(name='associations.menu', context=IAssociationContainerTarget, layer=IPyAMSLayer, manager=IPropertiesMenu, permission=VIEW_SYSTEM_PERMISSION, weight=60) class AssociationsMenu(MenuItem): """Associations menu""" @@ -117,16 +118,15 @@ @property def data_attributes(self): registry = get_current_registry() - target = get_parent(self.context, IAssociationTarget) + target = get_parent(self.context, IAssociationContainerTarget) container = registry.getAdapter(target, IAssociationContainer, name=self.associations_name) attributes = super(AssociationsTable, self).data_attributes - attributes['table'] = { - 'id': self.id, + 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' - } + }) return attributes @reify @@ -134,7 +134,7 @@ return list(super(AssociationsTable, self).values) -@adapter_config(context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IValues) +@adapter_config(context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IValues) class AssociationsTableValuesAdapter(ContextRequestViewAdapter): """Associations table values adapter""" @@ -144,7 +144,7 @@ return registry.getAdapter(self.context, IAssociationContainer, name=self.view.associations_name).values() -@adapter_config(name='sorter', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='sorter', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='sorter', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) class AssociationsTableSorterColumn(ProtectedFormObjectMixin, SorterColumn): """Associations table sorter column""" @@ -159,7 +159,7 @@ return {'status': 'success'} -@adapter_config(name='show-hide', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), +@adapter_config(name='show-hide', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='show-hide', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) @@ -174,7 +174,7 @@ return switch_element_visibility(request, IAssociationContainer) -@adapter_config(name='pictogram', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='pictogram', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='pictogram', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) class AssociationsTablePictogramColumn(ImageColumn): """Associations table pictogram column""" @@ -190,7 +190,7 @@ return self.request.localizer.translate(item.icon_hint) -@adapter_config(name='name', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='name', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='name', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) class AssociationsTablePublicNameColumn(NameColumn): """Associations table name column""" @@ -208,7 +208,7 @@ return title -@adapter_config(name='inner_name', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='inner_name', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='inner_name', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) class AssociationsTableInnerNameColumn(I18nColumn, GetAttrColumn): """Associations table inner name column""" @@ -224,7 +224,7 @@ return '--' -@adapter_config(name='size', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='size', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='size', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) class AssociationsTableSizeColumn(I18nColumn, GetAttrColumn): """Associations table size column""" @@ -240,7 +240,7 @@ return '--' -@adapter_config(name='trash', context=(IAssociationTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='trash', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) @adapter_config(name='trash', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) class AssociationsTableTrashColumn(ProtectedFormObjectMixin, TrashColumn): """Associations table trash column""" @@ -253,7 +253,7 @@ output = delete_container_element(request) if output.get('status') == 'success': from pyams_content.component.paragraph.zmi import get_json_paragraph_toolbar_refresh_event - parent = get_parent(request.context, IAssociationTarget) + parent = get_parent(request.context, IAssociationContainerTarget) output.update({ 'handle_json': True, 'events': [ @@ -264,7 +264,7 @@ return output -@pagelet_config(name='associations.html', context=IAssociationTarget, layer=IPyAMSLayer, +@pagelet_config(name='associations.html', context=IAssociationContainerTarget, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @implementer(IAssociationsView) class AssociationsContainerView(ContainerAdminView, Pagelet): @@ -274,7 +274,7 @@ table_class = AssociationsTable -@pagelet_config(name='associations-dialog.html', context=IAssociationTarget, layer=IPyAMSLayer, +@pagelet_config(name='associations-dialog.html', context=IAssociationContainerTarget, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @implementer(IAssociationsParentForm) class AssociationsContainerDialogView(AdminDialogDisplayForm): @@ -287,7 +287,7 @@ fields = field.Fields(Interface) -@adapter_config(name='associations', context=(IAssociationTarget, IPyAMSLayer, IAssociationsParentForm), +@adapter_config(name='associations', context=(IAssociationContainerTarget, IPyAMSLayer, IAssociationsParentForm), provides=IInnerSubForm) @implementer(IAssociationsView) class AssociationsView(InnerTableView): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/extfile/interfaces/__init__.py --- a/src/pyams_content/component/extfile/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/extfile/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationItem, IAssociationTarget +from pyams_content.component.association.interfaces import IAssociationItem, IAssociationContainerTarget # import packages from pyams_i18n.schema import I18nTextLineField, I18nTextField, I18nFileField, I18nThumbnailImageField, \ @@ -91,5 +91,5 @@ required=True) -class IExtFileContainerTarget(IAssociationTarget): +class IExtFileContainerTarget(IAssociationContainerTarget): """External files container marker interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/extfile/zmi/container.py --- a/src/pyams_content/component/extfile/zmi/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/extfile/zmi/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,8 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationTarget, IAssociationContainer, IAssociationInfo +from pyams_content.component.association.interfaces import IAssociationContainerTarget, IAssociationContainer, \ + IAssociationInfo from pyams_content.component.extfile.interfaces import IExtFile, IExtImage from pyams_i18n.interfaces import II18n from pyams_skin.layer import IPyAMSLayer @@ -37,7 +38,7 @@ def get_files_list(request): """Get container files in JSON format for TinyMCE editor""" result = [] - target = get_parent(request.context, IAssociationTarget) + target = get_parent(request.context, IAssociationContainerTarget) if target is not None: container = IAssociationContainer(target) result.extend([{'title': IAssociationInfo(item).user_title, @@ -52,7 +53,7 @@ def get_images_list(request): """Get container images in JSON format for TinyMCE editor""" result = [] - target = get_parent(request.context, IAssociationTarget) + target = get_parent(request.context, IAssociationContainerTarget) if target is not None: container = IAssociationContainer(target) result.extend([{'title': IAssociationInfo(item).user_title, diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/gallery/interfaces/__init__.py --- a/src/pyams_content/component/gallery/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/gallery/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -93,7 +93,7 @@ title = I18nTextLineField(title=_("Title"), description=_("Gallery title, as shown in front-office"), - required=True) + required=False) description = I18nTextField(title=_("Description"), description=_("Gallery description displayed by front-office template"), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/illustration/__init__.py --- a/src/pyams_content/component/illustration/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/illustration/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -17,7 +17,8 @@ # import interfaces from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationTarget, \ - ILLUSTRATION_KEY, ILLUSTRATION_RENDERERS + ILLUSTRATION_KEY, ILLUSTRATION_RENDERERS, IBasicIllustration, IBasicIllustrationTarget, BASIC_ILLUSTRATION_KEY, \ + ILinkIllustrationTarget, LINK_ILLUSTRATION_KEY, ILinkIllustration from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE from pyams_file.interfaces import IFileInfo, IImage, IResponsiveImage from pyams_i18n.interfaces import INegotiator, II18n, II18nManager @@ -46,17 +47,14 @@ from pyams_content import _ -@implementer(IIllustration) -@factory_config(provided=IIllustration) -class Illustration(RenderedContentMixin, Persistent, Contained): +@implementer(IBasicIllustration) +@factory_config(provided=IBasicIllustration) +class BasicIllustration(Persistent, Contained): """Illustration persistent class""" _data = I18nFileProperty(IIllustration['data']) title = FieldProperty(IIllustration['title']) alt_title = FieldProperty(IIllustration['alt_title']) - description = FieldProperty(IIllustration['description']) - author = FieldProperty(IIllustration['author']) - renderer = FieldProperty(IIllustration['renderer']) @property def data(self): @@ -69,6 +67,36 @@ if IImage.providedBy(data): alsoProvides(data, IResponsiveImage) + def has_data(self): + if not self._data: + return False + for data in self._data.values(): + if bool(data): + return True + return False + + +@adapter_config(context=IBasicIllustrationTarget, provides=IIllustration) +def basic_illustration_factory(context): + """Basic illustration factory""" + + def illustration_callback(illustration): + get_current_registry().notify(ObjectAddedEvent(illustration, context, illustration.__name__)) + + return get_annotation_adapter(context, BASIC_ILLUSTRATION_KEY, BasicIllustration, + name='++illustration++', + callback=illustration_callback) + + +@implementer(IIllustration) +@factory_config(provided=IIllustration) +class Illustration(RenderedContentMixin, BasicIllustration): + """Illustration persistent class""" + + description = FieldProperty(IIllustration['description']) + author = FieldProperty(IIllustration['author']) + renderer = FieldProperty(IIllustration['renderer']) + @adapter_config(context=IIllustrationTarget, provides=IIllustration) def illustration_factory(context): @@ -82,6 +110,20 @@ callback=illustration_callback) +@adapter_config(context=ILinkIllustrationTarget, provides=ILinkIllustration) +@adapter_config(name='link', context=ILinkIllustrationTarget, provides=IIllustration) +def link_illustration_factory(context): + """Link illustration factory""" + + def illustration_callback(illustration): + get_current_registry().notify(ObjectAddedEvent(illustration, context, illustration.__name__)) + + return get_annotation_adapter(context, LINK_ILLUSTRATION_KEY, BasicIllustration, + markers=ILinkIllustration, + name='++illustration++link', + callback=illustration_callback) + + def update_illustration_properties(illustration): """Update missing file properties""" request = check_request() @@ -95,21 +137,21 @@ info.description = II18n(illustration).get_attribute('alt_title', lang, request) -@subscriber(IObjectAddedEvent, context_selector=IIllustration) +@subscriber(IObjectAddedEvent, context_selector=IBasicIllustration) def handle_added_illustration(event): """Handle added illustration""" illustration = event.object update_illustration_properties(illustration) -@subscriber(IObjectModifiedEvent, context_selector=IIllustration) +@subscriber(IObjectModifiedEvent, context_selector=IBasicIllustration) def handle_modified_illustration(event): """Handle modified illustration""" illustration = event.object update_illustration_properties(illustration) -@adapter_config(name='illustration', context=IIllustrationTarget, provides=ITraversable) +@adapter_config(name='illustration', context=IBasicIllustrationTarget, provides=ITraversable) class IllustrationNamespace(ContextAdapter): """++illustration++ namespace adapter""" @@ -118,12 +160,14 @@ return registry.queryAdapter(self.context, IIllustration, name=name) -@adapter_config(name='illustration', context=IIllustrationTarget, provides=ISublocations) +@adapter_config(name='illustration', context=IBasicIllustrationTarget, provides=ISublocations) class IllustrationSublocations(ContextAdapter): """Illustration sub-locations adapter""" def sublocations(self): - return IIllustration(self.context), + registry = get_global_registry() + for name, adapter in registry.getAdapters((self, ), IBasicIllustration): + yield adapter @adapter_config(context=IIllustration, provides=IContentChecker) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/illustration/interfaces/__init__.py --- a/src/pyams_content/component/illustration/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/illustration/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -22,6 +22,7 @@ from zope.annotation.interfaces import IAttributeAnnotatable # import packages +from zope.interface import Interface from zope.schema import Choice, TextLine from pyams_content import _ @@ -31,17 +32,24 @@ # Illustration # +BASIC_ILLUSTRATION_KEY = 'pyams_content.illustration.base' + ILLUSTRATION_KEY = 'pyams_content.illustration' ILLUSTRATION_RENDERERS = 'PyAMS.illustration.renderers' +LINK_ILLUSTRATION_KEY = '{0}::link'.format(ILLUSTRATION_KEY) -class IIllustration(IRenderedContent): - """Illustration paragraph""" + +class IBasicIllustration(Interface): + """Basic illustration interface""" data = I18nThumbnailMediaField(title=_("Image or video data"), description=_("Image or video content"), required=False) + def has_data(self): + """Check if data is provided in any language""" + title = I18nTextLineField(title=_("Legend"), required=False) @@ -49,6 +57,10 @@ description=_("Alternate title used to describe image content"), required=False) + +class IIllustration(IBasicIllustration, IRenderedContent): + """Illustration paragraph""" + description = I18nTextField(title=_("Description"), description=_(""), required=False) @@ -63,9 +75,25 @@ default='default') -class IIllustrationTarget(IAttributeAnnotatable): - """Illustration target marker interface""" +class ILinkIllustration(IBasicIllustration): + """Navigation link illustration interface""" + + +class IBasicIllustrationTarget(IAttributeAnnotatable): + """Basic illustration target marker interface""" + +class IIllustrationTarget(IBasicIllustrationTarget): + """Illustration target interface""" + + +class ILinkIllustrationTarget(IBasicIllustrationTarget): + """Link illustration target interface""" + + +# +# Illustration paragraph +# ILLUSTRATION_PARAGRAPH_TYPE = 'Illustration' ILLUSTRATION_PARAGRAPH_NAME = _("Illustration") diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/illustration/zmi/__init__.py --- a/src/pyams_content/component/illustration/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/illustration/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,16 +16,16 @@ # import standard library # import interfaces -from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationTarget +from pyams_content.component.illustration.interfaces import IBasicIllustration, IBasicIllustrationTarget, \ + IIllustration, IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph import IBaseParagraph -from pyams_content.component.paragraph.zmi.interfaces import IParagraphContainerTable, IParagraphTitleToolbar from pyams_form.interfaces.form import IInnerSubForm, IWidgetsPrefixViewletsManager from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from pyams_zmi.interfaces import IPropertiesEditForm from transaction.interfaces import ITransactionManager # import packages +from pyams_content.component.illustration.zmi.paragraph import ParagraphContainerIllustrationMarker from pyams_content.component.paragraph.zmi import get_json_paragraph_markers_refresh_event from pyams_content.features.renderer.zmi.widget import RendererFieldWidget from pyams_skin.event import get_json_form_refresh_event, get_json_widget_refresh_event @@ -42,38 +42,57 @@ # Illustration properties inner edit form # -@viewlet_config(name='illustration', context=IIllustrationTarget, layer=IPyAMSLayer, view=IParagraphContainerTable, - manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=5) -@template_config(template='templates/paragraph-illustration-icon.pt', layer=IPyAMSLayer) -class ParagraphContainerIllustrationMarker(Viewlet): - """Paragraph container illustration marker column""" +@adapter_config(name='illustration', context=(IBasicIllustrationTarget, IPyAMSLayer, IPropertiesEditForm), + provides=IInnerSubForm) +class BasicIllustrationPropertiesInnerEditForm(InnerAdminEditForm): + """Basic illustration properties inner edit form""" + + prefix = 'basic_illustration_form.' + + css_class = 'form-group' + padding_class = '' + fieldset_class = 'bordered margin-top-10 padding-y-5' + + legend = _("Illustration") + legend_class = 'illustration switcher no-y-padding padding-right-10' + + fields = field.Fields(IBasicIllustration).omit('__parent__', '__name__') + + weight = 10 - weight = 5 - action_class = 'action illustration nowrap width-40' - icon_class = 'fa fa-fw fa-picture-o' - icon_hint = _("Illustration") + def getContent(self): + return IIllustration(self.context) - marker_type = 'illustration' + def check_mode(self): + if self.parent_form is not None: + self.mode = self.parent_form.mode - def render(self): - illustration = IIllustration(self.context, None) - if illustration and illustration.data: - for value in illustration.data.values(): - if value: - return super(ParagraphContainerIllustrationMarker, self).render() - return '' + @property + def switcher_state(self): + content = self.getContent() + if content.has_data(): + return 'open' + + def get_ajax_output(self, changes): + output = super(BasicIllustrationPropertiesInnerEditForm, self).get_ajax_output(changes) + updated = changes.get(IBasicIllustration, ()) + if 'data' in updated: + # we have to commit transaction to be able to handle blobs... + ITransactionManager(self.context).get().commit() + output.setdefault('events', []).append( + get_json_form_refresh_event(self.context, self.request, self.__class__)) + return output @adapter_config(name='illustration', context=(IIllustrationTarget, IPyAMSLayer, IPropertiesEditForm), provides=IInnerSubForm) -class IllustrationPropertiesInnerEditForm(InnerAdminEditForm): +class IllustrationPropertiesInnerEditForm(BasicIllustrationPropertiesInnerEditForm): """Illustration properties inner edit form""" prefix = 'illustration_form.' - css_class = 'form-group' - padding_class = '' - fieldset_class = 'margin-top-10 padding-y-5' + fields = field.Fields(IIllustration).omit('__parent__', '__name__') + fields['renderer'].widgetFactory = RendererFieldWidget @property def legend(self): @@ -87,20 +106,21 @@ if IBaseParagraph.providedBy(self.context): return 'illustration switcher no-y-padding padding-right-10 pull-left width-auto' else: - return 'illustration no-y-padding' + return 'illustration switcher no-y-padding' - fields = field.Fields(IIllustration).omit('__parent__', '__name__') - fields['renderer'].widgetFactory = RendererFieldWidget + @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 - weight = 10 - def getContent(self): - return IIllustration(self.context) - - def check_mode(self): - if self.parent_form is not None: - self.mode = self.parent_form.mode + @property + def switcher_state(self): + if not IBaseParagraph.providedBy(self.context): + return 'open' def updateWidgets(self, prefix=None): super(IllustrationPropertiesInnerEditForm, self).updateWidgets(prefix) @@ -109,13 +129,8 @@ def get_ajax_output(self, changes): output = super(IllustrationPropertiesInnerEditForm, self).get_ajax_output(changes) - updated = changes.get(IIllustration, ()) events = output.setdefault('events', []) - if 'data' in updated: - # we have to commit transaction to be able to handle blobs... - ITransactionManager(self.context).get().commit() - events.append(get_json_form_refresh_event(self.context, self.request, - IllustrationPropertiesInnerEditForm)) + if 'data' in changes.get(IBasicIllustration, ()): if IBaseParagraph.providedBy(self.context): if self.getContent().data: events.append(get_json_paragraph_markers_refresh_event(self.context, self.request, self, @@ -124,14 +139,31 @@ events.append(get_json_paragraph_markers_refresh_event(self.context, self.request, self, EmptyViewlet, ParagraphContainerIllustrationMarker.marker_type)) - elif 'renderer' in updated: + elif 'renderer' in changes.get(IIllustration, ()): events.append(get_json_widget_refresh_event(self.context, self.request, IllustrationPropertiesInnerEditForm, 'renderer')) return output -@viewlet_config(name='illustration-thumbnail', context=IIllustrationTarget, layer=IPyAMSLayer, - view=IllustrationPropertiesInnerEditForm, manager=IWidgetsPrefixViewletsManager) +@adapter_config(name='link-illustration', context=(ILinkIllustrationTarget, IPyAMSLayer, IPropertiesEditForm), + provides=IInnerSubForm) +class LinkIllustrationPropertiesInnerEditForm(BasicIllustrationPropertiesInnerEditForm): + """Link illustration properties inner edit form""" + + prefix = 'link_illustration_form.' + + legend = _("Navigation link illustration") + legend_class = 'illustration switcher no-y-padding' + + weight = 11 + + def getContent(self): + registry = self.request.registry + return registry.getAdapter(self.context, IIllustration, name='link') + + +@viewlet_config(name='illustration-thumbnail', context=IBasicIllustrationTarget, layer=IPyAMSLayer, + view=BasicIllustrationPropertiesInnerEditForm, manager=IWidgetsPrefixViewletsManager) @template_config(template='templates/illustration-thumbnail.pt', layer=IPyAMSLayer) class IllustrationThumbnail(Viewlet): """Paragraph illustration thumbnail""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/illustration/zmi/paragraph.py --- a/src/pyams_content/component/illustration/zmi/paragraph.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/illustration/zmi/paragraph.py Wed Jun 27 16:42:01 2018 +0200 @@ -18,13 +18,15 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, \ IParagraphContainer -from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationParagraph, \ - ILLUSTRATION_PARAGRAPH_TYPE -from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView +from pyams_content.component.illustration.interfaces import IIllustrationTarget, IIllustration, \ + IIllustrationParagraph, ILLUSTRATION_PARAGRAPH_TYPE +from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView, \ + IParagraphContainerTable, IParagraphTitleToolbar 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 pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from transaction.interfaces import ITransactionManager from z3c.form.interfaces import INPUT_MODE @@ -36,8 +38,9 @@ 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_template.template import template_config from pyams_utils.adapter import adapter_config -from pyams_viewlet.viewlet import viewlet_config +from pyams_viewlet.viewlet import viewlet_config, Viewlet from pyams_zmi.form import AdminDialogAddForm from z3c.form import field, button from zope.interface import implementer @@ -147,3 +150,29 @@ output.setdefault('events', []).append(get_json_form_refresh_event(self.context, self.request, IllustrationInnerEditForm)) return output + + +# +# Paragraph container illustration marker +# + +@viewlet_config(name='illustration', context=IIllustrationTarget, layer=IPyAMSLayer, view=IParagraphContainerTable, + manager=IParagraphTitleToolbar, permission=VIEW_SYSTEM_PERMISSION, weight=5) +@template_config(template='templates/paragraph-illustration-icon.pt', layer=IPyAMSLayer) +class ParagraphContainerIllustrationMarker(Viewlet): + """Paragraph container illustration marker column""" + + weight = 5 + action_class = 'action illustration nowrap width-40' + icon_class = 'fa fa-fw fa-picture-o' + icon_hint = _("Illustration") + + marker_type = 'illustration' + + def render(self): + illustration = IIllustration(self.context, None) + if illustration and illustration.data: + for value in illustration.data.values(): + if value: + return super(ParagraphContainerIllustrationMarker, self).render() + return '' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,204 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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 IKeyNumber, IKeyNumberContainerTarget, IKeyNumberContainer, \ + KEYNUMBER_CONTAINER_KEY +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE +from pyams_form.interfaces.form import IFormContextPermissionChecker +from pyams_i18n.interfaces import II18n, II18nManager, INegotiator +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent +from zope.location.interfaces import ISublocations +from zope.traversing.interfaces import ITraversable + +# import packages +from pyams_catalog.utils import index_object +from pyams_content.features.checker import BaseContentChecker +from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter +from pyams_utils.registry import get_current_registry, get_utility +from pyams_utils.request import check_request +from pyams_utils.traversing import get_parent +from persistent import Persistent +from pyramid.events import subscriber +from zope.container.contained import Contained +from zope.container.ordered import OrderedContainer +from zope.interface import implementer +from zope.lifecycleevent import ObjectModifiedEvent +from zope.location.location import locate +from zope.schema.fieldproperty import FieldProperty + +from pyams_content import _ + + +# +# Key number class and adapters +# + +@implementer(IKeyNumber) +class KeyNumber(Persistent, Contained): + """Key number persistent class""" + + visible = FieldProperty(IKeyNumber['visible']) + label = FieldProperty(IKeyNumber['label']) + number = FieldProperty(IKeyNumber['number']) + unit = FieldProperty(IKeyNumber['unit']) + text = FieldProperty(IKeyNumber['text']) + + +@adapter_config(context=IKeyNumber, provides=IFormContextPermissionChecker) +class KeyNumberPermissionChecker(ContextAdapter): + """Key number permission checker""" + + @property + def edit_permission(self): + content = get_parent(self.context, IKeyNumberContainerTarget) + return IFormContextPermissionChecker(content).edit_permission + + +@subscriber(IObjectAddedEvent, context_selector=IKeyNumber) +def handle_added_keynumber(event): + """Handle added key number""" + content = get_parent(event.object, IKeyNumberContainerTarget) + if content is not None: + get_current_registry().notify(ObjectModifiedEvent(content)) + + +@subscriber(IObjectModifiedEvent, context_selector=IKeyNumber) +def handle_modified_keynumber(event): + """Handle modified key number""" + content = get_parent(event.object, IKeyNumberContainerTarget) + if content is not None: + get_current_registry().notify(ObjectModifiedEvent(content)) + + +@subscriber(IObjectRemovedEvent, context_selector=IKeyNumber) +def handle_removed_keynumber(event): + """Handle removed key number""" + content = get_parent(event.object, IKeyNumberContainerTarget) + if content is not None: + get_current_registry().notify(ObjectModifiedEvent(content)) + + +@adapter_config(context=IKeyNumber, provides=IContentChecker) +class KeyNumberContentChecker(BaseContentChecker): + """Key number content checker""" + + @property + def label(self): + request = check_request() + return II18n(self.context).query_attribute('title', request=request) + + 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: + for attr in ('label', 'text'): + value = i18n.get_attribute(attr, lang, request) + if not value: + field_title = translate(IKeyNumber[attr].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 + + +# +# Key numbers container classes and adapters +# + +@implementer(IKeyNumberContainer) +class KeyNumberContainer(OrderedContainer): + """Key numbers container""" + + last_id = 1 + + def append(self, value, notify=True): + key = str(self.last_id) + if not notify: + # pre-locate key number item to avoid multiple notifications + locate(value, self, key) + self[key] = value + self.last_id += 1 + if not notify: + # make sure that key number item is correctly indexed + index_object(value) + + def get_visible_items(self): + return filter(lambda x: IKeyNumber(x).visible, self.values()) + + +@adapter_config(context=IKeyNumberContainerTarget, provides=IKeyNumberContainer) +def keynumber_container_factory(target): + """Key number container factory""" + return get_annotation_adapter(target, KEYNUMBER_CONTAINER_KEY, KeyNumberContainer, + name='++keynumbers++') + + +@adapter_config(context=IKeyNumberContainer, provides=IFormContextPermissionChecker) +class KeyNumberContainerPermissionChecker(ContextAdapter): + """Key number container permission checker""" + + @property + def edit_permission(self): + content = get_parent(self.context, IKeyNumberContainerTarget) + return IFormContextPermissionChecker(content).edit_permission + + +@adapter_config(name='keynumbers', context=IKeyNumberContainerTarget, provides=ITraversable) +class KeyNumberContainerNamespace(ContextAdapter): + """Key numbers container ++keynumbers++ namespace""" + + def traverse(self, name, furtherpaath=None): + return IKeyNumberContainer(self.context) + + +@adapter_config(name='keynumbers', context=IKeyNumberContainerTarget, provides=ISublocations) +class KeyNumberContainerSublocations(ContextAdapter): + """Key numbers container sub-locations adapter""" + + def sublocations(self): + return IKeyNumberContainer(self.context).values() + + +@adapter_config(name='keynumbers', context=IKeyNumberContainerTarget, provides=IContentChecker) +class KeyNumberContainerContentChecker(BaseContentChecker): + """Key numbers container content checker""" + + label = _("Key numbers") + sep = '\n' + weight = 200 + + def inner_check(self, request): + output = [] + registry = request.registry + for keynumber in IKeyNumberContainer(self.context).values(): + if not keynumber.visible: + continue + for name, checker in sorted(registry.getAdapters((keynumber, ), IContentChecker), + key=lambda x: x[1].weight): + output.append('- {0} ({1}):'.format(keynumber.number, + II18n(keynumber).query_attribute('label', request=request) or '--')) + output.append(checker.get_check_output(request)) + return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,75 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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 zope.annotation.interfaces import IAttributeAnnotatable + +# import packages +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 pyams_content import _ + + +KEYNUMBER_CONTAINER_KEY = 'pyams_content.keynumbers' + + +class IKeyNumber(IAttributeAnnotatable): + """Base key number interface""" + + containers('.IKeyNumberContainer') + + visible = Bool(title=_("Visible?"), + description=_("Is this key number visible in front-office?"), + required=True, + default=True) + + label = I18nTextLineField(title=_('key-number-label', default="Header"), + description=_("Small text to be displayed above number (according to selected " + "renderer)"), + required=False) + + number = TextLine(title=_("Number"), + description=_("Key number value"), + required=True) + + unit = I18nTextLineField(title=_('key-number-unit', default="Unit"), + description=_("Displayed unit"), + required=False) + + text = I18nTextLineField(title=_("Associated text"), + description=_("The way this text will be rendered depends on presentation template"), + required=False) + + +class IKeyNumberContainer(IOrderedContainer): + """Key numbers container interface""" + + contains(IKeyNumber) + + def append(self, value, notify=True): + """Append given key number to container""" + + def get_visible_items(self): + """Get list of visible key numbers""" + + +class IKeyNumberContainerTarget(Interface): + """Key numbers container target interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/portlet/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/portlet/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +# import standard library + +# import interfaces +from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY +from pyams_content.component.keynumber.interfaces import IKeyNumberContainerTarget, IKeyNumberContainer +from pyams_content.component.keynumber.portlet.interfaces import IKeyNumberPortletSettings, IKeyNumberPortletMenu +from pyams_content.features.menu.interfaces import IMenuLinksContainerTarget, IMenuLinksContainer +from pyams_utils.interfaces import VIEW_PERMISSION + +# import packages +from pyams_content.features.menu import Menu +from pyams_portal.portlet import PortletSettings, portlet_config, Portlet +from pyams_utils.adapter import get_annotation_adapter, adapter_config +from pyams_utils.factory import factory_config +from zope.interface import implementer +from zope.schema.fieldproperty import FieldProperty + +from pyams_content import _ + + +KEYNUMBER_PORTLET_NAME = "pyams_portal.portlet.keynumber" + +KEYNUMBER_PORTLET_LINKS_NAME = 'links' +KEYNUMBER_PORTLET_LINKS_KEY = '{0}::{1}'.format(ASSOCIATION_CONTAINER_KEY, KEYNUMBER_PORTLET_LINKS_NAME) + + +@implementer(IKeyNumberPortletSettings, IKeyNumberContainerTarget, IMenuLinksContainerTarget) +@factory_config(provided=IKeyNumberPortletSettings) +class KeyNumberPortletSettings(PortletSettings): + """Key Number portlet settings""" + + title = FieldProperty(IKeyNumberPortletSettings['title']) + teaser = FieldProperty(IKeyNumberPortletSettings['teaser']) + + @property + def keynumbers(self): + return IKeyNumberContainer(self) + + @property + def links(self): + return get_annotation_adapter(self, KEYNUMBER_PORTLET_LINKS_KEY, Menu, + markers=IKeyNumberPortletMenu, + name='++ass++' + KEYNUMBER_PORTLET_LINKS_NAME) + + +@adapter_config(name=KEYNUMBER_PORTLET_LINKS_NAME, context=IKeyNumberPortletSettings, provides=IMenuLinksContainer) +def keynumber_links_adapter(context): + """Key number settings links factory""" + return context.links + + +@portlet_config(permission=VIEW_PERMISSION) +class KeyNumberPortlet(Portlet): + """Key number portlet""" + + name = KEYNUMBER_PORTLET_NAME + label = _("Key Numbers") + + toolbar_image = None + toolbar_css_class = 'fa fa-fw fa-2x fa-dashboard' + + settings_factory = IKeyNumberPortletSettings diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/portlet/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/portlet/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,43 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_portal.interfaces import IPortletSettings + +# import packages +from pyams_i18n.schema import I18nTextLineField, I18nTextField +from zope.interface import Attribute, Interface + +from pyams_content import _ + + +class IKeyNumberPortletSettings(IPortletSettings): + """Key numbers portlet settings interface""" + + title = I18nTextLineField(title=_("Title"), + description=_("Portlet title"), + required=False) + + teaser = I18nTextField(title=_("Teaser"), + description=_("Short text displayed above key numbers"), + required=False) + + links = Attribute("Navigation links") + + +class IKeyNumberPortletMenu(Interface): + """Key numbers portlet menu marker interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/portlet/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/portlet/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,126 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.association.interfaces import IAssociationInfo +from pyams_content.component.keynumber.portlet.interfaces import IKeyNumberPortletSettings, IKeyNumberPortletMenu +from pyams_content.features.menu.zmi import IMenuLinksView +from pyams_content.component.links.interfaces import IInternalLink +from pyams_portal.interfaces import IPortletPreviewer +from pyams_form.interfaces.form import IInnerSubForm, IInnerTabForm +from pyams_pagelet.interfaces import IPagelet +from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_workflow.interfaces import IWorkflowPublicationInfo + +# import packages +from pyams_content.component.keynumber.portlet import KEYNUMBER_PORTLET_LINKS_NAME +from pyams_content.component.keynumber.zmi import KeyNumbersView +from pyams_content.features.menu.zmi import MenuLinksView, LinksTable +from pyams_form.form import AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_portal.portlet import PortletPreviewer +from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from zope.interface import Interface + +from pyams_content import _ + + +@pagelet_config(name='properties.html', context=IKeyNumberPortletSettings, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +class KeyNumberPortletEditor(PortletSettingsEditor): + """Key number portlet settings editor""" + + settings = IKeyNumberPortletSettings + + +@adapter_config(name='properties', context=(Interface, IPyAMSLayer, KeyNumberPortletEditor), provides=IInnerTabForm) +class KeyNumberPortletSettingsPropertiesEditor(PortletSettingsPropertiesEditor): + """Key number portlet settings properties editor""" + + def updateWidgets(self, prefix=None): + super().updateWidgets(prefix) + if 'teaser' in self.widgets: + self.widgets['teaser'].widget_css_class = 'textarea' + + +@adapter_config(name='properties.json', context=(IKeyNumberPortletSettings, IPyAMSLayer), provides=IPagelet) +class KeyNumberPortletAJAXEditor(AJAXEditForm, KeyNumberPortletEditor): + """Key number portlet settings editor, JSON renderer""" + + +# +# Key numbers portlet numbers view +# + +@adapter_config(name='keynumber-portlet-numbers', + context=(IKeyNumberPortletSettings, IPyAMSLayer, PortletSettingsPropertiesEditor), + provides=IInnerSubForm) +class KeyNumberPortletNumbersView(KeyNumbersView): + """Key number portlet numbers view""" + + title = _("Key numbers") + weight = 10 + + +# +# Key numbers portlet links view +# + +class KeyNumberPortletLinksTable(LinksTable): + """Key Numbers links associations table""" + + associations_name = KEYNUMBER_PORTLET_LINKS_NAME + + +@adapter_config(name='keynumber-portlet-links', + context=(IKeyNumberPortletSettings, IPyAMSLayer, PortletSettingsPropertiesEditor), + provides=IInnerSubForm) +@adapter_config(name='++ass++{0}'.format(KEYNUMBER_PORTLET_LINKS_NAME), + context=(IKeyNumberPortletMenu, IPyAMSLayer), + provides=IMenuLinksView) +class KeyNumberPortletLinksView(MenuLinksView): + """Key numbers portlet links view""" + + title = _("Associated links") + weight = 20 + + table_class = KeyNumberPortletLinksTable + + +# +# Key numbers portlet previewer +# + +@adapter_config(context=(Interface, IPyAMSLayer, Interface, IKeyNumberPortletSettings), provides=IPortletPreviewer) +@template_config(template='templates/keynumber-preview.pt', layer=IPyAMSLayer) +class KeyNumberPortletPreviewer(PortletPreviewer): + """Key number portlet previewer""" + + @classmethod + def get_link_info(cls, link): + return IAssociationInfo(link) + + @classmethod + def get_link_status(cls, link): + if not IInternalLink.providedBy(link): + return True + target = link.get_target() + return (target is not None) and IWorkflowPublicationInfo(target).is_published() diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,35 @@ +
+ +
+
Teaser
+
    +
  • + + : + Number + Unit + text +
  • +
+
+ Associated links : +
    +
  • + + + User title + Inner title + +
  • +
+
+
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/keynumber/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/keynumber/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,271 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.component.keynumber.interfaces import IKeyNumberContainer, IKeyNumberContainerTarget, IKeyNumber +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_form.interfaces.form import IInnerSubForm +from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager +from pyams_skin.layer import IPyAMSLayer +from z3c.table.interfaces import IValues, IColumn + +# import packages +from pyams_content.component.keynumber import KeyNumber +from pyams_form.form import ajax_config, AJAXAddForm +from pyams_form.security import ProtectedFormObjectMixin +from pyams_i18n.column import I18nAttrColumn +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.container import switch_element_visibility +from pyams_skin.event import get_json_table_row_refresh_event, get_json_switched_table_refresh_event +from pyams_skin.table import BaseTable, SorterColumn, VisibilitySwitcherColumn, I18nColumn, TrashColumn +from pyams_skin.viewlet.toolbar import ToolbarAction +from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter +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 pyams_zmi.zmi.table import InnerTableView +from pyramid.decorator import reify +from pyramid.view import view_config +from z3c.form import field +from z3c.table.column import GetAttrColumn +from zope.interface import implementer, Interface + +from pyams_content import _ + + +# +# Views marker interfaces +# + +class IKeyNumbersView(Interface): + """Key numbers view marker interface""" + + +class IKeyNumbersParentForm(Interface): + """Key numbers parent form marker interface""" + + +# +# Key number items table view +# + +class KeyNumbersTable(ProtectedFormObjectMixin, BaseTable): + """Key numbers view inner table""" + + prefix = 'keynumbers' + + hide_header = True + hide_body_toolbar = True + sortOn = None + + @classmethod + def get_context(cls, context): + return IKeyNumberContainer(context) + + @reify + def cssClasses(self): + classes = ['table', 'table-bordered', 'table-striped', 'table-hover', 'table-tight'] + permission = self.permission + if (not permission) or self.request.has_permission(permission, self.context): + classes.append('table-dnd') + return {'table': ' '.join(classes)} + + @reify + def data_attributes(self): + container = IKeyNumberContainer(self.context) + attributes = super(KeyNumbersTable, self).data_attributes + 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' + }) + return attributes + + @reify + def values(self): + return list(super(KeyNumbersTable, self).values) + + +@adapter_config(context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IValues) +class KeyNumbersTableValuesAdapter(ContextRequestViewAdapter): + """Key numbers table values adapter""" + + @property + def values(self): + return IKeyNumberContainer(self.context).values() + + +@adapter_config(name='sorter', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IColumn) +class KeyNumbersTableSorterColumn(ProtectedFormObjectMixin, SorterColumn): + """Key numbers table sorter column""" + + +@view_config(name='set-keynumbers-order.json', context=IKeyNumberContainer, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) +def set_keynumbers_order(request): + """Update key numbers order""" + order = list(map(str, json.loads(request.params.get('names')))) + request.context.updateOrder(order) + return {'status': 'success'} + + +@adapter_config(name='show-hide', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), + provides=IColumn) +class KeyNumbersTableShowHideColumn(ProtectedFormObjectMixin, VisibilitySwitcherColumn): + """Key numbers container visibility switcher column""" + + +@view_config(name='switch-keynumber-visibility.json', context=IKeyNumberContainer, request_type=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) +def switch_keynumber_visibility(request): + """Switch key number visibility""" + return switch_element_visibility(request, IKeyNumberContainer) + + +@adapter_config(name='label', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IColumn) +class KeyNumbersTableLabelColumn(I18nColumn, I18nAttrColumn): + """Key numbers table label column""" + + _header = _('key-number-label', default="Header") + attrName = 'label' + weight = 10 + + def getValue(self, obj): + return super(KeyNumbersTableLabelColumn, self).getValue(obj) or '--' + + +@adapter_config(name='name', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IColumn) +class KeyNumbersTableNameColumn(I18nColumn, GetAttrColumn): + """Key numbers table number column""" + + _header = _("Number") + attrName = 'number' + weight = 20 + + +@adapter_config(name='unit', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IColumn) +class KeyNumbersTableUnitColumn(I18nColumn, I18nAttrColumn): + """Key numbers table unit column""" + + _header = _('key-number-unit', default="Unit") + attrName = 'unit' + weight = 30 + + def getValue(self, obj): + return super(KeyNumbersTableUnitColumn, self).getValue(obj) or '--' + + +@adapter_config(name='text', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IColumn) +class KeyNumbersTableTextColumn(I18nColumn, I18nAttrColumn): + """Key numbers table text column""" + + _header = _("Associated text") + attrName = 'text' + weight = 40 + + def getValue(self, obj): + return super(KeyNumbersTableTextColumn, self).getValue(obj) or '--' + + +@adapter_config(name='trash', context=(IKeyNumberContainer, IPyAMSLayer, KeyNumbersTable), provides=IColumn) +class KeyNumbersTableTrashColumn(ProtectedFormObjectMixin, TrashColumn): + """Key numbers table trash column""" + + +@adapter_config(name='keynumbers', context=(IKeyNumberContainerTarget, IPyAMSLayer, IKeyNumbersParentForm), + provides=IInnerSubForm) +@implementer(IKeyNumbersView) +class KeyNumbersView(InnerTableView): + """Key numbers view""" + + title = _("Key numbers") + + table_class = KeyNumbersTable + weight = 110 + + @property + def actions_context(self): # define context for internal actions + return IKeyNumberContainer(self.context) + + +# +# Key numbers forms +# + +@viewlet_config(name='add-keynumber.action', context=IKeyNumberContainerTarget, layer=IPyAMSLayer, view=IKeyNumbersView, + manager=IWidgetTitleViewletManager, weight=1) +class KeyNumberAddAction(ProtectedFormObjectMixin, ToolbarAction): + """Key number add action""" + + label = _("Add keynumber") + label_css_class = 'fa fa-fw fa-plus' + url = 'add-keynumber.html' + modal_target = True + + +@pagelet_config(name='add-keynumber.html', context=IKeyNumberContainer, layer=IPyAMSLayer) +@ajax_config(name='add-keynumber.json', context=IKeyNumberContainer, layer=IPyAMSLayer, + base=AJAXAddForm) +class KeyNumberAddForm(AdminDialogAddForm): + """Key number add form""" + + legend = _("Add new keynumber") + icon_css_class = 'fa fa-fw fa-dashboard' + + fields = field.Fields(IKeyNumber).omit('__parent__', '__name__', 'visible') + edit_permission = None # use context permission checker + + def create(self, data): + return KeyNumber() + + def add(self, object): + IKeyNumberContainer(self.context).append(object) + + def get_ajax_output(self, changes): + return { + 'status': 'success', + 'message': self.request.localizer.translate(_("Key number was correctly added")), + 'events': [ + get_json_switched_table_refresh_event(self.context, self.request, KeyNumbersTable) + ] + } + + +@pagelet_config(name='properties.html', context=IKeyNumber, layer=IPyAMSLayer) +@ajax_config(name='properties.json', context=IKeyNumber, layer=IPyAMSLayer) +class KeyNumberPropertiesEditForm(AdminDialogEditForm): + """Key number properties edit form""" + + prefix = 'keynumber_properties.' + + legend = _("Edit keynumber properties") + icon_css_class = 'fa fa-fw fa-dashboard' + + fields = field.Fields(IKeyNumber).omit('__parent__', '__name__', 'visible') + edit_permission = None # use context permission checker + + def get_ajax_output(self, changes): + output = super(self.__class__, self).get_ajax_output(changes) + updated = changes.get(IKeyNumber, ()) + if updated: + target = get_parent(self.context, IKeyNumberContainerTarget) + output.setdefault('events', []).append( + get_json_table_row_refresh_event(target, self.request, KeyNumbersTable, self.context)) + return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/links/__init__.py --- a/src/pyams_content/component/links/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/links/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -9,6 +9,7 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # +from pyams_skin.layer import IPyAMSUserLayer __docformat__ = 'restructuredtext' @@ -16,10 +17,11 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationInfo, IAssociationTarget, 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 @@ -31,10 +33,12 @@ from pyams_content.workflow import VISIBLE_STATES from pyams_sequence.utility import get_reference_target from pyams_utils.adapter import adapter_config, ContextAdapter +from pyams_utils.registry import query_utility from pyams_utils.request import check_request from pyams_utils.traversing import get_parent -from pyams_utils.url import absolute_url +from pyams_utils.url import absolute_url, relative_url 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 from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm @@ -52,7 +56,7 @@ def __init__(self, context=None): terms = [] - target = get_parent(context, IAssociationTarget) + target = get_parent(context, IAssociationContainerTarget) if target is not None: terms = [SimpleTerm(link.__name__, title=IAssociationInfo(link).inner_title) for link in IAssociationContainer(target).values() if IBaseLink.providedBy(link)] @@ -69,6 +73,23 @@ title = FieldProperty(IBaseLink['title']) description = FieldProperty(IBaseLink['description']) + _pictogram_name = FieldProperty(IBaseLink['pictogram_name']) + + @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) + if table is not None: + return table.get(self._pictogram_name) class BaseLinkInfoAdapter(ContextAdapter): @@ -112,11 +133,11 @@ return 'oid://{0}'.format(self.reference) def get_url(self, request=None, view_name=None): - target = self.get_target(state=VISIBLE_STATES) + target = self.get_target() if target is not None: if request is None: request = check_request() - return absolute_url(target, request, view_name) + return relative_url(target, request, view_name=view_name) else: return '' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/links/interfaces/__init__.py --- a/src/pyams_content/component/links/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/links/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,12 +16,14 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationTarget, IAssociationItem +from pyams_content.component.association.interfaces import IAssociationContainerTarget, IAssociationItem +from pyams_content.reference.pictograms.interfaces import SELECTED_PICTOGRAM_VOCABULARY from pyams_sequence.interfaces import IInternalReference # import packages from pyams_i18n.schema import I18nTextLineField, I18nTextField from pyams_utils.schema import MailAddressField +from zope.interface import Attribute from zope.schema import Choice, TextLine, URI from pyams_content import _ @@ -38,6 +40,13 @@ description=_("Link description displayed by front-office template"), required=False) + pictogram_name = Choice(title=_("Pictogram"), + description=_("Name of the pictogram associated with this link"), + required=False, + vocabulary=SELECTED_PICTOGRAM_VOCABULARY) + + pictogram = Attribute("Selected pictogram object") + def get_editor_url(self): """Get URL for use in HTML editor""" @@ -74,5 +83,5 @@ required=True) -class ILinkContainerTarget(IAssociationTarget): +class ILinkContainerTarget(IAssociationContainerTarget): """Links container marker interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/links/zmi/__init__.py --- a/src/pyams_content/component/links/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/links/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -18,19 +18,21 @@ # import interfaces from pyams_content.component.association.interfaces import IAssociationContainer from pyams_content.component.association.zmi.interfaces import IAssociationsView -from pyams_content.component.links.interfaces import ILinkContainerTarget, IInternalLink, IBaseLink, \ +from pyams_content.component.links.interfaces import ILinkContainerTarget, IBaseLink, IInternalLink, \ IExternalLink, IMailtoLink from pyams_content.component.paragraph.zmi.interfaces import IParagraphContainerTable, IParagraphTitleToolbar from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION from pyams_skin.interfaces.viewlet import IToolbarAddingMenu from pyams_skin.layer import IPyAMSLayer from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_zmi.interfaces import IPropertiesEditForm # import packages from pyams_content.component.association.zmi import AssociationItemAJAXAddForm, AssociationItemAJAXEditForm from pyams_content.component.links import InternalLink, ExternalLink, MailtoLink from pyams_content.component.paragraph.zmi import get_json_paragraph_markers_refresh_event from pyams_content.component.paragraph.zmi.container import ParagraphContainerCounterBase +from pyams_content.reference.pictograms.zmi.widget import PictogramSelectFieldWidget from pyams_form.form import ajax_config from pyams_form.security import ProtectedFormObjectMixin from pyams_pagelet.pagelet import pagelet_config @@ -38,6 +40,7 @@ from pyams_viewlet.viewlet import viewlet_config from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm from z3c.form import field +from zope.interface import implementer from pyams_content import _ @@ -86,7 +89,9 @@ legend = _("Add new internal link") icon_css_class = 'fa fa-fw fa-external-link-square fa-rotate-90' - fields = field.Fields(IInternalLink).select('reference', 'title', 'description') + fields = field.Fields(IInternalLink).select('reference', 'title', 'description', 'pictogram_name') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = MANAGE_CONTENT_PERMISSION def updateWidgets(self, prefix=None): @@ -111,6 +116,7 @@ @pagelet_config(name='properties.html', context=IInternalLink, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @ajax_config(name='properties.json', context=IInternalLink, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, base=AssociationItemAJAXEditForm) +@implementer(IPropertiesEditForm) class InternalLinkPropertiesEditForm(AdminDialogEditForm): """Internal link properties edit form""" @@ -118,8 +124,11 @@ legend = _("Edit internal link properties") icon_css_class = 'fa fa-fw fa-external-link-square fa-rotate-90' + dialog_class = 'modal-large' - fields = field.Fields(IInternalLink).select('reference', 'title', 'description') + fields = field.Fields(IInternalLink).select('reference', 'title', 'description', 'pictogram_name') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = None # defined by IFormContextPermissionChecker adapter def updateWidgets(self, prefix=None): @@ -179,7 +188,9 @@ legend = _("Add new external link") icon_css_class = 'fa fa-fw fa-external-link' - fields = field.Fields(IExternalLink).select('url', 'title', 'description', 'language') + fields = field.Fields(IExternalLink).select('url', 'title', 'description', 'pictogram_name', 'language') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = MANAGE_CONTENT_PERMISSION def updateWidgets(self, prefix=None): @@ -204,6 +215,7 @@ @pagelet_config(name='properties.html', context=IExternalLink, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @ajax_config(name='properties.json', context=IExternalLink, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, base=AssociationItemAJAXEditForm) +@implementer(IPropertiesEditForm) class ExternalLinkPropertiesEditForm(AdminDialogEditForm): """External link properties edit form""" @@ -211,8 +223,11 @@ legend = _("Edit external link properties") icon_css_class = 'fa fa-fw fa-external-link' + dialog_class = 'modal-large' - fields = field.Fields(IExternalLink).select('url', 'title', 'description', 'language') + fields = field.Fields(IExternalLink).select('url', 'title', 'description', 'pictogram_name', 'language') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = None # defined by IFormContextPermissionChecker adapter def updateWidgets(self, prefix=None): @@ -272,7 +287,9 @@ legend = _("Add new mailto link") icon_css_class = 'fa fa-fw fa-envelope-o' - fields = field.Fields(IMailtoLink).select('address', 'address_name', 'title', 'description') + fields = field.Fields(IMailtoLink).select('address', 'address_name', 'title', 'description', 'pictogram_name') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = MANAGE_CONTENT_PERMISSION def updateWidgets(self, prefix=None): @@ -297,6 +314,7 @@ @pagelet_config(name='properties.html', context=IMailtoLink, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @ajax_config(name='properties.json', context=IMailtoLink, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, base=AssociationItemAJAXEditForm) +@implementer(IPropertiesEditForm) class MailtoLinkPropertiesEditForm(AdminDialogEditForm): """Mailto link properties edit form""" @@ -305,7 +323,9 @@ legend = _("Edit mailto link properties") icon_css_class = 'fa fa-fw fa-envelope-o' - fields = field.Fields(IMailtoLink).select('address', 'address_name', 'title', 'description') + fields = field.Fields(IMailtoLink).select('address', 'address_name', 'title', 'description', 'pictogram_name') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = None # defined by IFormContextPermissionChecker adapter def updateWidgets(self, prefix=None): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/links/zmi/container.py --- a/src/pyams_content/component/links/zmi/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/links/zmi/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationContainer, IAssociationTarget, IAssociationInfo +from pyams_content.component.association.interfaces import IAssociationContainer, IAssociationContainerTarget, IAssociationInfo from pyams_content.component.extfile.interfaces import IBaseExtFile from pyams_content.component.links.interfaces import IBaseLink from pyams_i18n.interfaces import II18n @@ -40,7 +40,7 @@ result = [] key_field_name = request.params.get('keyFieldName', 'title') value_field_name = request.params.get('valueFieldName', 'value') - target = get_parent(request.context, IAssociationTarget) + target = get_parent(request.context, IAssociationContainerTarget) if target is not None: container = IAssociationContainer(target) result.extend([{key_field_name: item.__name__, @@ -54,7 +54,7 @@ def get_links_list(request): """Get links list in JSON format for TinyMCE editor""" result = [] - target = get_parent(request.context, IAssociationTarget) + target = get_parent(request.context, IAssociationContainerTarget) if target is not None: container = IAssociationContainer(target) for item in container.values(): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/links/zmi/reverse.py --- a/src/pyams_content/component/links/zmi/reverse.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/links/zmi/reverse.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,6 +19,8 @@ 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 @@ -77,11 +79,23 @@ @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(lambda x: IWorkflowVersions(get_parent(x, IWfSharedContent)).get_last_versions(count=1)[0], + return unique(map(get_item, CatalogResultSet(CatalogQuery(catalog).query(params, sort_index='modified_date')))) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/audio.py --- a/src/pyams_content/component/paragraph/audio.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/audio.py Wed Jun 27 16:42:01 2018 +0200 @@ -44,10 +44,9 @@ icon_class = 'fa-volume-up' icon_hint = AUDIO_PARAGRAPH_NAME - body = FieldProperty(IAudioParagraph['body']) + data = FileProperty(IAudioParagraph['data']) description = FieldProperty(IAudioParagraph['description']) author = FieldProperty(IAudioParagraph['author']) - data = FileProperty(IAudioParagraph['data']) renderer = FieldProperty(IAudioParagraph['renderer']) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/interfaces/audio.py --- a/src/pyams_content/component/paragraph/interfaces/audio.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/interfaces/audio.py Wed Jun 27 16:42:01 2018 +0200 @@ -20,7 +20,7 @@ # import packages from pyams_file.schema import AudioField -from pyams_i18n.schema import I18nHTMLField, I18nTextField +from pyams_i18n.schema import I18nTextField, I18nTextLineField from zope.schema import TextLine, Choice from pyams_content import _ @@ -38,8 +38,12 @@ class IAudioParagraph(IBaseParagraph): """Audio paragraph""" - body = I18nHTMLField(title=_("Body"), - required=False) + data = AudioField(title=_("Audio data"), + description=_("Audio file content"), + required=True) + + title = I18nTextLineField(title=_("Legend"), + required=False) description = I18nTextField(title=_("Description"), description=_("File description displayed by front-office template"), @@ -49,10 +53,6 @@ description=_("Name of document's author"), required=False) - data = AudioField(title=_("Audio data"), - description=_("Audio file content"), - required=True) - renderer = Choice(title=_("Audio template"), description=_("Presentation template used for this audio file"), vocabulary=AUDIO_PARAGRAPH_RENDERERS, diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/interfaces/keynumber.py --- a/src/pyams_content/component/paragraph/interfaces/keynumber.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/interfaces/keynumber.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,62 +16,15 @@ # import standard library # import interfaces +from pyams_content.component.keynumber.interfaces import IKeyNumberContainerTarget from pyams_content.component.paragraph import IBaseParagraph -from pyams_content.interfaces.container import IOrderedContainer -from zope.annotation.interfaces import IAttributeAnnotatable # import packages -from pyams_i18n.schema import I18nTextLineField -from zope.container.constraints import containers, contains -from zope.interface import Interface from zope.schema import Bool, Choice, TextLine from pyams_content import _ -KEYNUMBER_CONTAINER_KEY = 'pyams_content.keynumbers' - - -class IKeyNumber(IAttributeAnnotatable): - """Base key number interface""" - - containers('.IKeyNumberContainer') - - visible = Bool(title=_("Visible?"), - description=_("Is this key number visible in front-office?"), - required=True, - default=True) - - number = TextLine(title=_("Number"), - description=_("Key number value"), - required=True) - - label = I18nTextLineField(title=_('key-number-label', default="Header"), - description=_("Small text to be displayed above number (according to selected " - "renderer)"), - required=False) - - text = I18nTextLineField(title=_("Associated text"), - description=_("The way this text will be rendered depends on presentation template"), - required=False) - - -class IKeyNumberContainer(IOrderedContainer): - """Key numbers container interface""" - - contains(IKeyNumber) - - def append(self, value, notify=True): - """Append given key number to container""" - - def get_visible_items(self): - """Get list of visible key numbers""" - - -class IKeyNumberContainerTarget(Interface): - """Key numbers container target interface""" - - KEYNUMBER_PARAGRAPH_TYPE = 'KeyNumbers' KEYNUMBER_PARAGRAPH_NAME = _("Key numbers") KEYNUMBER_PARAGRAPH_RENDERERS = 'PyAMS.keynumbers.renderers' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/interfaces/video.py --- a/src/pyams_content/component/paragraph/interfaces/video.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/interfaces/video.py Wed Jun 27 16:42:01 2018 +0200 @@ -20,7 +20,7 @@ # import packages from pyams_file.schema import VideoField -from pyams_i18n.schema import I18nHTMLField, I18nTextField +from pyams_i18n.schema import I18nTextField, I18nTextLineField from zope.schema import TextLine, Choice from pyams_content import _ @@ -38,8 +38,12 @@ class IVideoParagraph(IBaseParagraph): """Video paragraph""" - body = I18nHTMLField(title=_("Body"), - required=False) + data = VideoField(title=_("Video data"), + description=_("Video file content"), + required=True) + + title = I18nTextLineField(title=_("Legend"), + required=False) description = I18nTextField(title=_("Description"), description=_("File description displayed by front-office template"), @@ -49,10 +53,6 @@ description=_("Name of document's author"), required=False) - data = VideoField(title=_("Video data"), - description=_("Video file content"), - required=True) - renderer = Choice(title=_("Video template"), description=_("Presentation template used for this video"), vocabulary=VIDEO_PARAGRAPH_RENDERERS, diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/keynumber.py --- a/src/pyams_content/component/paragraph/keynumber.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/keynumber.py Wed Jun 27 16:42:01 2018 +0200 @@ -14,188 +14,27 @@ # import standard library -from persistent import Persistent # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphFactory -from pyams_content.component.paragraph.interfaces.keynumber import IKeyNumber, IKeyNumberContainer, \ - IKeyNumberContainerTarget, KEYNUMBER_CONTAINER_KEY, IKeyNumberParagraph, KEYNUMBER_PARAGRAPH_TYPE, \ +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_form.interfaces.form import IFormContextPermissionChecker from pyams_i18n.interfaces import II18n, II18nManager, INegotiator -from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent -from zope.location.interfaces import ISublocations -from zope.traversing.interfaces import ITraversable # import packages -from pyams_catalog.utils import index_object from pyams_content.component.paragraph import BaseParagraph, BaseParagraphFactory, BaseParagraphContentChecker -from pyams_content.features.checker import BaseContentChecker from pyams_content.features.renderer import RenderersVocabulary -from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter +from pyams_utils.adapter import adapter_config from pyams_utils.factory import factory_config -from pyams_utils.registry import get_current_registry, get_utility, utility_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 pyramid.events import subscriber -from zope.container.contained import Contained -from zope.container.ordered import OrderedContainer from zope.interface import implementer -from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent -from zope.location import locate from zope.schema.fieldproperty import FieldProperty -# -# Key number class and adapters -# - -@implementer(IKeyNumber) -class KeyNumber(Persistent, Contained): - """Key number persistent class""" - - visible = FieldProperty(IKeyNumber['visible']) - number = FieldProperty(IKeyNumber['number']) - label = FieldProperty(IKeyNumber['label']) - text = FieldProperty(IKeyNumber['text']) - - -@adapter_config(context=IKeyNumber, provides=IFormContextPermissionChecker) -class KeyNumberPermissionChecker(ContextAdapter): - """Key number permission checker""" - - @property - def edit_permission(self): - content = get_parent(self.context, IKeyNumberContainerTarget) - return IFormContextPermissionChecker(content).edit_permission - - -@subscriber(IObjectAddedEvent, context_selector=IKeyNumber) -def handle_added_keynumber(event): - """Handle added key number""" - content = get_parent(event.object, IKeyNumberContainerTarget) - if content is not None: - get_current_registry().notify(ObjectModifiedEvent(content)) - - -@subscriber(IObjectModifiedEvent, context_selector=IKeyNumber) -def handle_modified_keynumber(event): - """Handle modified key number""" - content = get_parent(event.object, IKeyNumberContainerTarget) - if content is not None: - get_current_registry().notify(ObjectModifiedEvent(content)) - - -@subscriber(IObjectRemovedEvent, context_selector=IKeyNumber) -def handle_removed_keynumber(event): - """Handle removed key number""" - content = get_parent(event.object, IKeyNumberContainerTarget) - if content is not None: - get_current_registry().notify(ObjectModifiedEvent(content)) - - -@adapter_config(context=IKeyNumber, provides=IContentChecker) -class KeyNumberContentChecker(BaseContentChecker): - """Key number content checker""" - - @property - def label(self): - request = check_request() - return II18n(self.context).query_attribute('title', request=request) - - 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: - for attr in ('label', 'text'): - value = i18n.get_attribute(attr, lang, request) - if not value: - field_title = translate(IKeyNumber[attr].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 - - -# -# Key numbers container classes and adapters -# - -@implementer(IKeyNumberContainer) -class KeyNumberContainer(OrderedContainer): - """Key numbers container""" - - last_id = 1 - - def append(self, value, notify=True): - key = str(self.last_id) - if not notify: - # pre-locate key number item to avoid multiple notifications - locate(value, self, key) - self[key] = value - self.last_id += 1 - if not notify: - # make sure that key number item is correctly indexed - index_object(value) - - def get_visible_items(self): - return filter(lambda x: IKeyNumber(x).visible, self.values()) - - -@adapter_config(context=IKeyNumberContainerTarget, provides=IKeyNumberContainer) -def keynumber_container_factory(target): - """Key number container factory""" - return get_annotation_adapter(target, KEYNUMBER_CONTAINER_KEY, KeyNumberContainer, name='++keynumbers++') - - -@adapter_config(name='keynumbers', context=IKeyNumberContainerTarget, provides=ITraversable) -class KeyNumberContainerNamespace(ContextAdapter): - """Key numbers container ++keynumbers++ namespace""" - - def traverse(self, name, furtherpaath=None): - return IKeyNumberContainer(self.context) - - -@adapter_config(name='keynumbers', context=IKeyNumberContainerTarget, provides=ISublocations) -class KeyNumberContainerSublocations(ContextAdapter): - """Key numbers container sub-locations adapter""" - - def sublocations(self): - return IKeyNumberContainer(self.context).values() - - -@adapter_config(name='keynumbers', context=IKeyNumberContainerTarget, provides=IContentChecker) -class KeyNumberContainerContentChecker(BaseContentChecker): - """Key numbers container content checker""" - - label = KEYNUMBER_PARAGRAPH_NAME - sep = '\n' - weight = 200 - - def inner_check(self, request): - output = [] - registry = request.registry - for keynumber in IKeyNumberContainer(self.context).values(): - if not keynumber.visible: - continue - for name, checker in sorted(registry.getAdapters((keynumber, ), IContentChecker), - key=lambda x: x[1].weight): - output.append('- {0} ({1}):'.format(keynumber.number, - II18n(keynumber).query_attribute('label', request=request) or '--')) - output.append(checker.get_check_output(request)) - return output - - @implementer(IKeyNumberParagraph) @factory_config(provided=IKeyNumberParagraph) class KeyNumberParagraph(BaseParagraph): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/pictogram.py --- a/src/pyams_content/component/paragraph/pictogram.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/pictogram.py Wed Jun 27 16:42:01 2018 +0200 @@ -78,7 +78,8 @@ @volatile_property def pictogram(self): table = query_utility(IPictogramTable) - return table.get(self.pictogram_name) + if table is not None: + return table.get(self._pictogram_name) @adapter_config(context=IPictogramItem, provides=IFormContextPermissionChecker) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/video.py --- a/src/pyams_content/component/paragraph/video.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/video.py Wed Jun 27 16:42:01 2018 +0200 @@ -43,10 +43,9 @@ icon_class = 'fa-film' icon_hint = VIDEO_PARAGRAPH_NAME - body = FieldProperty(IVideoParagraph['body']) + data = FileProperty(IVideoParagraph['data']) description = FieldProperty(IVideoParagraph['description']) author = FieldProperty(IVideoParagraph['author']) - data = FileProperty(IVideoParagraph['data']) renderer = FieldProperty(IVideoParagraph['renderer']) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/audio.py --- a/src/pyams_content/component/paragraph/zmi/audio.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/audio.py Wed Jun 27 16:42:01 2018 +0200 @@ -31,10 +31,9 @@ # import packages from pyams_content.component.paragraph.audio import AudioParagraph from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ - BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, IParagraphEditFormButtons + BaseParagraphAddMenu, 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_form.group import NamedWidgetsGroup from pyams_pagelet.pagelet import pagelet_config from pyams_skin.event import get_json_form_refresh_event, get_json_widget_refresh_event from pyams_utils.adapter import adapter_config @@ -75,20 +74,6 @@ super(AudioParagraphAddForm, self).updateWidgets(prefix) if 'description' in self.widgets: self.widgets['description'].widget_css_class = 'textarea' - if 'body' in self.widgets: - self.widgets['body'].label = '' - - def updateGroups(self): - self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',), - bordered=False, - legend=_("HTML content"), - css_class='inner switcher padding-right-10 no-y-padding pull-left', - switch=True, - display_mode='auto')) - self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets, - ('description', 'author', 'data', 'renderer'), - bordered=False)) - super(AudioParagraphAddForm, self).updateGroups() def create(self, data): return AudioParagraph() @@ -118,21 +103,6 @@ super(AudioParagraphPropertiesEditForm, self).updateWidgets(prefix) if 'description' in self.widgets: self.widgets['description'].widget_css_class = 'textarea' - if 'body' in self.widgets: - self.widgets['body'].label = '' - - def updateGroups(self): - self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',), - bordered=False, - fieldset_class='margin-top-10 padding-y-5', - legend=_("HTML content"), - css_class='inner switcher padding-right-10 no-y-padding pull-left', - switch=True, - display_mode='auto')) - self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets, - ('description', 'author', 'data', 'renderer'), - bordered=False)) - super(AudioParagraphPropertiesEditForm, self).updateGroups() @adapter_config(context=(IAudioParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) @@ -159,8 +129,12 @@ ITransactionManager(self.context).get().commit() output.setdefault('events', []).append( get_json_form_refresh_event(self.context, self.request, AudioParagraphPropertiesInnerEditForm)) - elif 'renderer' in updated: - output.setdefault('events', []).append( - get_json_widget_refresh_event(self.context, self.request, - AudioParagraphPropertiesInnerEditForm, 'renderer')) + else: + if 'title' in updated: + output.setdefault('events', []).append( + get_json_paragraph_refresh_event(self.context, self.request)) + if 'renderer' in updated: + output.setdefault('events', []).append( + get_json_widget_refresh_event(self.context, self.request, + AudioParagraphPropertiesInnerEditForm, 'renderer')) return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/container.py --- a/src/pyams_content/component/paragraph/zmi/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -101,7 +101,6 @@ def data_attributes(self): attributes = super(ParagraphContainerBaseTable, self).data_attributes attributes.setdefault('table', {}).update({ - 'id': self.id, 'data-ams-plugins': 'pyams_content', 'data-ams-plugin-pyams_content-src': get_resource_path(pyams_content), 'data-ams-location': absolute_url(IParagraphContainer(self.context), self.request), @@ -132,7 +131,7 @@ message = '{0}
{1}'.format(message, translate(_("Check allowed paragraph types to be able to create " "new paragraphs."))) - return message + return self.renderEmptyTable(message) return super(ParagraphContainerBaseTable, self).render() diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/frame.py --- a/src/pyams_content/component/paragraph/zmi/frame.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/frame.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationTarget +from pyams_content.component.association.interfaces import IAssociationContainerTarget from pyams_content.component.association.zmi.interfaces import IAssociationsParentForm from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer from pyams_content.component.paragraph.interfaces.frame import IFrameParagraph, FRAME_PARAGRAPH_TYPE @@ -150,7 +150,7 @@ output = super(self.__class__, self).get_ajax_output(changes) if 'body' in changes.get(IFrameParagraph, ()): # refresh associations count markers - parent = get_parent(self.context, IAssociationTarget) + parent = get_parent(self.context, IAssociationContainerTarget) output.setdefault('events', []).append( get_json_paragraph_toolbar_refresh_event(parent, self.request, ParagraphContainerTable, ParagraphTitleToolbarViewletManager)) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/html.py --- a/src/pyams_content/component/paragraph/zmi/html.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/html.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.association.interfaces import IAssociationTarget +from pyams_content.component.association.interfaces import IAssociationContainerTarget from pyams_content.component.association.zmi.interfaces import IAssociationsParentForm from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphFactorySettings, \ IParagraphContainer @@ -223,7 +223,7 @@ output = super(self.__class__, self).get_ajax_output(changes) if 'body' in changes.get(IHTMLParagraph, ()): # refresh associations count markers - parent = get_parent(self.context, IAssociationTarget) + parent = get_parent(self.context, IAssociationContainerTarget) output.setdefault('events', []).append( get_json_paragraph_toolbar_refresh_event(parent, self.request)) # refresh associations table @@ -252,7 +252,7 @@ output = super(self.__class__, self).get_ajax_output(changes) if 'body' in changes.get(IHTMLParagraph, ()): # refresh associations count markers - parent = get_parent(self.context, IAssociationTarget) + parent = get_parent(self.context, IAssociationContainerTarget) output.setdefault('events', []).append( get_json_paragraph_toolbar_refresh_event(parent, self.request)) # refresh associations table diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/keynumber.py --- a/src/pyams_content/component/paragraph/zmi/keynumber.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/keynumber.py Wed Jun 27 16:42:01 2018 +0200 @@ -14,60 +14,39 @@ # import standard library -import json # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer -from pyams_content.component.paragraph.interfaces.keynumber import KEYNUMBER_PARAGRAPH_TYPE, IKeyNumberParagraph, \ - IKeyNumberContainer, IKeyNumberContainerTarget, IKeyNumber +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, IInnerSubForm +from pyams_form.interfaces.form import IInnerForm from pyams_i18n.interfaces import II18n -from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IWidgetTitleViewletManager +from pyams_skin.interfaces.viewlet import IToolbarAddingMenu from pyams_skin.layer import IPyAMSLayer from z3c.form.interfaces import INPUT_MODE -from z3c.table.interfaces import IValues, IColumn # import packages -from pyams_content.component.paragraph.keynumber import KeyNumberParagraph, KeyNumber +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 AJAXAddForm, ajax_config -from pyams_form.security import ProtectedFormObjectMixin -from pyams_i18n.column import I18nAttrColumn +from pyams_form.form import ajax_config from pyams_pagelet.pagelet import pagelet_config -from pyams_skin.container import switch_element_visibility -from pyams_skin.event import get_json_widget_refresh_event, get_json_switched_table_refresh_event, \ - get_json_table_row_refresh_event -from pyams_skin.table import BaseTable, SorterColumn, I18nColumn, VisibilitySwitcherColumn, TrashColumn -from pyams_skin.viewlet.toolbar import ToolbarAction -from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter +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_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config -from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm -from pyams_zmi.zmi.table import InnerTableView -from pyramid.decorator import reify -from pyramid.view import view_config +from pyams_zmi.form import AdminDialogAddForm from z3c.form import field, button -from z3c.table.column import GetAttrColumn from zope.interface import implementer, Interface from pyams_content import _ -class IKeyNumbersView(Interface): - """Key numbers view marker interface""" - - -class IKeyNumbersParentForm(Interface): - """Key numbers parent form marker interface""" - - @viewlet_config(name='add-keynumber-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView, layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=600) class KeyNumberParagraphAddMenu(BaseParagraphAddMenu): @@ -103,6 +82,7 @@ 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""" @@ -145,191 +125,3 @@ output.setdefault('events', []).append( get_json_widget_refresh_event(self.context, self.request, KeyNumberParagraphInnerEditForm, 'renderer')) return output - - -# -# Key number items table view -# - -class KeyNumbersTable(ProtectedFormObjectMixin, BaseTable): - """Key numbers view inner table""" - - prefix = 'keynumbers' - - hide_header = True - sortOn = None - - @property - def cssClasses(self): - classes = ['table', 'table-bordered', 'table-striped', 'table-hover', 'table-tight'] - permission = self.permission - if (not permission) or self.request.has_permission(permission, self.context): - classes.append('table-dnd') - return {'table': ' '.join(classes)} - - @property - def data_attributes(self): - attributes = super(KeyNumbersTable, self).data_attributes - attributes['table'] = { - 'id': self.id, - 'data-ams-location': absolute_url(IKeyNumberContainer(self.context), 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' - } - return attributes - - @reify - def values(self): - return list(super(KeyNumbersTable, self).values) - - -@adapter_config(context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), provides=IValues) -class KeyNumbersTableValuesAdapter(ContextRequestViewAdapter): - """Key numbers table values adapter""" - - @property - def values(self): - return IKeyNumberContainer(self.context).values() - - -@adapter_config(name='sorter', context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), provides=IColumn) -class KeyNumbersTableSorterColumn(ProtectedFormObjectMixin, SorterColumn): - """Key numbers table sorter column""" - - -@view_config(name='set-keynumbers-order.json', context=IKeyNumberContainer, request_type=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) -def set_keynumbers_order(request): - """Update key numbers order""" - order = list(map(str, json.loads(request.params.get('names')))) - request.context.updateOrder(order) - return {'status': 'success'} - - -@adapter_config(name='show-hide', context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), - provides=IColumn) -class KeyNumbersTableShowHideColumn(ProtectedFormObjectMixin, VisibilitySwitcherColumn): - """Key numbers container visibility switcher column""" - - -@view_config(name='switch-keynumber-visibility.json', context=IKeyNumberContainer, request_type=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) -def switch_keynumber_visibility(request): - """Switch key number visibility""" - return switch_element_visibility(request, IKeyNumberContainer) - - -@adapter_config(name='name', context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), provides=IColumn) -class KeyNumbersTableNameColumn(I18nColumn, GetAttrColumn): - """Key numbers table number column""" - - _header = _("Number") - attrName = 'number' - weight = 10 - - -@adapter_config(name='label', context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), provides=IColumn) -class KeyNumbersTableLabelColumn(I18nColumn, I18nAttrColumn): - """Key numbers table label column""" - - _header = _('key-number-label', default="Header") - attrName = 'label' - weight = 20 - - def getValue(self, obj): - return super(KeyNumbersTableLabelColumn, self).getValue(obj) or '--' - - -@adapter_config(name='text', context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), provides=IColumn) -class KeyNumbersTableTextColumn(I18nColumn, I18nAttrColumn): - """Key numbers table text column""" - - _header = _("Associated text") - attrName = 'text' - weight = 30 - - def getValue(self, obj): - return super(KeyNumbersTableTextColumn, self).getValue(obj) or '--' - - -@adapter_config(name='trash', context=(IKeyNumberContainerTarget, IPyAMSLayer, KeyNumbersTable), provides=IColumn) -class KeyNumbersTableTrashColumn(ProtectedFormObjectMixin, TrashColumn): - """Key numbers table trash column""" - - -@adapter_config(name='keynumbers', context=(IKeyNumberContainerTarget, IPyAMSLayer, IKeyNumbersParentForm), - provides=IInnerSubForm) -@implementer(IKeyNumbersView) -class KeyNumbersView(InnerTableView): - """Key numbers view""" - - title = _("Key numbers") - - table_class = KeyNumbersTable - weight = 110 - - -# -# Key numbers forms -# - -@viewlet_config(name='add-keynumber.action', context=IKeyNumberContainerTarget, layer=IPyAMSLayer, view=IKeyNumbersView, - manager=IWidgetTitleViewletManager, permission=MANAGE_CONTENT_PERMISSION, weight=1) -class KeyNumberAddAction(ToolbarAction): - """Key number add action""" - - label = _("Add keynumber") - label_css_class = 'fa fa-fw fa-plus' - url = 'add-keynumber.html' - modal_target = True - - -@pagelet_config(name='add-keynumber.html', context=IKeyNumberContainerTarget, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION) -@ajax_config(name='add-keynumber.json', context=IParagraphContainerTarget, layer=IPyAMSLayer, - base=AJAXAddForm) -class KeyNumberAddForm(AdminDialogAddForm): - """Key number add form""" - - legend = _("Add new keynumber") - icon_css_class = 'fa fa-fw fa-dashboard' - - fields = field.Fields(IKeyNumber).omit('__parent__', '__name__', 'visible') - edit_permission = MANAGE_CONTENT_PERMISSION - - def create(self, data): - return KeyNumber() - - def add(self, object): - IKeyNumberContainer(self.context).append(object) - - def get_ajax_output(self, changes): - return { - 'status': 'success', - 'message': self.request.localizer.translate(_("Key number was correctly added")), - 'events': [get_json_switched_table_refresh_event(self.context, self.request, KeyNumbersTable), ] - } - - -@pagelet_config(name='properties.html', context=IKeyNumber, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) -@ajax_config(name='properties.json', context=IKeyNumber, layer=IPyAMSLayer) -class KeyNumberPropertiesEditForm(AdminDialogEditForm): - """Key number properties edit form""" - - prefix = 'keynumber_properties.' - - legend = _("Edit keynumber properties") - icon_css_class = 'fa fa-fw fa-dashboard' - - fields = field.Fields(IKeyNumber).omit('__parent__', '__name__', 'visible') - edit_permission = MANAGE_CONTENT_PERMISSION - - def get_ajax_output(self, changes): - output = super(self.__class__, self).get_ajax_output(changes) - updated = changes.get(IKeyNumber, ()) - if updated: - target = get_parent(self.context, IKeyNumberContainerTarget) - output.setdefault('events', []).append( - get_json_table_row_refresh_event(target, self.request, KeyNumbersTable, self.context)) - return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/milestone.py --- a/src/pyams_content/component/paragraph/zmi/milestone.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/milestone.py Wed Jun 27 16:42:01 2018 +0200 @@ -304,7 +304,7 @@ @pagelet_config(name='add-milestone.html', context=IMilestoneContainerTarget, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) -@ajax_config(name='add-milestone.json', context=IParagraphContainerTarget, layer=IPyAMSLayer, +@ajax_config(name='add-milestone.json', context=IMilestoneContainerTarget, layer=IPyAMSLayer, base=AJAXAddForm) class MilestoneAddForm(AdminDialogAddForm): """Milestone add form""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/pictogram.py --- a/src/pyams_content/component/paragraph/zmi/pictogram.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/pictogram.py Wed Jun 27 16:42:01 2018 +0200 @@ -23,13 +23,11 @@ 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.reference.pictograms.interfaces import IPictogramTable from pyams_content.shared.common import IWfSharedContent from pyams_form.interfaces.form import IInnerForm, IInnerSubForm from pyams_i18n.interfaces import II18n from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IWidgetTitleViewletManager from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces.data import IObjectData from pyams_zmi.interfaces import IPropertiesEditForm from z3c.form.interfaces import INPUT_MODE, IDataExtractedEvent from z3c.table.interfaces import IValues, IColumn @@ -40,6 +38,8 @@ from pyams_content.component.paragraph.zmi import BaseParagraphAddMenu, BaseParagraphAJAXAddForm, \ BaseParagraphPropertiesEditForm, BaseParagraphAJAXEditForm from pyams_content.features.renderer.zmi.widget import RendererFieldWidget +from pyams_content.reference.pictograms.zmi.widget import PictogramSelectFieldWidget +from pyams_file.zmi.image import render_image from pyams_form.form import AJAXAddForm, ajax_config from pyams_form.security import ProtectedFormObjectMixin from pyams_i18n.column import I18nAttrColumn @@ -50,7 +50,6 @@ from pyams_skin.table import BaseTable, SorterColumn, I18nColumn, TrashColumn, VisibilitySwitcherColumn from pyams_skin.viewlet.toolbar import ToolbarAction from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter -from pyams_utils.registry import query_utility from pyams_utils.text import get_text_start from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url @@ -229,7 +228,7 @@ if pictogram is not None: image = II18n(pictogram).query_attribute('image', request=self.request) if image: - return ''.format(absolute_url(image, self.request, '++thumb++48x48')) + return render_image(image, 48, 48, self.request) return '--' @@ -273,7 +272,7 @@ value = super(PictogramsTableBodyColumn, self).getValue(obj) if not value: return BaseParagraph.empty_title - return get_text_start(value, 40, 10) + return get_text_start(value, 80, 10) @adapter_config(name='trash', context=(IPictogramContainerTarget, IPyAMSLayer, PictogramsTable), provides=IColumn) @@ -319,26 +318,12 @@ icon_css_class = 'fa fa-fw fa-arrow-h' fields = field.Fields(IPictogramItem).omit('__parent__', '__name__', 'visible') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = MANAGE_CONTENT_PERMISSION def updateWidgets(self, prefix=None): super(PictogramAddForm, self).updateWidgets(prefix) - if 'pictogram_name' in self.widgets: - pictograms = query_utility(IPictogramTable) - if pictograms is not None: - label_id = '{0}_pictogram_label'.format(self.id) - widget = self.widgets['pictogram_name'] - widget.after_widget_notice = '{1}'.format( - label_id, - self.request.localizer.translate(_("Default header: --"))) - widget.object_data = { - 'ams-change-handler': 'MyAMS.helpers.select2ChangeHelper', - 'ams-stop-propagation': 'true', - 'ams-select2-helper-type': 'html', - 'ams-select2-helper-url': absolute_url(pictograms, self.request, 'get-pictogram-header.html'), - 'ams-select2-helper-target': '#{0}'.format(label_id) - } - alsoProvides(widget, IObjectData) if 'body' in self.widgets: self.widgets['body'].widget_css_class = 'textarea height-100' @@ -375,32 +360,12 @@ icon_css_class = 'fa fa-fw fa-linode' fields = field.Fields(IPictogramItem).omit('__parent__', '__name__', 'visible') + fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget + edit_permission = MANAGE_CONTENT_PERMISSION def updateWidgets(self, prefix=None): super(PictogramPropertiesEditForm, self).updateWidgets(prefix) - if 'pictogram_name' in self.widgets: - pictograms = query_utility(IPictogramTable) - if pictograms is not None: - pictogram = pictograms.get(self.context.pictogram_name) - label_id = '{0}_pictogram_label'.format(self.id) - widget = self.widgets['pictogram_name'] - widget.required = True - if pictogram is None: - widget.after_widget_notice = '{1}'.format(label_id, '--') - else: - widget.after_widget_notice = '{1}'.format( - label_id, - self.request.localizer.translate(_("Default header: {0}")).format( - II18n(pictogram).query_attribute('header', request=self.request) or '--')) - widget.object_data = { - 'ams-change-handler': 'MyAMS.helpers.select2ChangeHelper', - 'ams-stop-propagation': 'true', - 'ams-select2-helper-type': 'html', - 'ams-select2-helper-url': absolute_url(pictograms, self.request, 'get-pictogram-header.html'), - 'ams-select2-helper-target': '#{0}'.format(label_id) - } - alsoProvides(widget, IObjectData) if 'body' in self.widgets: self.widgets['body'].widget_css_class = 'textarea height-100' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/preview.py --- a/src/pyams_content/component/paragraph/zmi/preview.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/preview.py Wed Jun 27 16:42:01 2018 +0200 @@ -18,7 +18,7 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \ IParagraphRenderer -from pyams_content.features.renderer.interfaces import IContentRenderer +from pyams_content.features.renderer.interfaces import ISharedContentRenderer from pyams_skin.layer import IPyAMSLayer # import packages @@ -27,7 +27,7 @@ @adapter_config(name='paragraphs-render', context=(IParagraphContainerTarget, IPyAMSLayer), - provides=IContentRenderer) + provides=ISharedContentRenderer) class ParagraphsContainerRenderer(BaseContentRenderer): """Paragraphs container renderer""" @@ -37,7 +37,8 @@ super(ParagraphsContainerRenderer, self).__init__(context, request) paragraphs = [para for para in IParagraphContainer(self.context).values() if para.visible] - self.renderers = [self.request.registry.queryMultiAdapter((paragraph, self.request), IParagraphRenderer) + registry = self.request.registry + self.renderers = [registry.queryMultiAdapter((paragraph, self.request), IParagraphRenderer) for paragraph in paragraphs] def update(self): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/paragraph/zmi/video.py --- a/src/pyams_content/component/paragraph/zmi/video.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/paragraph/zmi/video.py Wed Jun 27 16:42:01 2018 +0200 @@ -31,16 +31,14 @@ # import packages from pyams_content.component.paragraph.video import VideoParagraph from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ - BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, IParagraphEditFormButtons + BaseParagraphAddMenu, 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_form.group import NamedWidgetsGroup from pyams_pagelet.pagelet import pagelet_config from pyams_skin.event import get_json_form_refresh_event, 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 pyramid.view import view_config from z3c.form import field, button from zope.interface import implementer @@ -76,20 +74,6 @@ super(VideoParagraphAddForm, self).updateWidgets(prefix) if 'description' in self.widgets: self.widgets['description'].widget_css_class = 'textarea' - if 'body' in self.widgets: - self.widgets['body'].label = '' - - def updateGroups(self): - self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',), - bordered=False, - legend=_("HTML content"), - css_class='inner switcher padding-right-10 no-y-padding pull-left', - switch=True, - display_mode='auto')) - self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets, - ('description', 'author', 'data', 'renderer'), - bordered=False)) - super(VideoParagraphAddForm, self).updateGroups() def create(self, data): return VideoParagraph() @@ -120,21 +104,6 @@ super(VideoParagraphPropertiesEditForm, self).updateWidgets(prefix) if 'description' in self.widgets: self.widgets['description'].widget_css_class = 'textarea' - if 'body' in self.widgets: - self.widgets['body'].label = '' - - def updateGroups(self): - self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',), - bordered=False, - fieldset_class='margin-top-10 padding-y-5', - legend=_("HTML content"), - css_class='inner switcher padding-right-10 no-y-padding pull-left', - switch=True, - display_mode='auto')) - self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets, - ('description', 'author', 'data', 'renderer'), - bordered=False)) - super(VideoParagraphPropertiesEditForm, self).updateGroups() @adapter_config(context=(IVideoParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) @@ -161,8 +130,12 @@ ITransactionManager(self.context).get().commit() output.setdefault('events', []).append( get_json_form_refresh_event(self.context, self.request, VideoParagraphPropertiesInnerEditForm)) - elif 'renderer' in updated: - output.setdefault('events', []).append( - get_json_widget_refresh_event(self.context, self.request, - VideoParagraphPropertiesInnerEditForm, 'renderer')) + else: + if 'title' in updated: + output.setdefault('events', []).append( + get_json_paragraph_refresh_event(self.context, self.request)) + if 'renderer' in updated: + output.setdefault('events', []).append( + get_json_widget_refresh_event(self.context, self.request, + VideoParagraphPropertiesInnerEditForm, 'renderer')) return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/theme/zmi/__init__.py --- a/src/pyams_content/component/theme/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/theme/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -88,7 +88,7 @@ def get_subterms(self, term): for subterm in term.specifics: - if self.extract_name in subterm.extracts: + if (not self.extract_name) or (self.extract_name in subterm.extracts): yield subterm for another in self.get_subterms(subterm): yield another diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/video/interfaces/__init__.py --- a/src/pyams_content/component/video/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/video/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -21,7 +21,7 @@ from zope.contentprovider.interfaces import IContentProvider # import packages -from pyams_i18n.schema import I18nHTMLField, I18nTextField +from pyams_i18n.schema import I18nTextField, I18nTextLineField from zope.interface import Interface, Attribute from zope.schema import Choice, TextLine @@ -72,8 +72,8 @@ class IExternalVideoParagraph(IExternalVideo, IBaseParagraph): """External video paragraph""" - body = I18nHTMLField(title=_("Body"), - required=False) + title = I18nTextLineField(title=_("Legend"), + required=False) renderer = Choice(title=_("Video template"), description=_("Presentation template used for this video"), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/video/paragraph.py --- a/src/pyams_content/component/video/paragraph.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/video/paragraph.py Wed Jun 27 16:42:01 2018 +0200 @@ -44,7 +44,6 @@ icon_class = 'fa-youtube-play' icon_hint = EXTERNAL_VIDEO_PARAGRAPH_NAME - body = FieldProperty(IExternalVideoParagraph['body']) renderer = FieldProperty(IExternalVideoParagraph['renderer']) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/component/video/zmi/paragraph.py --- a/src/pyams_content/component/video/zmi/paragraph.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/component/video/zmi/paragraph.py Wed Jun 27 16:42:01 2018 +0200 @@ -76,15 +76,13 @@ dialog_class = 'modal-large' icon_css_class = 'fa fa-fw fa-youtube-play' - fields = field.Fields(IExternalVideoParagraph).omit('__parent__', '__name__', 'visible') + fields = field.Fields(IExternalVideoParagraph).select('title', 'description', 'author', 'renderer', 'provider_name') edit_permission = MANAGE_CONTENT_PERMISSION def updateWidgets(self, prefix=None): super(ExternalVideoParagraphAddForm, self).updateWidgets(prefix) if 'description' in self.widgets: self.widgets['description'].widget_css_class = 'textarea' - if 'body' in self.widgets: - self.widgets['body'].label = '' if 'provider_name' in self.widgets: widget = self.widgets['provider_name'] widget.object_data = { @@ -98,19 +96,6 @@ } alsoProvides(widget, IObjectData) - def updateGroups(self): - if 'body' in self.widgets: - self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',), - bordered=False, - legend=_("HTML content"), - css_class='inner switcher padding-right-10 no-y-padding pull-left', - switch=True, - display_mode='auto')) - self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets, - ('description', 'author', 'renderer', 'provider_name'), - bordered=False)) - super(ExternalVideoParagraphAddForm, self).updateGroups() - def create(self, data): return ExternalVideoParagraph() @@ -211,7 +196,8 @@ @property def fields(self): - fields = field.Fields(IExternalVideoParagraph).omit('__parent__', '__name__', 'visible') + fields = field.Fields(IExternalVideoParagraph).select('title', 'description', 'author', 'renderer', + 'provider_name') fields['renderer'].widgetFactory = RendererFieldWidget provider = self.context.get_provider() if provider is not None: @@ -222,23 +208,10 @@ super(ExternalVideoParagraphPropertiesEditForm, self).updateWidgets(prefix) if 'description' in self.widgets: self.widgets['description'].widget_css_class = 'textarea' - if 'body' in self.widgets: - self.widgets['body'].label = '' if 'provider_name' in self.widgets: self.widgets['provider_name'].mode = DISPLAY_MODE def updateGroups(self): - if 'body' in self.widgets: - self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',), - bordered=False, - fieldset_class='margin-top-10 padding-y-5', - legend=_("HTML content"), - css_class='inner switcher padding-right-10 no-y-padding pull-left', - switch=True, - display_mode='auto')) - self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets, - ('description', 'author', 'renderer', 'provider_name'), - bordered=False)) if 'provider_name' in self.widgets: provider = self.context.get_provider() if provider is not None: @@ -261,7 +234,7 @@ def get_ajax_output(self, changes): output = super(self.__class__, self).get_ajax_output(changes) - if 'title' in changes.get(IBaseParagraph, ()): + if 'title' in changes.get(IExternalVideoParagraph, ()): output.setdefault('events', []).append( get_json_paragraph_refresh_event(self.context, self.request)) return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/alert/zmi/container.py --- a/src/pyams_content/features/alert/zmi/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/alert/zmi/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -71,7 +71,6 @@ def data_attributes(self): attributes = super(AlertContainerTable, self).data_attributes attributes.setdefault('table', {}).update({ - 'id': self.id, 'data-ams-plugins': 'pyams_content', 'data-ams-plugin-pyams_content-src': get_resource_path(pyams_content), 'data-ams-location': absolute_url(IAlertContainer(self.context), self.request), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/footer/skin/__init__.py --- a/src/pyams_content/features/footer/skin/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/footer/skin/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,10 +19,12 @@ from pyams_content.features.footer.interfaces import IFooterTarget, IFooterRenderer, IFooterSettings from pyams_content.features.renderer.interfaces import HIDDEN_RENDERER_NAME from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces.url import DISPLAY_CONTEXT # import packages from pyams_content.features.renderer.skin import BaseContentRenderer from pyams_utils.adapter import adapter_config +from pyams_utils.traversing import get_parent from pyramid.decorator import reify from pyams_content import _ @@ -35,7 +37,11 @@ def settings(self): if self.settings_interface is None: return None - settings = IFooterSettings(self.context) + context = self.request.annotations.get(DISPLAY_CONTEXT) + if context is None: + context = self.context + target = get_parent(context, IFooterTarget) + settings = IFooterSettings(target) while settings.inherit: settings = IFooterSettings(settings.parent) return settings.settings diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/footer/zmi/__init__.py --- a/src/pyams_content/features/footer/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/footer/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,22 +19,26 @@ from pyams_content.features.footer.interfaces import IFooterTarget, IFooterSettings, IFooterRenderer, \ IFooterRendererSettings from pyams_form.interfaces.form import IWidgetForm, IUncheckedEditFormButtons, IInnerSubForm, \ - IWidgetsSuffixViewletsManager + IWidgetsSuffixViewletsManager, IFormHelp from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION from pyams_portal.zmi.interfaces import IPortalContextTemplatePropertiesMenu from pyams_skin.interfaces import IInnerPage from pyams_skin.layer import IPyAMSLayer from pyams_utils.interfaces.data import IObjectData from pyams_utils.interfaces.inherit import IInheritInfo +from pyams_zmi.layer import IAdminLayer from z3c.form.interfaces import INPUT_MODE # import packages -from pyams_form.form import ajax_config +from pyams_content.skin import pyams_content +from pyams_form.form import AJAXEditForm from pyams_form.group import NamedWidgetsGroup +from pyams_form.help import FormHelp from pyams_pagelet.pagelet import pagelet_config from pyams_skin.viewlet.menu import MenuItem from pyams_template.template import template_config from pyams_utils.adapter import adapter_config +from pyams_utils.fanstatic import get_resource_path from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config, Viewlet from pyams_zmi.form import AdminEditForm, InnerAdminEditForm @@ -63,8 +67,6 @@ @pagelet_config(name='footer-settings.html', context=IFooterTarget, layer=IPyAMSLayer, permission=MANAGE_TEMPLATE_PERMISSION) -@ajax_config(name='footer-settings.json', context=IFooterTarget, layer=IPyAMSLayer, - permission=MANAGE_TEMPLATE_PERMISSION) @implementer(IWidgetForm, IInnerPage) class FooterSettingsEditForm(AdminEditForm): """Footer settings edit form""" @@ -87,6 +89,8 @@ fields = field.Fields(Interface) return fields + edit_permission = MANAGE_TEMPLATE_PERMISSION + @property def buttons(self): if self.mode == INPUT_MODE: @@ -94,6 +98,8 @@ else: return button.Buttons(Interface) + ajax_handler = 'footer-settings.json' + def updateGroups(self): if self.getContent().can_inherit: group = NamedWidgetsGroup(self, 'footer', self.widgets, @@ -104,19 +110,49 @@ checkbox_switch=True, checkbox_mode='disable', checkbox_field=IFooterSettings['no_inherit']) + if self.mode == INPUT_MODE: + group.object_data = { + 'ams-plugins': 'pyams_content', + 'ams-plugin-pyams_content-src': get_resource_path(pyams_content), + 'ams-plugin-pyams_content-async': False, + 'ams-events-handlers': { + 'ams.checker.opened': 'PyAMS_content.footer.submitEditForm', + 'ams.checker.closed': 'PyAMS_content.footer.submitEditForm' + } + } + alsoProvides(group, IObjectData) else: group = NamedWidgetsGroup(self, 'footer', self.widgets, (), css_class='inner') alsoProvides(group, IFooterSettingsGroup) self.add_group(group) super(FooterSettingsEditForm, self).updateGroups() + +@view_config(name='footer-settings.json', context=IFooterTarget, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +class FooterSettingsAJAXEditForm(AJAXEditForm, FooterSettingsEditForm): + """Footer settings edit form, JSON renderer""" + def get_ajax_output(self, changes): - output = super(self.__class__, self).get_ajax_output(changes) or {} + output = super(FooterSettingsAJAXEditForm, self).get_ajax_output(changes) or {} if 'no_inherit' in changes.get(IInheritInfo, ()): output['status'] = 'reload' return output +@adapter_config(context=(Interface, IAdminLayer, FooterSettingsEditForm), provides=IFormHelp) +class FooterSettingsEditFormHelpAdapter(FormHelp): + """Footer settings edit form help adapter""" + + def __new__(cls, context, request, view): + if (not view.getContent().can_inherit) or (view.mode != INPUT_MODE): + return None + return FormHelp.__new__(cls) + + message = _("""WARNING: Footer properties are saved automatically when changing inherit mode!!""") + message_format = 'rest' + + @adapter_config(name='renderer', context=(IFooterTarget, IPyAMSLayer, IFooterSettingsGroup), provides=IInnerSubForm) class FooterSettingsRendererEditSubform(InnerAdminEditForm): """Footer settings renderer edit form""" @@ -126,10 +162,17 @@ fields = field.Fields(IFooterSettings).select('renderer') weight = 1 + edit_permission = MANAGE_TEMPLATE_PERMISSION + + _changes = None + def __init__(self, context, request, group): context = IFooterSettings(context) super(FooterSettingsRendererEditSubform, self).__init__(context, request, group) + def getContent(self): + return IFooterSettings(self.context) + def updateWidgets(self, prefix=None): super(FooterSettingsRendererEditSubform, self).updateWidgets(prefix) if 'renderer' in self.widgets: @@ -146,19 +189,30 @@ alsoProvides(widget, IObjectData) def get_forms(self, include_self=True): - if include_self and self.request.method == 'POST': + if include_self and (self._changes is None) and (self.request.method == 'POST'): data, errors = self.extractData() if not errors: - self.applyChanges(data) + self._changes = self.applyChanges(data) for form in super(FooterSettingsRendererEditSubform, self).get_forms(include_self): yield form + def get_ajax_output(self, changes): + if not changes: + changes = self._changes + if changes: + return { + 'status': 'success', + 'message': self.request.localizer.translate(self.successMessage) + } + else: + return super(FooterSettingsRendererEditSubform, self).get_ajax_output(changes) + @adapter_config(name='footer-renderer-settings-form', context=(IFooterRendererSettings, IPyAMSLayer, FooterSettingsRendererEditSubform), provides=IInnerSubForm) @adapter_config(name='footer-renderer-settings-form', - context=(IFooterTarget, IPyAMSLayer, FooterSettingsEditForm), + context=(IFooterTarget, IPyAMSLayer, FooterSettingsAJAXEditForm), provides=IInnerSubForm) class FooterSettingsRendererSettingsEditForm(InnerAdminEditForm): """Footer settings renderer settings edit form""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/header/skin/__init__.py --- a/src/pyams_content/features/header/skin/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/header/skin/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,10 +19,12 @@ from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderRenderer, IHeaderSettings from pyams_content.features.renderer.interfaces import HIDDEN_RENDERER_NAME from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces.url import DISPLAY_CONTEXT # import packages from pyams_content.features.renderer.skin import BaseContentRenderer from pyams_utils.adapter import adapter_config +from pyams_utils.traversing import get_parent from pyramid.decorator import reify from pyams_content import _ @@ -35,7 +37,11 @@ def settings(self): if self.settings_interface is None: return None - settings = IHeaderSettings(self.context) + context = self.request.annotations.get(DISPLAY_CONTEXT) + if context is None: + context = self.context + target = get_parent(context, IHeaderTarget) + settings = IHeaderSettings(target) while settings.inherit: settings = IHeaderSettings(settings.parent) return settings.settings diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/header/zmi/__init__.py --- a/src/pyams_content/features/header/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/header/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,22 +19,26 @@ from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderSettings, IHeaderRenderer, \ IHeaderRendererSettings from pyams_form.interfaces.form import IWidgetForm, IUncheckedEditFormButtons, IInnerSubForm, \ - IWidgetsSuffixViewletsManager + IWidgetsSuffixViewletsManager, IFormHelp from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION from pyams_portal.zmi.interfaces import IPortalContextTemplatePropertiesMenu from pyams_skin.interfaces import IInnerPage from pyams_skin.layer import IPyAMSLayer from pyams_utils.interfaces.data import IObjectData from pyams_utils.interfaces.inherit import IInheritInfo +from pyams_zmi.layer import IAdminLayer from z3c.form.interfaces import INPUT_MODE # import packages -from pyams_form.form import ajax_config +from pyams_content.skin import pyams_content +from pyams_form.form import AJAXEditForm from pyams_form.group import NamedWidgetsGroup +from pyams_form.help import FormHelp from pyams_pagelet.pagelet import pagelet_config from pyams_skin.viewlet.menu import MenuItem, MenuDivider from pyams_template.template import template_config from pyams_utils.adapter import adapter_config +from pyams_utils.fanstatic import get_resource_path from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config, Viewlet from pyams_zmi.form import AdminEditForm, InnerAdminEditForm @@ -69,8 +73,6 @@ @pagelet_config(name='header-settings.html', context=IHeaderTarget, layer=IPyAMSLayer, permission=MANAGE_TEMPLATE_PERMISSION) -@ajax_config(name='header-settings.json', context=IHeaderTarget, layer=IPyAMSLayer, - permission=MANAGE_TEMPLATE_PERMISSION) @implementer(IWidgetForm, IInnerPage) class HeaderSettingsEditForm(AdminEditForm): """Header settings edit form""" @@ -93,6 +95,8 @@ fields = field.Fields(Interface) return fields + edit_permission = MANAGE_TEMPLATE_PERMISSION + @property def buttons(self): if self.mode == INPUT_MODE: @@ -100,6 +104,8 @@ else: return button.Buttons(Interface) + ajax_handler = 'header-settings.json' + def updateGroups(self): if self.getContent().can_inherit: group = NamedWidgetsGroup(self, 'header', self.widgets, @@ -110,19 +116,52 @@ checkbox_switch=True, checkbox_mode='disable', checkbox_field=IHeaderSettings['no_inherit']) + if self.mode == INPUT_MODE: + group.object_data = { + 'ams-plugins': 'pyams_content', + 'ams-plugin-pyams_content-src': get_resource_path(pyams_content), + 'ams-plugin-pyams_content-async': False, + 'ams-events-handlers': { + 'ams.checker.opened': 'PyAMS_content.header.submitEditForm', + 'ams.checker.closed': 'PyAMS_content.header.submitEditForm' + } + } + alsoProvides(group, IObjectData) else: group = NamedWidgetsGroup(self, 'header', self.widgets, (), css_class='inner') alsoProvides(group, IHeaderSettingsGroup) self.add_group(group) super(HeaderSettingsEditForm, self).updateGroups() + +@view_config(name='header-settings.json', context=IHeaderTarget, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +class HeaderSettingsAJAXEditForm(AJAXEditForm, HeaderSettingsEditForm): + """Header settings edit form, JSON renderer""" + def get_ajax_output(self, changes): - output = super(self.__class__, self).get_ajax_output(changes) or {} + output = super(HeaderSettingsAJAXEditForm, self).get_ajax_output(changes) or {} if 'no_inherit' in changes.get(IInheritInfo, ()): - output['status'] = 'reload' + if 'autosubmit' in self.request.params: + output['close_form'] = False + else: + output['status'] = 'reload' return output +@adapter_config(context=(Interface, IAdminLayer, HeaderSettingsEditForm), provides=IFormHelp) +class HeaderSettingsEditFormHelpAdapter(FormHelp): + """Header settings edit form help adapter""" + + def __new__(cls, context, request, view): + if (not view.getContent().can_inherit) or (view.mode != INPUT_MODE): + return None + return FormHelp.__new__(cls) + + message = _("""WARNING: Header properties are saved automatically when changing inherit mode!!""") + message_format = 'rest' + + @adapter_config(name='renderer', context=(IHeaderTarget, IPyAMSLayer, IHeaderSettingsGroup), provides=IInnerSubForm) class HeaderSettingsRendererEditSubform(InnerAdminEditForm): """Header settings renderer edit form""" @@ -132,10 +171,17 @@ fields = field.Fields(IHeaderSettings).select('renderer') weight = 1 + edit_permission = MANAGE_TEMPLATE_PERMISSION + + _changes = None + def __init__(self, context, request, group): context = IHeaderSettings(context) super(HeaderSettingsRendererEditSubform, self).__init__(context, request, group) + def getContent(self): + return IHeaderSettings(self.context) + def updateWidgets(self, prefix=None): super(HeaderSettingsRendererEditSubform, self).updateWidgets(prefix) if 'renderer' in self.widgets: @@ -152,19 +198,30 @@ alsoProvides(widget, IObjectData) def get_forms(self, include_self=True): - if include_self and self.request.method == 'POST': + if include_self and (self._changes is None) and (self.request.method == 'POST'): data, errors = self.extractData() if not errors: - self.applyChanges(data) + self._changes = self.applyChanges(data) for form in super(HeaderSettingsRendererEditSubform, self).get_forms(include_self): yield form + def get_ajax_output(self, changes): + if not changes: + changes = self._changes + if changes: + return { + 'status': 'success', + 'message': self.request.localizer.translate(self.successMessage) + } + else: + return super(HeaderSettingsRendererEditSubform, self).get_ajax_output(changes) + @adapter_config(name='header-renderer-settings-form', context=(IHeaderRendererSettings, IPyAMSLayer, HeaderSettingsRendererEditSubform), provides=IInnerSubForm) @adapter_config(name='header-renderer-settings-form', - context=(IHeaderTarget, IPyAMSLayer, HeaderSettingsEditForm), + context=(IHeaderTarget, IPyAMSLayer, HeaderSettingsAJAXEditForm), provides=IInnerSubForm) class HeaderSettingsRendererSettingsEditForm(InnerAdminEditForm): """Header settings renderer settings edit form""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,44 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.menu.interfaces import IMenu, IMenusContainer, IMenuLink + +# import packages +from pyams_content.component.association.container import AssociationContainer +from zope.interface import implementer +from zope.schema.fieldproperty import FieldProperty + + +# +# Menus classes +# + +@implementer(IMenu) +class Menu(AssociationContainer): + """Associations menu""" + + visible = FieldProperty(IMenu['visible']) + title = FieldProperty(IMenu['title']) + + +@implementer(IMenusContainer) +class MenusContainer(AssociationContainer): + """Associations menus container""" + + def get_visible_items(self): + return filter(lambda x: IMenu(x).visible, self.values()) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,75 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.association.interfaces import IAssociationContainer, IAssociationContainerTarget +from zope.annotation.interfaces import IAttributeAnnotatable + +# import packages +from pyams_i18n.schema import I18nTextLineField +from zope.container.constraints import containers, contains +from zope.interface import Interface +from zope.schema import Bool + +from pyams_content import _ + + +class IMenuLink(Interface): + """Menu link marker interface""" + + +class IMenuInternalLink(IMenuLink): + """Menu internal link marker interface""" + + +class IMenuExternalLink(IMenuLink): + """Menu external link marker interface""" + + +class IMenuLinksContainer(IAssociationContainer): + """Menu links container interface""" + + contains(IMenuLink) + + +class IMenuLinksContainerTarget(IAssociationContainerTarget): + """Menu links container marker interface""" + + +class IMenu(IMenuLinksContainer): + """Menu container interface""" + + containers('.IMenusContainer') + + visible = Bool(title=_("Visible?"), + description=_("Is this item visible in front-office?"), + required=True, + default=True) + + title = I18nTextLineField(title=_("Menu title"), + description=_("Displayed menu label"), + required=True) + + +class IMenusContainer(IAssociationContainer): + """Menus container interface""" + + contains(IMenu) + + +class IMenusContainerTarget(IAssociationContainerTarget): + """Menus container target marker interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/double.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/double.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,84 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY +from pyams_content.component.illustration.interfaces import IBasicIllustrationTarget +from pyams_content.features.menu.interfaces import IMenusContainer, IMenusContainerTarget +from pyams_content.features.menu.portlet.navigation.interfaces.double import IDoubleNavigationPortletSettings, \ + IDoubleNavigationMenu, IDoubleNavigationMenusContainer +from pyams_utils.interfaces import VIEW_PERMISSION +from zope.lifecycleevent.interfaces import IObjectAddedEvent + +# import packages +from pyams_content.features.menu import MenusContainer +from pyams_portal.portlet import PortletSettings, portlet_config, Portlet +from pyams_utils.adapter import get_annotation_adapter, adapter_config +from pyams_utils.factory import factory_config +from pyramid.events import subscriber +from zope.interface import implementer, alsoProvides +from zope.schema.fieldproperty import FieldProperty + +from pyams_content import _ + + +DOUBLE_NAVIGATION_PORTLET_NAME = 'pyams_content.portlet.navigation.double' +DOUBLE_NAVIGATION_LINKS_KEY = '{0}::menus'.format(ASSOCIATION_CONTAINER_KEY) + + +@implementer(IDoubleNavigationPortletSettings, IMenusContainerTarget) +@factory_config(provided=IDoubleNavigationPortletSettings) +class DoubleNavigationPortletSettings(PortletSettings): + """Double navigation portlet settings""" + + title = FieldProperty(IDoubleNavigationPortletSettings['title']) + subtitle = FieldProperty(IDoubleNavigationPortletSettings['subtitle']) + + @property + def menus(self): + return get_annotation_adapter(self, DOUBLE_NAVIGATION_LINKS_KEY, MenusContainer, + markers=IDoubleNavigationMenusContainer, name='++ass++menus') + + +@adapter_config(name='menus', context=IDoubleNavigationPortletSettings, provides=IMenusContainer) +def simple_navigation_links_adapter(context): + """Double navigation menus factory""" + return context.menus + + +@portlet_config(permission=VIEW_PERMISSION) +class DoubleNavigationPortlet(Portlet): + """Double navigation portlet""" + + name = DOUBLE_NAVIGATION_PORTLET_NAME + label = _("Double navigation") + + toolbar_css_class = 'fa fa-fw fa-2x fa-list-alt' + + settings_factory = IDoubleNavigationPortletSettings + + +@subscriber(IObjectAddedEvent, parent_selector=IDoubleNavigationMenusContainer) +def handle_added_navigation_menu(event): + """Add marker interface to added menus container""" + alsoProvides(event.object, IDoubleNavigationMenu, IBasicIllustrationTarget) + + +@subscriber(IObjectAddedEvent, parent_selector=IDoubleNavigationMenu) +def handle_added_navigation_menu_link(event): + """Add marker interface to added menu link""" + alsoProvides(event.object, IBasicIllustrationTarget) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,1 @@ +# diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/interfaces/double.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/double.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_portal.interfaces import IPortletSettings + +# import packages +from pyams_i18n.schema import I18nTextLineField +from zope.interface import Interface, Attribute + +from pyams_content import _ + + +class IDoubleNavigationPortletSettings(IPortletSettings): + """Double navigation portlet settings interface""" + + title = I18nTextLineField(title=_("Title"), + description=_("Portlet main title"), + required=False) + + subtitle = I18nTextLineField(title=_("Subtitle"), + description=_("Portlet subtitle"), + required=False) + + menus = Attribute("Navigation menus") + + +class IDoubleNavigationMenusContainer(Interface): + """Double navigation menus container marker interface""" + + +class IDoubleNavigationMenu(Interface): + """Double navigation menu marker interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,43 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_portal.interfaces import IPortletSettings + +# import packages +from pyams_i18n.schema import I18nTextLineField +from zope.interface import Interface, Attribute + +from pyams_content import _ + + +class ISimpleNavigationPortletSettings(IPortletSettings): + """Simple navigation portlet settings interface""" + + title = I18nTextLineField(title=_("Title"), + description=_("Portlet main title"), + required=False) + + subtitle = I18nTextLineField(title=_("Subtitle"), + description=_("Portlet subtitle"), + required=False) + + links = Attribute("Navigation links") + + +class ISimpleNavigationMenu(Interface): + """Simple navigation menu marker interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/simple.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/simple.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,77 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY +from pyams_content.component.illustration import IBasicIllustrationTarget +from pyams_content.features.menu.interfaces import IMenuLinksContainer, IMenuLinksContainerTarget +from pyams_content.features.menu.portlet.navigation.interfaces.simple import ISimpleNavigationPortletSettings, \ + ISimpleNavigationMenu +from pyams_utils.interfaces import VIEW_PERMISSION +from zope.lifecycleevent.interfaces import IObjectAddedEvent + +# import packages +from pyams_content.features.menu import Menu +from pyams_portal.portlet import PortletSettings, portlet_config, Portlet +from pyams_utils.adapter import get_annotation_adapter, adapter_config +from pyams_utils.factory import factory_config +from pyramid.events import subscriber +from zope.interface import implementer, alsoProvides +from zope.schema.fieldproperty import FieldProperty + +from pyams_content import _ + + +SIMPLE_NAVIGATION_PORTLET_NAME = 'pyams_content.portlet.navigation.simple' +SIMPLE_NAVIGATION_LINKS_KEY = '{0}::links'.format(ASSOCIATION_CONTAINER_KEY) + + +@implementer(ISimpleNavigationPortletSettings, IMenuLinksContainerTarget) +@factory_config(provided=ISimpleNavigationPortletSettings) +class SimpleNavigationPortletSettings(PortletSettings): + """Simple navigation portlet settings""" + + title = FieldProperty(ISimpleNavigationPortletSettings['title']) + subtitle = FieldProperty(ISimpleNavigationPortletSettings['subtitle']) + + @property + def links(self): + return get_annotation_adapter(self, SIMPLE_NAVIGATION_LINKS_KEY, Menu, + markers=ISimpleNavigationMenu, name='++ass++links') + + +@adapter_config(name='links', context=ISimpleNavigationPortletSettings, provides=IMenuLinksContainer) +def simple_navigation_links_adapter(context): + """Simple navigation links factory""" + return context.links + + +@portlet_config(permission=VIEW_PERMISSION) +class SimpleNavigationPortlet(Portlet): + """Simple navigation portlet""" + + name = SIMPLE_NAVIGATION_PORTLET_NAME + label = _("Simple navigation") + + toolbar_css_class = 'fa fa-fw fa-2x fa-bars' + + settings_factory = ISimpleNavigationPortletSettings + + +@subscriber(IObjectAddedEvent, parent_selector=ISimpleNavigationMenu) +def handle_added_navigation_link(event): + alsoProvides(event.object, IBasicIllustrationTarget) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/zmi/double.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/zmi/double.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,104 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.illustration.interfaces import IIllustration, ILinkIllustration +from pyams_content.component.links.interfaces import IInternalLink +from pyams_content.features.menu.portlet.navigation.interfaces.double import IDoubleNavigationPortletSettings, \ + IDoubleNavigationMenusContainer +from pyams_form.interfaces.form import IInnerSubForm +from pyams_pagelet.interfaces import IPagelet +from pyams_portal.interfaces import IPortletPreviewer +from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_workflow.interfaces import IWorkflowPublicationInfo + +# import packages +from pyams_content.component.association.interfaces import IAssociationInfo +from pyams_content.features.menu.zmi import MenusTable, IMenusView, MenusView +from pyams_form.form import AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_portal.portlet import PortletPreviewer +from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from zope.interface import alsoProvides, Interface + +from pyams_content import _ + + +@pagelet_config(name='properties.html', context=IDoubleNavigationPortletSettings, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +class DoubleNavigationPortletSettingsEditor(PortletSettingsEditor): + """Double navigation portlet settings editor""" + + settings = IDoubleNavigationPortletSettings + + +@adapter_config(name='properties.json', context=(IDoubleNavigationPortletSettings, IPyAMSLayer), provides=IPagelet) +class DoubleNavigationPortletSettingsAJAXEditor(AJAXEditForm, DoubleNavigationPortletSettingsEditor): + """Double navigation portlet settings editor, JSON renderer""" + + +class DoubleNavigationPortletMenusTable(MenusTable): + """Double navigation portlet menus table""" + + associations_name = 'menus' + + +@adapter_config(name='double-navigation-menus', + context=(IDoubleNavigationPortletSettings, IPyAMSLayer, PortletSettingsPropertiesEditor), + provides=IInnerSubForm) +@adapter_config(name='++ass++menus', context=(IDoubleNavigationMenusContainer, IPyAMSLayer), provides=IMenusView) +class DoubleNavigationPortletLinksView(MenusView): + """Double navigation portlet menus view""" + + title = _("Navigation menus") + + table_class = DoubleNavigationPortletMenusTable + weight = 10 + + +@adapter_config(context=(Interface, IPyAMSLayer, Interface, IDoubleNavigationPortletSettings), + provides=IPortletPreviewer) +@template_config(template='templates/double-preview.pt', layer=IPyAMSLayer) +class DoubleNavigationPortletPreviewer(PortletPreviewer): + """Double navigation portlet previewer""" + + @classmethod + def get_link_info(cls, link): + return IAssociationInfo(link) + + @classmethod + def get_link_status(cls, link): + if not IInternalLink.providedBy(link): + return True + target = link.get_target() + return (target is not None) and IWorkflowPublicationInfo(target).is_published() + + @classmethod + def get_link_illustration(cls, link): + illustration = IIllustration(link, None) + if (illustration is None) or not illustration.has_data(): + if IInternalLink.providedBy(link): + target = link.get_target() + if target is None: + return + illustration = ILinkIllustration(target, None) + if (illustration is None) or not illustration.has_data(): + illustration = IIllustration(target, None) + return illustration diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/zmi/simple.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/zmi/simple.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,104 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.component.illustration.interfaces import IIllustration, ILinkIllustration +from pyams_content.component.links.interfaces import IInternalLink +from pyams_content.features.menu.portlet.navigation.interfaces.simple import ISimpleNavigationPortletSettings, \ + ISimpleNavigationMenu +from pyams_form.interfaces.form import IInnerSubForm +from pyams_pagelet.interfaces import IPagelet +from pyams_portal.interfaces import IPortletPreviewer +from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_workflow.interfaces import IWorkflowPublicationInfo + +# import packages +from pyams_content.component.association.interfaces import IAssociationInfo +from pyams_content.features.menu.zmi import LinksTable, IMenuLinksView, MenuLinksView +from pyams_form.form import AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_portal.portlet import PortletPreviewer +from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from zope.interface import alsoProvides, Interface + +from pyams_content import _ + + +@pagelet_config(name='properties.html', context=ISimpleNavigationPortletSettings, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +class SimpleNavigationPortletSettingsEditor(PortletSettingsEditor): + """Simple navigation portlet settings editor""" + + settings = ISimpleNavigationPortletSettings + + +@adapter_config(name='properties.json', context=(ISimpleNavigationPortletSettings, IPyAMSLayer), provides=IPagelet) +class SimpleNavigationPortletSettingsAJAXEditor(AJAXEditForm, SimpleNavigationPortletSettingsEditor): + """Simple navigation portlet settings editor, JSON renderer""" + + +class SimpleNavigationPortletLinksTable(LinksTable): + """Simple navigation portlet links table""" + + associations_name = 'links' + + +@adapter_config(name='simple-navigation-links', + context=(ISimpleNavigationPortletSettings, IPyAMSLayer, PortletSettingsPropertiesEditor), + provides=IInnerSubForm) +@adapter_config(name='++ass++links', context=(ISimpleNavigationMenu, IPyAMSLayer), provides=IMenuLinksView) +class SimpleNavigationPortletLinksView(MenuLinksView): + """Simple navigation portlet links view""" + + title = _("Navigation links") + + table_class = SimpleNavigationPortletLinksTable + weight = 10 + + +@adapter_config(context=(Interface, IPyAMSLayer, Interface, ISimpleNavigationPortletSettings), + provides=IPortletPreviewer) +@template_config(template='templates/simple-preview.pt', layer=IPyAMSLayer) +class SimpleNavigationPortletPreviewer(PortletPreviewer): + """Simple navigation portlet previewer""" + + @classmethod + def get_link_info(cls, link): + return IAssociationInfo(link) + + @classmethod + def get_link_status(cls, link): + if not IInternalLink.providedBy(link): + return True + target = link.get_target() + return (target is not None) and IWorkflowPublicationInfo(target).is_published() + + @classmethod + def get_link_illustration(cls, link): + illustration = IIllustration(link, None) + if (illustration is None) or not illustration.has_data(): + if IInternalLink.providedBy(link): + target = link.get_target() + if target is None: + return + illustration = ILinkIllustration(target, None) + if (illustration is None) or not illustration.has_data(): + illustration = IIllustration(target, None) + return illustration diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,26 @@ +
+ Title + +
    +
  • + Title +
      +
    • + + + + User title + – + Inner title + +
    • +
    +
  • +
+
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,21 @@ +
+ Title + +
    +
  • + + + + User title + – + Inner title + +
  • +
+
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,489 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.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 +from pyams_form.interfaces.form import IFormContextPermissionChecker +from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION +from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager, IToolbarAddingMenu +from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_viewlet.interfaces import IViewletManager +from pyams_zmi.interfaces import IPropertiesEditForm +from z3c.table.interfaces import IValues, IColumn + +# import packages +from pyams_content.component.association.zmi import AssociationsTable, AssociationsTablePublicNameColumn +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.viewlet.toolbar import ToolbarAction +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 +from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm +from pyams_zmi.zmi.table import InnerTableView +from pyramid.decorator import reify +from pyramid.exceptions import NotFound +from pyramid.renderers import render +from pyramid.view import view_config +from z3c.form import field +from zope.interface import implementer, alsoProvides, Interface + +from pyams_content import _ + + +# +# Custom marker interfaces +# + +class IMenuLinksView(Interface): + """Menu links view marker interface""" + + +class IMenusView(Interface): + """Menus view marker interface""" + + +# +# Menus add and edit forms +# + +@viewlet_config(name='add-menu.action', context=IMenusContainerTarget, layer=IPyAMSLayer, + view=IMenusView, manager=IWidgetTitleViewletManager, weight=10) +class MenuAddAction(ToolbarAction): + """Menu add action""" + + label = _("Add menu...") + url = 'add-menu.html' + modal_target = True + + +@pagelet_config(name='add-menu.html', context=IMenusContainer, layer=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION) +@ajax_config(name='add-menu.json', context=IMenusContainer, layer=IPyAMSLayer, base=AJAXAddForm) +class MenuAddForm(AdminDialogAddForm): + """Menu add form""" + + legend = _("Add new menu") + icon_css_class = 'fa fa-fw fa-bars' + + fields = field.Fields(IMenu).select('title') + edit_permission = MANAGE_TEMPLATE_PERMISSION + + def create(self, data): + return Menu() + + def add(self, object): + self.context.append(object) + + def get_ajax_output(self, changes): + settings = get_parent(self.context, IMenusContainerTarget) + view = self.request.registry.getMultiAdapter((self.context, self.request), IMenusView, + name=self.context.__name__) + return { + 'status': 'success', + 'message': self.request.localizer.translate(_("Menu was correctly added.")), + 'events': [ + get_json_switched_table_refresh_event(settings, self.request, view.table_class) + ] + } + + +@pagelet_config(name='properties.html', context=IMenu, layer=IPyAMSLayer, permission=MANAGE_TEMPLATE_PERMISSION) +@ajax_config(name='properties.json', context=IMenu, layer=IPyAMSLayer) +@implementer(IPropertiesEditForm) +class MenuPropertiesEditForm(AdminDialogEditForm): + """Menu properties edit form""" + + legend = _("Edit menu properties") + icon_css_class = 'fa fa-fw fa-bars' + + dialog_class = 'modal-large' + + fields = field.Fields(IMenu).select('title') + edit_permission = MANAGE_TEMPLATE_PERMISSION + + def get_ajax_output(self, changes): + output = super(self.__class__, self).get_ajax_output(changes) + if changes: + settings = get_parent(self.context, IMenusContainerTarget) + container = settings.menus + view = self.request.registry.getMultiAdapter((container, self.request), IMenusView, + name=container.__name__) + output.setdefault('events', []).append( + get_json_table_row_refresh_event(settings, self.request, view.table_class, self.context)) + return output + + +# +# Menus table views +# + +class MenusTable(BaseTable): + """Menus table""" + + prefix = 'menus' + associations_name = 'menus' + + permission = MANAGE_TEMPLATE_PERMISSION + hide_header = True + hide_body_toolbar = True + sortOn = None + + @property + def cssClasses(self): + classes = ['table', 'table-bordered', 'table-striped', 'table-hover', 'table-tight'] + permission = self.permission + if (not permission) or self.request.has_permission(permission, self.context): + classes.append('table-dnd') + return {'table': ' '.join(classes)} + + @property + def data_attributes(self): + menus = getattr(self.context, self.associations_name) + attributes = super(MenusTable, self).data_attributes + 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' + }) + return attributes + + +@adapter_config(context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), provides=IValues) +class MenusTableValuesAdapter(ContextRequestViewAdapter): + """Menus table values adapter""" + + @property + def values(self): + return getattr(self.context, self.view.associations_name).values() + + +@adapter_config(name='sorter', context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), + provides=IColumn) +class MenusTableSorterColumn(SorterColumn): + """Menus table sorter column""" + + permission = MANAGE_TEMPLATE_PERMISSION + + +@adapter_config(name='show-hide', context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), + provides=IColumn) +class MenusTableShowHideColumn(VisibilitySwitcherColumn): + """Menus table visibility switcher column""" + + permission = MANAGE_TEMPLATE_PERMISSION + + +@adapter_config(name='name', context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), provides=IColumn) +class MenusTableNameColumn(I18nColumn, I18nAttrColumn): + """Menus table name column""" + + _header = _("Label") + attrName = 'title' + weight = 10 + + def renderCell(self, item): + return render('templates/menu-name-cell.pt', {'context': item}, request=self.request) + + +@adapter_config(name='trash', context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), provides=IColumn) +class MenusTableTrashColumn(TrashColumn): + """Menus table trash column""" + + permission = MANAGE_TEMPLATE_PERMISSION + + +@implementer(IMenusView) +class MenusView(InnerTableView): + """Menus view""" + + table_class = MenusTable + + @property + def actions_context(self): # define context for internal actions + return self.request.registry.getAdapter(self.context, IMenusContainer, + name=self.table.associations_name) + + +# +# Menus container views +# + +@view_config(name='set-menus-order.json', context=IMenusContainer, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +def set_menus_order(request): + """Update menus order""" + order = list(map(str, json.loads(request.params.get('names')))) + request.context.updateOrder(order) + return {'status': 'success'} + + +@view_config(name='switch-menu-visibility.json', context=IMenusContainer, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +def set_menu_visibility(request): + """Set menu visibility""" + return switch_element_visibility(request, IMenusContainer) + + +@view_config(name='delete-element.json', context=IMenusContainer, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +def delete_menu(request): + """Delete menu""" + return delete_container_element(request, ignore_permission=True) + + +@view_config(name='get-menu-items.json', context=IMenusContainer, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +def get_menu_items_table(request): + """Get menu items table""" + menu = request.context.get(str(request.params.get('object_name'))) + if menu is None: + raise NotFound() + table = MenuLinksTable(menu, request) + table.update() + return table.render() + + +# +# Menu links table +# + +class LinksTable(AssociationsTable): + """Links base table class""" + + associations_name = None + + @reify + def id(self): + if IMenu.providedBy(self.context): + context = self.context + else: + context = self.request.registry.getAdapter(self.context, IMenuLinksContainer, + name=self.associations_name) + return get_table_id(self, context) + + @property + def prefix(self): + return '{0}_links'.format(self.associations_name) + + permission = MANAGE_TEMPLATE_PERMISSION + hide_header = True + hide_body_toolbar = True + + +class MenuLinksTable(LinksTable): + """Menu links associations table""" + + prefix = 'menu_links' + associations_name = '' + + @property + def data_attributes(self): + attributes = super(LinksTable, self).data_attributes + attributes.setdefault('table', {}).update({ + 'data-ams-location': absolute_url(self.context, self.request), + }) + attributes.setdefault('tr', {}).update({'data-ams-stop-propagation': 'true'}) + return attributes + + +@adapter_config(name='name', context=(IMenu, IPyAMSLayer, MenuLinksTable), provides=IColumn) +class MenuLinksTableNameColumn(AssociationsTablePublicNameColumn): + """Menu links table name column""" + + def renderHeadCell(self): + result = super(MenuLinksTableNameColumn, self).renderHeadCell() + registry = self.request.registry + viewlet = registry.queryMultiAdapter((self.context, self.request, self.table), IViewletManager, + name='pyams.widget_title') + if viewlet is not None: + viewlet.update() + result += viewlet.render() + return result + + +@adapter_config(context=(IMenu, IPyAMSLayer), provides=IMenuLinksView) +@implementer(IMenuLinksView) +class MenuLinksView(InnerTableView): + """Links base view""" + + table_class = MenuLinksTable + + @property + def actions_context(self): # define context for internal actions + return self.request.registry.getAdapter(self.context, IMenuLinksContainer, + name=self.table.associations_name) + + +# +# Menu links container views +# + +@view_config(name='set-associations-order.json', context=IMenuLinksContainer, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +def set_associations_order(request): + """Update associations order""" + order = list(map(str, json.loads(request.params.get('names')))) + request.context.updateOrder(order) + return {'status': 'success'} + + +@view_config(name='switch-association-visibility.json', context=IMenuLinksContainer, request_type=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION, renderer='json', xhr=True) +def set_association_visibility(request): + """Set association visibility""" + return switch_element_visibility(request, IMenuLinksContainer) + + +# +# Link add and edit forms +# + +@adapter_config(context=IMenuLink, provides=IFormContextPermissionChecker) +class MenuLinkPermissionChecker(ContextAdapter): + """Menu link permission checker""" + + edit_permission = MANAGE_TEMPLATE_PERMISSION + + +class LinkAJAXAddForm(AJAXAddForm): + """Menu link add form, JSON renderer""" + + def get_ajax_output(self, changes): + registry = self.request.registry + container = get_parent(self.context, IMenuLinksContainer) + view = registry.queryMultiAdapter((container, self.request), IMenuLinksView, + name=container.__name__) + if view is None: + view = registry.getMultiAdapter((container, self.request), IMenuLinksView) + return { + 'status': 'success', + 'message': self.request.localizer.translate(_("Link was correctly added.")), + 'events': [ + get_json_switched_table_refresh_event(self.context, self.request, view.table_class) + ] + } + + +class LinkPropertiesAJAXEditForm(AJAXEditForm): + """Menu link properties edit form, JSON renderer""" + + def get_ajax_output(self, changes): + output = AJAXEditForm.get_ajax_output(self, changes) + if changes: + registry = self.request.registry + container = get_parent(self.context, IMenuLinksContainer) + view = registry.queryMultiAdapter((container, self.request), IMenuLinksView, + name=container.__name__) + if view is None: + view = registry.getMultiAdapter((container, self.request), IMenuLinksView) + output.setdefault('events', []).append( + get_json_table_row_refresh_event(container, self.request, view.table_class, self.context)) + return output + + +# +# Internal links +# + +@viewlet_config(name='add-internal-link.menu', context=IMenuLinksContainerTarget, layer=IPyAMSLayer, + view=IMenuLinksView, manager=IToolbarAddingMenu, weight=50) +@viewlet_config(name='add-internal-link.menu', context=IMenu, layer=IPyAMSLayer, + view=MenuLinksTable, manager=IToolbarAddingMenu, permission=MANAGE_TEMPLATE_PERMISSION, weight=50) +class MenuInternalLinkAddMenu(InternalLinkAddMenu): + """Header internal link add menu""" + + +@pagelet_config(name='add-internal-link.html', context=IMenuLinksContainer, layer=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION) +@ajax_config(name='add-internal-link.json', context=IMenuLinksContainer, layer=IPyAMSLayer, + base=LinkAJAXAddForm) +class MenuInternalLinkAddForm(InternalLinkAddForm): + """Menu internal link add form""" + + edit_permission = MANAGE_TEMPLATE_PERMISSION + + def create(self, data): + result = super(MenuInternalLinkAddForm, self).create(data) + alsoProvides(result, IMenuInternalLink) + return result + + def add(self, object): + self.context.append(object) + + +@pagelet_config(name='properties.html', context=IMenuInternalLink, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +@ajax_config(name='properties.json', context=IMenuInternalLink, layer=IPyAMSLayer, + base=LinkPropertiesAJAXEditForm) +class MenuInternalLinkPropertiesEditForm(InternalLinkPropertiesEditForm): + """Menu internal link properties edit form""" + + edit_permission = None # managed by IFormContextPermissionChecker adapter + + +# +# External links +# + +@viewlet_config(name='add-external-link.menu', context=IMenuLinksContainerTarget, view=IMenuLinksView, + layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=51) +@viewlet_config(name='add-external-link.menu', context=IMenu, layer=IPyAMSLayer, + view=MenuLinksTable, manager=IToolbarAddingMenu, permission=MANAGE_TEMPLATE_PERMISSION, weight=51) +class MenuExternalLinkAddMenu(ExternalLinkAddMenu): + """Menu external link add menu""" + + +@pagelet_config(name='add-external-link.html', context=IMenuLinksContainer, layer=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION) +@ajax_config(name='add-external-link.json', context=IMenuLinksContainer, layer=IPyAMSLayer, + base=LinkAJAXAddForm) +class MenuExternalLinkAddForm(ExternalLinkAddForm): + """Menu external link add form""" + + edit_permission = MANAGE_TEMPLATE_PERMISSION + + def create(self, data): + result = super(MenuExternalLinkAddForm, self).create(data) + alsoProvides(result, IMenuExternalLink) + return result + + def add(self, object): + self.context.append(object) + + +@pagelet_config(name='properties.html', context=IMenuExternalLink, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +@ajax_config(name='properties.json', context=IMenuExternalLink, layer=IPyAMSLayer, + base=LinkPropertiesAJAXEditForm) +class MenuExternalLinkPropertiesEditForm(ExternalLinkPropertiesEditForm): + """Menu external link properties edit form""" + + edit_permission = None # managed by IFormContextPermissionChecker adapter diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,13 @@ + + + + + +    title + + diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/preview/zmi/templates/preview.pt --- a/src/pyams_content/features/preview/zmi/templates/preview.pt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/preview/zmi/templates/preview.pt Wed Jun 27 16:42:01 2018 +0200 @@ -14,7 +14,7 @@ @@ -36,7 +36,7 @@ tal:attributes="class string:small ${active}"> + tal:attributes="href string:#preview-${lang}"> diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/renderer/__init__.py --- a/src/pyams_content/features/renderer/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/renderer/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -43,7 +43,11 @@ """Get rendering adapter based on selected renderer name""" if request is None: request = check_request() - return request.registry.queryMultiAdapter((self, request), self.renderer_interface, name=self.renderer or '') + renderer = request.registry.queryMultiAdapter((self, request), self.renderer_interface, + name=self.renderer or '') + if 'lang' in request.params: + renderer.language = request.params['lang'] + return renderer @adapter_config(context=IRenderedContent, provides=IContentRenderer) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/renderer/interfaces/__init__.py --- a/src/pyams_content/features/renderer/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/renderer/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -41,6 +41,11 @@ label = Attribute("Renderer label") weight = Attribute("Renderer weight") settings_interface = Attribute("Renderer target interface") + language = Attribute("Renderer language (if forced)") + + +class ISharedContentRenderer(IContentRenderer): + """Shared content renderer interface""" class IRendererSettings(Interface): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/renderer/skin/__init__.py --- a/src/pyams_content/features/renderer/skin/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/renderer/skin/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -55,7 +55,7 @@ i18n = II18n(self.context, None) if i18n is not None: for attr in self.i18n_context_attrs: - setattr(self, attr, i18n.get_attribute(attr, lang=self.language, request=self.request)) + setattr(self, attr, i18n.query_attribute(attr, lang=self.language, request=self.request)) render = get_view_template() diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/renderer/zmi/__init__.py --- a/src/pyams_content/features/renderer/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/renderer/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -47,7 +47,6 @@ def update(self): renderer = self.renderer if renderer is not None: - renderer.language = self.language renderer.update() def render(self): @@ -57,10 +56,9 @@ # -# Base content renderer +# Base content renderer edit form # - @pagelet_config(name='renderer-properties.html', context=IRenderedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='renderer-properties.json', context=IRenderedContent, layer=IPyAMSLayer) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/features/review/__init__.py --- a/src/pyams_content/features/review/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/features/review/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -22,7 +22,6 @@ from pyams_content.interfaces import READER_ROLE from pyams_content.features.review.interfaces import IReviewManager, IReviewComment, IReviewComments, \ REVIEW_COMMENTS_ANNOTATION_KEY, CommentAddedEvent, ICommentAddedEvent, IReviewTarget -from pyams_content.shared.common.interfaces import IWfSharedContentRoles from pyams_i18n.interfaces import II18n from pyams_mail.interfaces import IPrincipalMailInfo from pyams_security.interfaces import ISecurityManager, IProtectedObject @@ -124,6 +123,8 @@ def ask_review(self, reviewers, comment, notify_all=True): """Ask for content review""" + from pyams_content.shared.common.interfaces import IWfSharedContentRoles + roles = IWfSharedContentRoles(self.context, None) if roles is None: return diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/generations/__init__.py --- a/src/pyams_content/generations/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/generations/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,7 +19,9 @@ # import interfaces from pyams_catalog.interfaces import MINUTE_RESOLUTION, DATE_RESOLUTION -from pyams_content.interfaces import IBaseContent +from pyams_content.component.theme import IThemesInfo +from pyams_content.interfaces import IBaseContent, WEBMASTER_ROLE, OWNER_ROLE, PILOT_ROLE, MANAGER_ROLE, \ + CONTRIBUTOR_ROLE from pyams_content.root.interfaces import ISiteRootToolsConfiguration from pyams_content.shared.common.interfaces import IWfSharedContent from pyams_content.shared.form.interfaces import IFormsManagerFactory @@ -42,6 +44,7 @@ from pyams_content.shared.common.manager import SharedToolContainer from pyams_i18n.index import I18nTextIndexWithInterface from pyams_security.index import PrincipalsRoleIndex +from pyams_thesaurus.index import ThesaurusTermsListFieldIndex from pyams_utils.registry import utility_config, get_global_registry from pyams_utils.site import check_required_utilities from pyramid.path import DottedNameResolver @@ -53,9 +56,26 @@ RENAMED_CLASSES = { - 'pyams_content.shared.common.review ReviewComment': 'pyams_content.features.review ReviewComment', + 'pyams_content.shared.common.review ReviewComment': + 'pyams_content.features.review ReviewComment', 'pyams_content.shared.common.review ReviewCommentsContainer': - 'pyams_content.features.review ReviewCommentsContainer' + 'pyams_content.features.review ReviewCommentsContainer', + 'pyams_portal.portlets.content ContentPortletSettings': + 'pyams_content.portlet.content SharedContentPortletSettings', + 'pyams_content.component.association.menu MenusContainer': + 'pyams_content.features.menu MenusContainer', + 'pyams_content.component.association.menu Menu': + 'pyams_content.features.menu Menu', + 'pyams_content.component.paragraph.keynumber KeyNumber': + 'pyams_content.component.keynumber KeyNumber', + 'pyams_content.component.paragraph.keynumber KeyNumberContainer': + 'pyams_content.component.keynumber KeyNumberContainer', + 'pyams_content.portlet.content SharedContentPortletSettings': + 'pyams_content.shared.common.portlet.content SharedContentPortletSettings', + 'pyams_content.portlet.navigation SimpleNavigationPortletSettings': + 'pyams_content.features.menu.portlet.navigation.simple SimpleNavigationPortletSettings', + 'pyams_content.portlet.navigation.interfaces ISimpleNavigationMenu': + 'pyams_content.features.menu.portlet.navigation.interfaces.simple ISimpleNavigationMenu' } @@ -76,11 +96,11 @@ REQUIRED_INDEXES = [ ('content_type', FieldIndexWithInterface, {'interface': IBaseContent, 'discriminator': 'content_type'}), - ('role:owner', PrincipalsRoleIndex, {'role_id': 'pyams.Owner'}), - ('role:pilot', PrincipalsRoleIndex, {'role_id': 'pyams.Pilot'}), - ('role:manager', PrincipalsRoleIndex, {'role_id': 'pyams.Manager'}), - ('role:contributor', PrincipalsRoleIndex, {'role_id': 'pyams.Contributor'}), - ('role:webmaster', PrincipalsRoleIndex, {'role_id': 'pyams.Webmaster'}), + ('role:owner', PrincipalsRoleIndex, {'role_id': OWNER_ROLE}), + ('role:pilot', PrincipalsRoleIndex, {'role_id': PILOT_ROLE}), + ('role:manager', PrincipalsRoleIndex, {'role_id': MANAGER_ROLE}), + ('role:contributor', PrincipalsRoleIndex, {'role_id': CONTRIBUTOR_ROLE}), + ('role:webmaster', PrincipalsRoleIndex, {'role_id': WEBMASTER_ROLE}), ('parents', KeywordIndexWithInterface, {'interface': IPathElements, 'discriminator': 'parents'}), ('workflow_state', FieldIndexWithInterface, {'interface': IWorkflowState, @@ -109,7 +129,19 @@ 'resolution': MINUTE_RESOLUTION}), ('first_publication_date', DatetimeIndexWithInterface, {'interface': IWorkflowPublicationInfo, 'discriminator': 'first_publication_date', - 'resolution': MINUTE_RESOLUTION}) + 'resolution': MINUTE_RESOLUTION}), + ('themes', ThesaurusTermsListFieldIndex, {'interface': IThemesInfo, + 'discriminator': 'themes', + 'include_parents': False, + 'include_synonyms': False}), + ('themes_tree', ThesaurusTermsListFieldIndex, {'interface': IThemesInfo, + 'discriminator': 'themes', + 'include_parents': True, + 'include_synonyms': False}), + ('themes_all', ThesaurusTermsListFieldIndex, {'interface': IThemesInfo, + 'discriminator': 'themes', + 'include_parents': True, + 'include_synonyms': True}) ] diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/interfaces/__init__.py --- a/src/pyams_content/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -93,7 +93,9 @@ """Base content interface""" __name__ = TextLine(title=_("Unique key"), - description=_("WARNING: this key can't be modified after creation!!!"), + description=_("WARNING: this key can't be modified after creation!!! Spaces, " + "uppercase letters ou accentuated characters will be replaced " + "automatically."), required=True) title = I18nTextLineField(title=_("Title"), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.mo Binary file src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.mo has changed diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po --- a/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po Wed Jun 27 16:42:01 2018 +0200 @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE 1.0\n" -"POT-Creation-Date: 2018-06-06 13:20+0200\n" +"POT-Creation-Date: 2018-06-26 14:52+0200\n" "PO-Revision-Date: 2015-09-10 10:42+0200\n" "Last-Translator: Thierry Florac \n" "Language-Team: French\n" @@ -48,31 +48,31 @@ msgid "Webmaster (role)" msgstr "Webmestre (rôle)" -#: src/pyams_content/__init__.py:62 +#: src/pyams_content/__init__.py:64 msgid "Pilot (role)" msgstr "Pilote (rôle)" -#: src/pyams_content/__init__.py:70 +#: src/pyams_content/__init__.py:74 msgid "Manager (role)" msgstr "Responsable (rôle)" -#: src/pyams_content/__init__.py:77 +#: src/pyams_content/__init__.py:83 msgid "Owner (role)" msgstr "Propriétaire (rôle)" -#: src/pyams_content/__init__.py:82 +#: src/pyams_content/__init__.py:88 msgid "Contributor (role)" msgstr "Contributeur (rôle)" -#: src/pyams_content/__init__.py:90 +#: src/pyams_content/__init__.py:99 msgid "Reader (role)" msgstr "Relecteur (rôle)" -#: src/pyams_content/__init__.py:96 +#: src/pyams_content/__init__.py:109 msgid "Operator (role)" msgstr "Opérateur (rôle)" -#: src/pyams_content/__init__.py:100 +#: src/pyams_content/__init__.py:114 msgid "Guest user (role)" msgstr "Invité (rôle)" @@ -80,25 +80,25 @@ msgid "Gallery" msgstr "Galerie de médias" -#: src/pyams_content/component/gallery/zmi/file.py:58 +#: src/pyams_content/component/gallery/zmi/file.py:57 #: src/pyams_content/component/gallery/zmi/file.py:69 -#: src/pyams_content/component/gallery/zmi/paragraph.py:174 +#: src/pyams_content/component/gallery/zmi/paragraph.py:164 msgid "Add media(s)" msgstr "Ajouter des médias" -#: src/pyams_content/component/gallery/zmi/file.py:189 +#: src/pyams_content/component/gallery/zmi/file.py:184 msgid "Update media properties" msgstr "Propriétés du média" -#: src/pyams_content/component/gallery/zmi/file.py:249 +#: src/pyams_content/component/gallery/zmi/file.py:238 msgid "Remove media..." msgstr "Supprimer le média" -#: src/pyams_content/component/gallery/zmi/file.py:154 +#: src/pyams_content/component/gallery/zmi/file.py:148 msgid "Show/hide media" msgstr "Cliquez pour rendre le média visible ou non" -#: src/pyams_content/component/gallery/zmi/file.py:216 +#: src/pyams_content/component/gallery/zmi/file.py:211 msgid "Audio content" msgstr "Contenu audio associé" @@ -106,25 +106,25 @@ msgid "Medias gallery..." msgstr "Galerie de médias" -#: src/pyams_content/component/gallery/zmi/paragraph.py:67 +#: src/pyams_content/component/gallery/zmi/paragraph.py:69 msgid "Add new gallery" msgstr "Ajout d'une galerie de médias" -#: src/pyams_content/component/gallery/zmi/paragraph.py:99 +#: src/pyams_content/component/gallery/zmi/paragraph.py:96 msgid "Edit gallery properties" msgstr "Propriétés de la galerie de médias" -#: src/pyams_content/component/gallery/zmi/__init__.py:62 +#: src/pyams_content/component/gallery/zmi/__init__.py:63 msgid "Update gallery properties" msgstr "Propriétés de la galerie de médias" -#: src/pyams_content/component/gallery/zmi/__init__.py:101 +#: src/pyams_content/component/gallery/zmi/__init__.py:95 msgid "Update gallery contents" msgstr "Contenu de la galerie de médias" #: src/pyams_content/component/gallery/zmi/interfaces.py:36 msgid "Images or videos data" -msgstr "Fichier (image ou vidéo)" +msgstr "Fichier" #: src/pyams_content/component/gallery/zmi/interfaces.py:37 msgid "You can upload a single file or choose to upload a whole ZIP archive" @@ -135,8 +135,8 @@ #: src/pyams_content/component/gallery/zmi/interfaces.py:40 #: src/pyams_content/component/gallery/interfaces/__init__.py:61 #: src/pyams_content/component/extfile/interfaces/__init__.py:44 -#: src/pyams_content/component/illustration/interfaces/__init__.py:56 -#: src/pyams_content/component/paragraph/interfaces/video.py:48 +#: src/pyams_content/component/illustration/interfaces/__init__.py:68 +#: src/pyams_content/component/paragraph/interfaces/video.py:52 #: src/pyams_content/component/paragraph/interfaces/audio.py:48 #: src/pyams_content/component/paragraph/interfaces/verbatim.py:44 #: src/pyams_content/component/video/interfaces/__init__.py:52 @@ -146,7 +146,7 @@ #: src/pyams_content/component/gallery/zmi/interfaces.py:41 #: src/pyams_content/component/gallery/interfaces/__init__.py:62 #: src/pyams_content/component/extfile/interfaces/__init__.py:45 -#: src/pyams_content/component/paragraph/interfaces/video.py:49 +#: src/pyams_content/component/paragraph/interfaces/video.py:53 #: src/pyams_content/component/paragraph/interfaces/audio.py:49 #: src/pyams_content/component/video/interfaces/__init__.py:53 msgid "Name of document's author" @@ -180,25 +180,27 @@ msgstr "Galerie de médias" #: src/pyams_content/component/gallery/interfaces/__init__.py:47 -#: src/pyams_content/component/illustration/interfaces/__init__.py:41 -#: src/pyams_content/component/illustration/interfaces/__init__.py:77 +#: src/pyams_content/component/illustration/interfaces/__init__.py:46 +#: src/pyams_content/component/illustration/interfaces/__init__.py:105 msgid "Image or video data" -msgstr "Fichier (image ou vidéo)" +msgstr "Fichier" #: src/pyams_content/component/gallery/interfaces/__init__.py:48 -#: src/pyams_content/component/illustration/interfaces/__init__.py:42 -#: src/pyams_content/component/illustration/interfaces/__init__.py:78 +#: src/pyams_content/component/illustration/interfaces/__init__.py:47 +#: src/pyams_content/component/illustration/interfaces/__init__.py:106 msgid "Image or video content" msgstr "" "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu..." #: src/pyams_content/component/gallery/interfaces/__init__.py:51 -#: src/pyams_content/component/illustration/interfaces/__init__.py:45 +#: src/pyams_content/component/illustration/interfaces/__init__.py:53 +#: src/pyams_content/component/paragraph/interfaces/video.py:45 +#: src/pyams_content/component/video/interfaces/__init__.py:75 msgid "Legend" msgstr "Légende" #: src/pyams_content/component/gallery/interfaces/__init__.py:54 -#: src/pyams_content/component/illustration/interfaces/__init__.py:48 +#: src/pyams_content/component/illustration/interfaces/__init__.py:56 #: src/pyams_content/reference/pictograms/interfaces/__init__.py:48 msgid "Accessibility title" msgstr "Alternative (accessibilité)" @@ -214,13 +216,13 @@ #: src/pyams_content/component/gallery/interfaces/__init__.py:58 #: src/pyams_content/component/gallery/interfaces/__init__.py:98 #: src/pyams_content/component/extfile/interfaces/__init__.py:40 -#: src/pyams_content/component/illustration/interfaces/__init__.py:52 -#: src/pyams_content/component/paragraph/interfaces/video.py:44 +#: 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:44 -#: src/pyams_content/component/links/interfaces/__init__.py:37 +#: 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:145 -#: src/pyams_content/shared/form/interfaces/__init__.py:65 +#: src/pyams_content/shared/common/interfaces/__init__.py:154 +#: src/pyams_content/shared/form/interfaces/__init__.py:66 msgid "Description" msgstr "Description" @@ -273,17 +275,20 @@ msgstr "Si 'non', ce média ne sera pas présenté aux internautes" #: src/pyams_content/component/gallery/interfaces/__init__.py:94 -#: src/pyams_content/component/paragraph/zmi/milestone.py:246 -#: src/pyams_content/component/paragraph/zmi/container.py:224 +#: src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:31 +#: src/pyams_content/component/paragraph/zmi/milestone.py:231 +#: src/pyams_content/component/paragraph/zmi/container.py:223 #: src/pyams_content/component/paragraph/interfaces/milestone.py:45 -#: src/pyams_content/component/links/zmi/reverse.py:71 +#: src/pyams_content/component/links/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/imagemap/zmi/container.py:123 -#: src/pyams_content/shared/site/zmi/folder.py:68 +#: src/pyams_content/shared/site/zmi/folder.py:70 #: src/pyams_content/root/zmi/templates/advanced-search.pt:188 -#: src/pyams_content/interfaces/__init__.py:99 -#: src/pyams_content/reference/pictograms/zmi/__init__.py:165 +#: 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 +#: src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:31 msgid "Title" msgstr "Titre" @@ -338,59 +343,59 @@ msgid "Add external file" msgstr "Fichier" -#: src/pyams_content/component/extfile/zmi/__init__.py:101 +#: src/pyams_content/component/extfile/zmi/__init__.py:103 msgid "Add new external file" msgstr "Ajout d'un fichier" -#: src/pyams_content/component/extfile/zmi/__init__.py:141 +#: src/pyams_content/component/extfile/zmi/__init__.py:138 msgid "Update file properties" msgstr "Propriétés du fichier" -#: src/pyams_content/component/extfile/zmi/__init__.py:181 +#: src/pyams_content/component/extfile/zmi/__init__.py:171 msgid "Images" msgstr "Images" -#: src/pyams_content/component/extfile/zmi/__init__.py:196 +#: src/pyams_content/component/extfile/zmi/__init__.py:186 msgid "Add image" msgstr "Image téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:208 +#: src/pyams_content/component/extfile/zmi/__init__.py:200 msgid "Add new image" msgstr "Ajout d'une image téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:244 +#: src/pyams_content/component/extfile/zmi/__init__.py:231 msgid "Update image properties" msgstr "Propriétés de l'image téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:283 +#: src/pyams_content/component/extfile/zmi/__init__.py:264 msgid "Videos" msgstr "Vidéos" -#: src/pyams_content/component/extfile/zmi/__init__.py:298 +#: src/pyams_content/component/extfile/zmi/__init__.py:279 msgid "Add video" msgstr "Vidéo téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:310 +#: src/pyams_content/component/extfile/zmi/__init__.py:293 msgid "Add new video" msgstr "Ajout d'une vidéo téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:339 +#: src/pyams_content/component/extfile/zmi/__init__.py:317 msgid "Update video properties" msgstr "Propriétés de la vidéo téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:371 +#: src/pyams_content/component/extfile/zmi/__init__.py:343 msgid "Audios files" msgstr "Fichiers audios" -#: src/pyams_content/component/extfile/zmi/__init__.py:386 +#: src/pyams_content/component/extfile/zmi/__init__.py:358 msgid "Add audio file" msgstr "Bande son téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:398 +#: src/pyams_content/component/extfile/zmi/__init__.py:372 msgid "Add new audio file" msgstr "Ajout d'une bande son téléchargeable" -#: src/pyams_content/component/extfile/zmi/__init__.py:427 +#: src/pyams_content/component/extfile/zmi/__init__.py:396 msgid "Update audio file properties" msgstr "Propriétés de la bande son téléchargeable" @@ -399,7 +404,7 @@ msgstr "Type de fichier joint" #: src/pyams_content/component/extfile/interfaces/__init__.py:36 -#: src/pyams_content/component/links/interfaces/__init__.py:33 +#: src/pyams_content/component/links/interfaces/__init__.py:35 #: src/pyams_content/shared/imagemap/interfaces/__init__.py:54 #: src/pyams_content/shared/site/interfaces/__init__.py:113 msgid "Alternate title" @@ -410,14 +415,14 @@ msgstr "Titre présenté aux internautes" #: src/pyams_content/component/extfile/interfaces/__init__.py:41 -#: src/pyams_content/component/paragraph/interfaces/video.py:45 +#: src/pyams_content/component/paragraph/interfaces/video.py:49 #: src/pyams_content/component/paragraph/interfaces/audio.py:45 #: 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" #: src/pyams_content/component/extfile/interfaces/__init__.py:48 -#: src/pyams_content/component/links/interfaces/__init__.py:59 +#: src/pyams_content/component/links/interfaces/__init__.py:68 msgid "Language" msgstr "Langue" @@ -456,7 +461,7 @@ "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu..." #: src/pyams_content/component/extfile/interfaces/__init__.py:81 -#: src/pyams_content/component/paragraph/interfaces/video.py:52 +#: src/pyams_content/component/paragraph/interfaces/video.py:41 msgid "Video data" msgstr "Fichier" @@ -471,30 +476,145 @@ msgstr "" "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu" -#: src/pyams_content/component/illustration/__init__.py:132 -#: src/pyams_content/component/illustration/zmi/__init__.py:54 -#: src/pyams_content/component/illustration/zmi/__init__.py:81 -#: src/pyams_content/component/illustration/interfaces/__init__.py:71 +#: src/pyams_content/component/keynumber/__init__.py:189 +#: src/pyams_content/component/keynumber/zmi/__init__.py:198 +#: src/pyams_content/component/keynumber/portlet/zmi/__init__.py:79 +#: src/pyams_content/component/paragraph/interfaces/keynumber.py:29 +msgid "Key numbers" +msgstr "Chiffres-clés" + +#. Default: Header +#: src/pyams_content/component/keynumber/zmi/__init__.py:146 +#: src/pyams_content/component/keynumber/interfaces/__init__.py:44 +msgid "key-number-label" +msgstr "En-tête" + +#: src/pyams_content/component/keynumber/zmi/__init__.py:158 +#: src/pyams_content/component/keynumber/interfaces/__init__.py:49 +msgid "Number" +msgstr "Chiffre" + +#. Default: Unit +#: src/pyams_content/component/keynumber/zmi/__init__.py:167 +#: src/pyams_content/component/keynumber/interfaces/__init__.py:53 +msgid "key-number-unit" +msgstr "Unité" + +#: src/pyams_content/component/keynumber/zmi/__init__.py:179 +#: src/pyams_content/component/keynumber/interfaces/__init__.py:57 +#: src/pyams_content/component/paragraph/zmi/pictogram.py:267 +#: src/pyams_content/component/paragraph/interfaces/pictogram.py:58 +msgid "Associated text" +msgstr "Texte associé" + +#: src/pyams_content/component/keynumber/zmi/__init__.py:217 +msgid "Add keynumber" +msgstr "Ajouter un chiffre-clé" + +#: src/pyams_content/component/keynumber/zmi/__init__.py:229 +msgid "Add new keynumber" +msgstr "Ajout d'un chiffre-clé" + +#: src/pyams_content/component/keynumber/zmi/__init__.py:258 +msgid "Edit keynumber properties" +msgstr "Propriétés du chiffre-clé" + +#: src/pyams_content/component/keynumber/zmi/__init__.py:244 +msgid "Key number was correctly added" +msgstr "Le chiffre-clé a été ajouté." + +#: src/pyams_content/component/keynumber/portlet/__init__.py:71 +msgid "Key Numbers" +msgstr "Chiffres-clés" + +#: src/pyams_content/component/keynumber/portlet/zmi/__init__.py:102 +#: src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt:22 +msgid "Associated links" +msgstr "Liens associés" + +#: src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt:27 +#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:12 +#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:9 +msgid "Link target is not published!" +msgstr "Le contenu ciblé n'est pas publié" + +#: src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:32 +msgid "Portlet title" +msgstr "Titre" + +#: src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:35 +msgid "Teaser" +msgstr "Accroche" + +#: src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:36 +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/paragraph/interfaces/milestone.py:40 +#: src/pyams_content/component/paragraph/interfaces/__init__.py:44 +#: src/pyams_content/component/paragraph/interfaces/pictogram.py:41 +#: src/pyams_content/component/association/interfaces/__init__.py:42 +#: src/pyams_content/shared/form/interfaces/__init__.py:87 +#: src/pyams_content/shared/site/interfaces/__init__.py:117 +#: src/pyams_content/features/alert/interfaces.py:54 +#: src/pyams_content/features/menu/interfaces/__init__.py:58 +msgid "Visible?" +msgstr "Visible ?" + +#: src/pyams_content/component/keynumber/interfaces/__init__.py:40 +msgid "Is this key number visible in front-office?" +msgstr "Si 'non', ce chiffre-clé ne sera pas présenté aux internautes" + +#: src/pyams_content/component/keynumber/interfaces/__init__.py:45 +msgid "" +"Small text to be displayed above number (according to selected renderer)" +msgstr "" +"Texte court affiché au-dessus du chiffre (selon le mode de rendu sélectionné)" + +#: src/pyams_content/component/keynumber/interfaces/__init__.py:50 +msgid "Key number value" +msgstr "Chiffre" + +#: src/pyams_content/component/keynumber/interfaces/__init__.py:54 +msgid "Displayed unit" +msgstr "Unité affichée" + +#: src/pyams_content/component/keynumber/interfaces/__init__.py:58 +msgid "The way this text will be rendered depends on presentation template" +msgstr "" +"La présentation de cette information peut varier en fonction du mode de " +"rendu choisi" + +#: src/pyams_content/component/illustration/__init__.py:177 +#: src/pyams_content/component/illustration/zmi/paragraph.py:168 +#: src/pyams_content/component/illustration/zmi/__init__.py:56 +#: src/pyams_content/component/illustration/zmi/__init__.py:100 +#: src/pyams_content/component/illustration/interfaces/__init__.py:99 msgid "Illustration" msgstr "Illustration" -#: src/pyams_content/component/illustration/zmi/paragraph.py:57 +#: src/pyams_content/component/illustration/zmi/paragraph.py:60 msgid "Illustration..." msgstr "Illustration" -#: src/pyams_content/component/illustration/zmi/paragraph.py:68 +#: src/pyams_content/component/illustration/zmi/paragraph.py:73 msgid "Add new illustration" msgstr "Ajout d'une illustration" -#: src/pyams_content/component/illustration/zmi/paragraph.py:102 +#: src/pyams_content/component/illustration/zmi/paragraph.py:103 msgid "Edit illustration properties" msgstr "Propriétés de l'illustration" -#: src/pyams_content/component/illustration/zmi/__init__.py:83 +#: src/pyams_content/component/illustration/zmi/__init__.py:155 +msgid "Navigation link illustration" +msgstr "Illustration de navigation" + +#: src/pyams_content/component/illustration/zmi/__init__.py:102 msgid "Header illustration" msgstr "Illustration d'en-tête" -#: src/pyams_content/component/illustration/interfaces/__init__.py:49 +#: src/pyams_content/component/illustration/interfaces/__init__.py:57 #: src/pyams_content/reference/pictograms/interfaces/__init__.py:49 msgid "Alternate title used to describe image content" msgstr "" @@ -503,15 +623,15 @@ "déficiences visuelles. Il doit donc décrire le contenu, pour se conformer " "aux normes d'accessibilité." -#: src/pyams_content/component/illustration/interfaces/__init__.py:57 +#: src/pyams_content/component/illustration/interfaces/__init__.py:69 msgid "Name of picture's author" msgstr "Sous la forme \"Prénom Nom / Organisme\"" -#: src/pyams_content/component/illustration/interfaces/__init__.py:60 +#: src/pyams_content/component/illustration/interfaces/__init__.py:72 msgid "Illustration template" msgstr "Mode de rendu" -#: src/pyams_content/component/illustration/interfaces/__init__.py:61 +#: src/pyams_content/component/illustration/interfaces/__init__.py:73 msgid "Presentation template used for illustration" msgstr "" "Modèle de présentation utilisé par cette illustration.
\n" @@ -49,31 +49,31 @@ msgid "Webmaster (role)" msgstr "" -#: ./src/pyams_content/__init__.py:62 +#: ./src/pyams_content/__init__.py:64 msgid "Pilot (role)" msgstr "" -#: ./src/pyams_content/__init__.py:70 +#: ./src/pyams_content/__init__.py:74 msgid "Manager (role)" msgstr "" -#: ./src/pyams_content/__init__.py:77 +#: ./src/pyams_content/__init__.py:83 msgid "Owner (role)" msgstr "" -#: ./src/pyams_content/__init__.py:82 +#: ./src/pyams_content/__init__.py:88 msgid "Contributor (role)" msgstr "" -#: ./src/pyams_content/__init__.py:90 +#: ./src/pyams_content/__init__.py:99 msgid "Reader (role)" msgstr "" -#: ./src/pyams_content/__init__.py:96 +#: ./src/pyams_content/__init__.py:109 msgid "Operator (role)" msgstr "" -#: ./src/pyams_content/__init__.py:100 +#: ./src/pyams_content/__init__.py:114 msgid "Guest user (role)" msgstr "" @@ -81,25 +81,25 @@ msgid "Gallery" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/file.py:58 +#: ./src/pyams_content/component/gallery/zmi/file.py:57 #: ./src/pyams_content/component/gallery/zmi/file.py:69 -#: ./src/pyams_content/component/gallery/zmi/paragraph.py:174 +#: ./src/pyams_content/component/gallery/zmi/paragraph.py:164 msgid "Add media(s)" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/file.py:189 +#: ./src/pyams_content/component/gallery/zmi/file.py:184 msgid "Update media properties" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/file.py:249 +#: ./src/pyams_content/component/gallery/zmi/file.py:238 msgid "Remove media..." msgstr "" -#: ./src/pyams_content/component/gallery/zmi/file.py:154 +#: ./src/pyams_content/component/gallery/zmi/file.py:148 msgid "Show/hide media" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/file.py:216 +#: ./src/pyams_content/component/gallery/zmi/file.py:211 msgid "Audio content" msgstr "" @@ -107,19 +107,19 @@ msgid "Medias gallery..." msgstr "" -#: ./src/pyams_content/component/gallery/zmi/paragraph.py:67 +#: ./src/pyams_content/component/gallery/zmi/paragraph.py:69 msgid "Add new gallery" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/paragraph.py:99 +#: ./src/pyams_content/component/gallery/zmi/paragraph.py:96 msgid "Edit gallery properties" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/__init__.py:62 +#: ./src/pyams_content/component/gallery/zmi/__init__.py:63 msgid "Update gallery properties" msgstr "" -#: ./src/pyams_content/component/gallery/zmi/__init__.py:101 +#: ./src/pyams_content/component/gallery/zmi/__init__.py:95 msgid "Update gallery contents" msgstr "" @@ -134,8 +134,8 @@ #: ./src/pyams_content/component/gallery/zmi/interfaces.py:40 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:61 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:44 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:56 -#: ./src/pyams_content/component/paragraph/interfaces/video.py:48 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:68 +#: ./src/pyams_content/component/paragraph/interfaces/video.py:52 #: ./src/pyams_content/component/paragraph/interfaces/audio.py:48 #: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:44 #: ./src/pyams_content/component/video/interfaces/__init__.py:52 @@ -145,7 +145,7 @@ #: ./src/pyams_content/component/gallery/zmi/interfaces.py:41 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:62 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:45 -#: ./src/pyams_content/component/paragraph/interfaces/video.py:49 +#: ./src/pyams_content/component/paragraph/interfaces/video.py:53 #: ./src/pyams_content/component/paragraph/interfaces/audio.py:49 #: ./src/pyams_content/component/video/interfaces/__init__.py:53 msgid "Name of document's author" @@ -177,24 +177,26 @@ msgstr "" #: ./src/pyams_content/component/gallery/interfaces/__init__.py:47 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:41 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:77 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:46 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:105 msgid "Image or video data" msgstr "" #: ./src/pyams_content/component/gallery/interfaces/__init__.py:48 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:42 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:78 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:47 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:106 msgid "Image or video content" msgstr "" #: ./src/pyams_content/component/gallery/interfaces/__init__.py:51 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:45 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:53 +#: ./src/pyams_content/component/paragraph/interfaces/video.py:45 +#: ./src/pyams_content/component/video/interfaces/__init__.py:75 msgid "Legend" msgstr "" #: ./src/pyams_content/component/gallery/interfaces/__init__.py:54 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:48 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:56 #: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:48 msgid "Accessibility title" msgstr "" @@ -206,13 +208,13 @@ #: ./src/pyams_content/component/gallery/interfaces/__init__.py:58 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:98 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:40 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:52 -#: ./src/pyams_content/component/paragraph/interfaces/video.py:44 +#: ./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:44 -#: ./src/pyams_content/component/links/interfaces/__init__.py:37 +#: ./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:145 -#: ./src/pyams_content/shared/form/interfaces/__init__.py:65 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:154 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:66 msgid "Description" msgstr "" @@ -263,17 +265,20 @@ msgstr "" #: ./src/pyams_content/component/gallery/interfaces/__init__.py:94 -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:246 -#: ./src/pyams_content/component/paragraph/zmi/container.py:224 +#: ./src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:31 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:231 +#: ./src/pyams_content/component/paragraph/zmi/container.py:223 #: ./src/pyams_content/component/paragraph/interfaces/milestone.py:45 -#: ./src/pyams_content/component/links/zmi/reverse.py:71 +#: ./src/pyams_content/component/links/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/imagemap/zmi/container.py:123 -#: ./src/pyams_content/shared/site/zmi/folder.py:68 +#: ./src/pyams_content/shared/site/zmi/folder.py:70 #: ./src/pyams_content/root/zmi/templates/advanced-search.pt:188 -#: ./src/pyams_content/interfaces/__init__.py:99 -#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:165 +#: ./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 +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:31 msgid "Title" msgstr "" @@ -325,59 +330,59 @@ msgid "Add external file" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:101 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:103 msgid "Add new external file" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:141 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:138 msgid "Update file properties" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:181 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:171 msgid "Images" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:196 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:186 msgid "Add image" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:208 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:200 msgid "Add new image" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:244 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:231 msgid "Update image properties" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:283 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:264 msgid "Videos" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:298 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:279 msgid "Add video" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:310 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:293 msgid "Add new video" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:339 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:317 msgid "Update video properties" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:371 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:343 msgid "Audios files" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:386 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:358 msgid "Add audio file" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:398 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:372 msgid "Add new audio file" msgstr "" -#: ./src/pyams_content/component/extfile/zmi/__init__.py:427 +#: ./src/pyams_content/component/extfile/zmi/__init__.py:396 msgid "Update audio file properties" msgstr "" @@ -386,7 +391,7 @@ msgstr "" #: ./src/pyams_content/component/extfile/interfaces/__init__.py:36 -#: ./src/pyams_content/component/links/interfaces/__init__.py:33 +#: ./src/pyams_content/component/links/interfaces/__init__.py:35 #: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:54 #: ./src/pyams_content/shared/site/interfaces/__init__.py:113 msgid "Alternate title" @@ -397,14 +402,14 @@ msgstr "" #: ./src/pyams_content/component/extfile/interfaces/__init__.py:41 -#: ./src/pyams_content/component/paragraph/interfaces/video.py:45 +#: ./src/pyams_content/component/paragraph/interfaces/video.py:49 #: ./src/pyams_content/component/paragraph/interfaces/audio.py:45 #: ./src/pyams_content/component/video/interfaces/__init__.py:49 msgid "File description displayed by front-office template" msgstr "" #: ./src/pyams_content/component/extfile/interfaces/__init__.py:48 -#: ./src/pyams_content/component/links/interfaces/__init__.py:59 +#: ./src/pyams_content/component/links/interfaces/__init__.py:68 msgid "Language" msgstr "" @@ -438,7 +443,7 @@ msgstr "" #: ./src/pyams_content/component/extfile/interfaces/__init__.py:81 -#: ./src/pyams_content/component/paragraph/interfaces/video.py:52 +#: ./src/pyams_content/component/paragraph/interfaces/video.py:41 msgid "Video data" msgstr "" @@ -451,43 +456,155 @@ msgid "Audio file content" msgstr "" -#: ./src/pyams_content/component/illustration/__init__.py:132 -#: ./src/pyams_content/component/illustration/zmi/__init__.py:54 -#: ./src/pyams_content/component/illustration/zmi/__init__.py:81 -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:71 +#: ./src/pyams_content/component/keynumber/__init__.py:189 +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:198 +#: ./src/pyams_content/component/keynumber/portlet/zmi/__init__.py:79 +#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:29 +msgid "Key numbers" +msgstr "" + +#. Default: Header +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:146 +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:44 +msgid "key-number-label" +msgstr "" + +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:158 +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:49 +msgid "Number" +msgstr "" + +#. Default: Unit +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:167 +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:53 +msgid "key-number-unit" +msgstr "" + +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:179 +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:57 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:267 +#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:58 +msgid "Associated text" +msgstr "" + +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:217 +msgid "Add keynumber" +msgstr "" + +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:229 +msgid "Add new keynumber" +msgstr "" + +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:258 +msgid "Edit keynumber properties" +msgstr "" + +#: ./src/pyams_content/component/keynumber/zmi/__init__.py:244 +msgid "Key number was correctly added" +msgstr "" + +#: ./src/pyams_content/component/keynumber/portlet/__init__.py:71 +msgid "Key Numbers" +msgstr "" + +#: ./src/pyams_content/component/keynumber/portlet/zmi/__init__.py:102 +#: ./src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt:22 +msgid "Associated links" +msgstr "" + +#: ./src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt:27 +#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:12 +#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:9 +msgid "Link target is not published!" +msgstr "" + +#: ./src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:32 +msgid "Portlet title" +msgstr "" + +#: ./src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:35 +msgid "Teaser" +msgstr "" + +#: ./src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:36 +msgid "Short text displayed above key numbers" +msgstr "" + +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:39 +#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:40 +#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:44 +#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:41 +#: ./src/pyams_content/component/association/interfaces/__init__.py:42 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:87 +#: ./src/pyams_content/shared/site/interfaces/__init__.py:117 +#: ./src/pyams_content/features/alert/interfaces.py:54 +#: ./src/pyams_content/features/menu/interfaces/__init__.py:58 +msgid "Visible?" +msgstr "" + +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:40 +msgid "Is this key number visible in front-office?" +msgstr "" + +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:45 +msgid "" +"Small text to be displayed above number (according to selected renderer)" +msgstr "" + +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:50 +msgid "Key number value" +msgstr "" + +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:54 +msgid "Displayed unit" +msgstr "" + +#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:58 +msgid "The way this text will be rendered depends on presentation template" +msgstr "" + +#: ./src/pyams_content/component/illustration/__init__.py:177 +#: ./src/pyams_content/component/illustration/zmi/paragraph.py:168 +#: ./src/pyams_content/component/illustration/zmi/__init__.py:56 +#: ./src/pyams_content/component/illustration/zmi/__init__.py:100 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:99 msgid "Illustration" msgstr "" -#: ./src/pyams_content/component/illustration/zmi/paragraph.py:57 +#: ./src/pyams_content/component/illustration/zmi/paragraph.py:60 msgid "Illustration..." msgstr "" -#: ./src/pyams_content/component/illustration/zmi/paragraph.py:68 +#: ./src/pyams_content/component/illustration/zmi/paragraph.py:73 msgid "Add new illustration" msgstr "" -#: ./src/pyams_content/component/illustration/zmi/paragraph.py:102 +#: ./src/pyams_content/component/illustration/zmi/paragraph.py:103 msgid "Edit illustration properties" msgstr "" -#: ./src/pyams_content/component/illustration/zmi/__init__.py:83 +#: ./src/pyams_content/component/illustration/zmi/__init__.py:155 +msgid "Navigation link illustration" +msgstr "" + +#: ./src/pyams_content/component/illustration/zmi/__init__.py:102 msgid "Header illustration" msgstr "" -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:49 -#: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:49 -msgid "Alternate title used to describe image content" -msgstr "" - #: ./src/pyams_content/component/illustration/interfaces/__init__.py:57 +#: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:49 +msgid "Alternate title used to describe image content" +msgstr "" + +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:69 msgid "Name of picture's author" msgstr "" -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:60 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:72 msgid "Illustration template" msgstr "" -#: ./src/pyams_content/component/illustration/interfaces/__init__.py:61 +#: ./src/pyams_content/component/illustration/interfaces/__init__.py:73 msgid "Presentation template used for illustration" msgstr "" @@ -507,7 +624,7 @@ msgid "no visible paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/pictogram.py:134 +#: ./src/pyams_content/component/paragraph/pictogram.py:135 msgid "Selected pictogram is missing" msgstr "" @@ -515,62 +632,62 @@ msgid "Milestones..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:88 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:90 msgid "Add new milestone paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:120 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:117 msgid "Edit milestone paragraph properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:258 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:243 #: ./src/pyams_content/component/paragraph/interfaces/milestone.py:49 msgid "Associated label" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:270 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:255 #: ./src/pyams_content/component/paragraph/interfaces/milestone.py:53 msgid "Anchor" msgstr "" +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:284 +#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:76 +msgid "Milestones" +msgstr "" + #: ./src/pyams_content/component/paragraph/zmi/milestone.py:299 -#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:76 -msgid "Milestones" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:314 msgid "Add milestone" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:325 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:312 msgid "Add new milestone" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:358 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:339 msgid "Edit milestone properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:347 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:327 msgid "Milestone was correctly added" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/milestone.py:285 +#: ./src/pyams_content/component/paragraph/zmi/milestone.py:270 msgid "(missing paragraph)" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keypoint.py:50 +#: ./src/pyams_content/component/paragraph/zmi/keypoint.py:51 msgid "Key points..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keypoint.py:61 +#: ./src/pyams_content/component/paragraph/zmi/keypoint.py:64 msgid "Add new key points paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keypoint.py:93 +#: ./src/pyams_content/component/paragraph/zmi/keypoint.py:91 msgid "Edit key points paragraph properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/__init__.py:66 +#: ./src/pyams_content/component/paragraph/zmi/__init__.py:65 msgid "Content block types..." msgstr "" @@ -578,7 +695,7 @@ msgid "Content block types" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/__init__.py:96 +#: ./src/pyams_content/component/paragraph/zmi/__init__.py:89 msgid "" "You can define which types of paragraphs are allowed in this container.\n" "\n" @@ -587,228 +704,174 @@ "NOTICE: removing types from allowed types list will have no effect on already created contents!" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/__init__.py:214 +#: ./src/pyams_content/component/paragraph/zmi/__init__.py:207 #: ./src/pyams_content/shared/common/zmi/templates/preview-input.pt:39 #: ./src/pyams_content/features/preview/zmi/__init__.py:45 msgid "Preview" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/__init__.py:219 -#: ./src/pyams_content/shared/common/zmi/workflow.py:125 -#: ./src/pyams_content/shared/common/zmi/workflow.py:217 -#: ./src/pyams_content/shared/common/zmi/workflow.py:262 -#: ./src/pyams_content/shared/common/zmi/workflow.py:321 -#: ./src/pyams_content/shared/common/zmi/workflow.py:415 -#: ./src/pyams_content/shared/common/zmi/workflow.py:476 -#: ./src/pyams_content/shared/common/zmi/workflow.py:521 -#: ./src/pyams_content/shared/common/zmi/workflow.py:567 -#: ./src/pyams_content/shared/common/zmi/workflow.py:615 -#: ./src/pyams_content/shared/common/zmi/workflow.py:660 -#: ./src/pyams_content/shared/common/zmi/workflow.py:706 -#: ./src/pyams_content/shared/common/zmi/workflow.py:762 -#: ./src/pyams_content/shared/common/zmi/__init__.py:276 -#: ./src/pyams_content/shared/common/zmi/owner.py:74 +#: ./src/pyams_content/component/paragraph/zmi/__init__.py:212 +#: ./src/pyams_content/shared/common/zmi/workflow.py:122 +#: ./src/pyams_content/shared/common/zmi/workflow.py:209 +#: ./src/pyams_content/shared/common/zmi/workflow.py:249 +#: ./src/pyams_content/shared/common/zmi/workflow.py:303 +#: ./src/pyams_content/shared/common/zmi/workflow.py:392 +#: ./src/pyams_content/shared/common/zmi/workflow.py:448 +#: ./src/pyams_content/shared/common/zmi/workflow.py:488 +#: ./src/pyams_content/shared/common/zmi/workflow.py:529 +#: ./src/pyams_content/shared/common/zmi/workflow.py:572 +#: ./src/pyams_content/shared/common/zmi/workflow.py:612 +#: ./src/pyams_content/shared/common/zmi/workflow.py:653 +#: ./src/pyams_content/shared/common/zmi/workflow.py:704 +#: ./src/pyams_content/shared/common/zmi/__init__.py:275 +#: ./src/pyams_content/shared/common/zmi/owner.py:73 #: ./src/pyams_content/features/review/zmi/__init__.py:90 msgid "Cancel" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/__init__.py:221 +#: ./src/pyams_content/component/paragraph/zmi/__init__.py:214 msgid "Submit" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/__init__.py:202 +#: ./src/pyams_content/component/paragraph/zmi/__init__.py:195 msgid "Paragraph was correctly added." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/video.py:54 +#: ./src/pyams_content/component/paragraph/zmi/video.py:53 msgid "Video paragraph..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/video.py:65 +#: ./src/pyams_content/component/paragraph/zmi/video.py:66 msgid "Add new video paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/video.py:112 -#: ./src/pyams_content/component/video/zmi/paragraph.py:209 +#: ./src/pyams_content/component/paragraph/zmi/video.py:94 +#: ./src/pyams_content/component/video/zmi/paragraph.py:192 msgid "Edit video properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/video.py:83 -#: ./src/pyams_content/component/paragraph/zmi/video.py:133 -#: ./src/pyams_content/component/paragraph/zmi/audio.py:83 -#: ./src/pyams_content/component/paragraph/zmi/audio.py:133 -#: ./src/pyams_content/component/video/zmi/paragraph.py:103 -#: ./src/pyams_content/component/video/zmi/paragraph.py:238 -msgid "HTML content" -msgstr "" - #: ./src/pyams_content/component/paragraph/zmi/container.py:74 msgid "Contents..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:240 +#: ./src/pyams_content/component/paragraph/zmi/container.py:239 msgid "Show/hide all paragraphs" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:288 -#: ./src/pyams_content/component/paragraph/zmi/container.py:297 -#: ./src/pyams_content/component/paragraph/zmi/container.py:310 +#: ./src/pyams_content/component/paragraph/zmi/container.py:287 +#: ./src/pyams_content/component/paragraph/zmi/container.py:296 +#: ./src/pyams_content/component/paragraph/zmi/container.py:309 msgid "Content blocks" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:367 +#: ./src/pyams_content/component/paragraph/zmi/container.py:366 msgid "Links and attachments..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:379 +#: ./src/pyams_content/component/paragraph/zmi/container.py:378 msgid "Content blocks links and attachments" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:127 +#: ./src/pyams_content/component/paragraph/zmi/container.py:126 msgid "No currently defined paragraph." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:249 +#: ./src/pyams_content/component/paragraph/zmi/container.py:248 msgid "Click to open/close all paragraphs editors" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:262 +#: ./src/pyams_content/component/paragraph/zmi/container.py:261 msgid "Click to open/close paragraph editor" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/container.py:133 +#: ./src/pyams_content/component/paragraph/zmi/container.py:132 msgid "Check allowed paragraph types to be able to create new paragraphs." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:83 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:82 msgid "Pictograms..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:94 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:95 msgid "Add new pictogram paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:126 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:122 msgid "Edit pictogram paragraph properties" msgstr "" #. Default: Header -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:268 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:252 msgid "pictogram-item-header" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:283 -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:263 -#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:58 -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:54 -msgid "Associated text" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:305 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:289 #: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:80 msgid "Pictograms" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:320 -#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:62 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:304 +#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:59 msgid "Add pictogram" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:331 -#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:73 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:317 +#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:71 msgid "Add new pictogram" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:393 -#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:103 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:359 +#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:95 msgid "Edit pictogram properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:374 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:339 msgid "Pictogram was correctly added" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:384 -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:448 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:349 +#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:387 msgid "You must select a pictogram!" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:347 -#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:186 -msgid "Default header: --" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:414 -#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:190 -#, python-format -msgid "Default header: {0}" -msgstr "" - #: ./src/pyams_content/component/paragraph/zmi/audio.py:54 msgid "Audio paragraph..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/audio.py:65 +#: ./src/pyams_content/component/paragraph/zmi/audio.py:67 msgid "Add new audio paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/audio.py:112 +#: ./src/pyams_content/component/paragraph/zmi/audio.py:108 msgid "Edit audio properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:76 +#: ./src/pyams_content/component/paragraph/zmi/audio.py:84 +#: ./src/pyams_content/component/paragraph/zmi/audio.py:128 +msgid "HTML content" +msgstr "" + +#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:55 msgid "Key numbers..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:87 +#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:68 msgid "Add new key number paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:119 +#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:96 msgid "Edit key number paragraph properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:242 -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:45 -msgid "Number" -msgstr "" - -#. Default: Header -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:251 -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:49 -msgid "key-number-label" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:282 -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:76 -msgid "Key numbers" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:297 -msgid "Add keynumber" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:308 -msgid "Add new keynumber" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:341 -msgid "Edit keynumber properties" -msgstr "" - -#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:330 -msgid "Key number was correctly added" -msgstr "" - #: ./src/pyams_content/component/paragraph/zmi/frame.py:84 msgid "Framed text..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/frame.py:96 +#: ./src/pyams_content/component/paragraph/zmi/frame.py:98 msgid "Add new framed text paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/frame.py:132 +#: ./src/pyams_content/component/paragraph/zmi/frame.py:129 msgid "Edit framed text paragraph properties" msgstr "" @@ -816,11 +879,11 @@ msgid "Verbatim..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/verbatim.py:67 +#: ./src/pyams_content/component/paragraph/zmi/verbatim.py:69 msgid "Add new verbatim paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/verbatim.py:99 +#: ./src/pyams_content/component/paragraph/zmi/verbatim.py:96 msgid "Edit verbatim paragraph properties" msgstr "" @@ -828,23 +891,23 @@ msgid "Raw HTML..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/html.py:87 +#: ./src/pyams_content/component/paragraph/zmi/html.py:89 msgid "Add new raw HTML paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/html.py:122 +#: ./src/pyams_content/component/paragraph/zmi/html.py:119 msgid "Edit raw HTML paragraph properties" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/html.py:174 +#: ./src/pyams_content/component/paragraph/zmi/html.py:159 msgid "Rich text..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/html.py:185 +#: ./src/pyams_content/component/paragraph/zmi/html.py:172 msgid "Add new rich text paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/html.py:220 +#: ./src/pyams_content/component/paragraph/zmi/html.py:202 msgid "Edit rich text paragraph properties" msgstr "" @@ -852,11 +915,11 @@ msgid "Contact card..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/contact.py:64 +#: ./src/pyams_content/component/paragraph/zmi/contact.py:66 msgid "Add new contact card" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/contact.py:97 +#: ./src/pyams_content/component/paragraph/zmi/contact.py:94 msgid "Edit contact card properties" msgstr "" @@ -864,25 +927,14 @@ msgid "Header..." msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/header.py:61 +#: ./src/pyams_content/component/paragraph/zmi/header.py:63 msgid "Add new header paragraph" msgstr "" -#: ./src/pyams_content/component/paragraph/zmi/header.py:93 +#: ./src/pyams_content/component/paragraph/zmi/header.py:90 msgid "Edit header paragraph properties" msgstr "" -#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:40 -#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:44 -#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:41 -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:40 -#: ./src/pyams_content/component/association/interfaces/__init__.py:42 -#: ./src/pyams_content/shared/form/interfaces/__init__.py:86 -#: ./src/pyams_content/shared/site/interfaces/__init__.py:117 -#: ./src/pyams_content/features/alert/interfaces.py:54 -msgid "Visible?" -msgstr "" - #: ./src/pyams_content/component/paragraph/interfaces/milestone.py:41 msgid "Is this milestone visible in front-office?" msgstr "" @@ -947,8 +999,8 @@ msgstr "" #: ./src/pyams_content/component/paragraph/interfaces/__init__.py:85 -#: ./src/pyams_content/shared/common/zmi/types.py:167 -#: ./src/pyams_content/shared/common/zmi/types.py:395 +#: ./src/pyams_content/shared/common/zmi/types.py:169 +#: ./src/pyams_content/shared/common/zmi/types.py:380 msgid "Default paragraphs" msgstr "" @@ -956,14 +1008,7 @@ msgid "List of paragraphs automatically added to a new content" msgstr "" -#: ./src/pyams_content/component/paragraph/interfaces/video.py:41 -#: ./src/pyams_content/component/paragraph/interfaces/audio.py:41 -#: ./src/pyams_content/component/paragraph/interfaces/html.py:63 -#: ./src/pyams_content/component/video/interfaces/__init__.py:75 -msgid "Body" -msgstr "" - -#: ./src/pyams_content/component/paragraph/interfaces/video.py:53 +#: ./src/pyams_content/component/paragraph/interfaces/video.py:42 msgid "Video file content" msgstr "" @@ -982,7 +1027,8 @@ msgstr "" #: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:46 -#: ./src/pyams_content/shared/common/interfaces/types.py:67 +#: ./src/pyams_content/component/links/interfaces/__init__.py:43 +#: ./src/pyams_content/shared/common/interfaces/types.py:68 #: ./src/pyams_content/features/alert/interfaces.py:79 msgid "Pictogram" msgstr "" @@ -1018,6 +1064,11 @@ msgid "Audio" msgstr "" +#: ./src/pyams_content/component/paragraph/interfaces/audio.py:41 +#: ./src/pyams_content/component/paragraph/interfaces/html.py:63 +msgid "Body" +msgstr "" + #: ./src/pyams_content/component/paragraph/interfaces/audio.py:56 msgid "Audio template" msgstr "" @@ -1026,28 +1077,11 @@ msgid "Presentation template used for this audio file" msgstr "" -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:41 -msgid "Is this key number visible in front-office?" -msgstr "" - -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:46 -msgid "Key number value" -msgstr "" - -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:50 -msgid "" -"Small text to be displayed above number (according to selected renderer)" -msgstr "" - -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:55 -msgid "The way this text will be rendered depends on presentation template" -msgstr "" - -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:83 +#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:36 msgid "Key numbers template" msgstr "" -#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:84 +#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:37 msgid "Presentation template used for key numbers" msgstr "" @@ -1203,8 +1237,8 @@ msgid "no defined theme" msgstr "" -#: ./src/pyams_content/component/theme/zmi/__init__.py:52 -#: ./src/pyams_content/shared/view/zmi/theme.py:49 +#: ./src/pyams_content/component/theme/zmi/__init__.py:51 +#: ./src/pyams_content/shared/view/zmi/theme.py:48 msgid "Themes..." msgstr "" @@ -1212,7 +1246,7 @@ msgid "Content themes" msgstr "" -#: ./src/pyams_content/component/theme/zmi/manager.py:46 +#: ./src/pyams_content/component/theme/zmi/manager.py:45 msgid "Themes settings..." msgstr "" @@ -1222,20 +1256,20 @@ #: ./src/pyams_content/component/association/container.py:88 #: ./src/pyams_content/component/association/zmi/__init__.py:296 -#: ./src/pyams_content/component/association/interfaces/__init__.py:86 +#: ./src/pyams_content/component/association/interfaces/__init__.py:90 msgid "Associations" msgstr "" #: ./src/pyams_content/component/association/zmi/paragraph.py:54 -#: ./src/pyams_content/component/association/zmi/__init__.py:95 +#: ./src/pyams_content/component/association/zmi/__init__.py:96 msgid "Associations..." msgstr "" -#: ./src/pyams_content/component/association/zmi/paragraph.py:65 +#: ./src/pyams_content/component/association/zmi/paragraph.py:67 msgid "Add new association paragraph" msgstr "" -#: ./src/pyams_content/component/association/zmi/paragraph.py:97 +#: ./src/pyams_content/component/association/zmi/paragraph.py:93 msgid "Edit association paragraph properties" msgstr "" @@ -1256,129 +1290,134 @@ msgid "Associations list" msgstr "" -#: ./src/pyams_content/component/association/zmi/__init__.py:65 +#: ./src/pyams_content/component/association/zmi/__init__.py:66 msgid "Association was correctly added." msgstr "" #: ./src/pyams_content/component/association/interfaces/__init__.py:43 +#: ./src/pyams_content/features/menu/interfaces/__init__.py:59 msgid "Is this item visible in front-office?" msgstr "" -#: ./src/pyams_content/component/association/interfaces/__init__.py:93 +#: ./src/pyams_content/component/association/interfaces/__init__.py:97 msgid "Associations template" msgstr "" -#: ./src/pyams_content/component/association/interfaces/__init__.py:94 +#: ./src/pyams_content/component/association/interfaces/__init__.py:98 msgid "Presentation template used for associations" msgstr "" -#: ./src/pyams_content/component/links/__init__.py:104 +#: ./src/pyams_content/component/links/__init__.py:125 msgid "Internal link" msgstr "" -#: ./src/pyams_content/component/links/__init__.py:186 +#: ./src/pyams_content/component/links/__init__.py:207 msgid "External link" msgstr "" -#: ./src/pyams_content/component/links/__init__.py:239 +#: ./src/pyams_content/component/links/__init__.py:260 msgid "Mailto link" msgstr "" -#: ./src/pyams_content/component/links/__init__.py:173 +#: ./src/pyams_content/component/links/__init__.py:194 msgid "target is not published" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:57 +#: ./src/pyams_content/component/links/zmi/__init__.py:60 msgid "Internal links" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:72 +#: ./src/pyams_content/component/links/zmi/__init__.py:75 msgid "Add internal link" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:84 +#: ./src/pyams_content/component/links/zmi/__init__.py:89 msgid "Add new internal link" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:122 +#: ./src/pyams_content/component/links/zmi/__init__.py:125 msgid "Edit internal link properties" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:160 +#: ./src/pyams_content/component/links/zmi/__init__.py:159 msgid "External links" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:175 +#: ./src/pyams_content/component/links/zmi/__init__.py:174 msgid "Add external link" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:187 +#: ./src/pyams_content/component/links/zmi/__init__.py:188 msgid "Add new external link" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:225 +#: ./src/pyams_content/component/links/zmi/__init__.py:224 msgid "Edit external link properties" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:263 +#: ./src/pyams_content/component/links/zmi/__init__.py:258 msgid "Mailto links" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:278 +#: ./src/pyams_content/component/links/zmi/__init__.py:273 msgid "Add mailto link" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:290 +#: ./src/pyams_content/component/links/zmi/__init__.py:287 msgid "Add new mailto link" msgstr "" -#: ./src/pyams_content/component/links/zmi/__init__.py:328 +#: ./src/pyams_content/component/links/zmi/__init__.py:323 msgid "Edit mailto link properties" msgstr "" -#: ./src/pyams_content/component/links/zmi/reverse.py:55 +#: ./src/pyams_content/component/links/zmi/reverse.py:57 msgid "Reverse links" msgstr "" -#: ./src/pyams_content/component/links/zmi/reverse.py:64 +#: ./src/pyams_content/component/links/zmi/reverse.py:66 msgid "Content's internal links" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:34 +#: ./src/pyams_content/component/links/interfaces/__init__.py:36 msgid "Link title, as shown in front-office" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:38 +#: ./src/pyams_content/component/links/interfaces/__init__.py:40 msgid "Link description displayed by front-office template" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:55 +#: ./src/pyams_content/component/links/interfaces/__init__.py:44 +msgid "Name of the pictogram associated with this link" +msgstr "" + +#: ./src/pyams_content/component/links/interfaces/__init__.py:64 #: ./src/pyams_content/shared/logo/interfaces/__init__.py:50 msgid "Target URL" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:56 +#: ./src/pyams_content/component/links/interfaces/__init__.py:65 #: ./src/pyams_content/shared/logo/interfaces/__init__.py:51 msgid "URL used to access external resource" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:60 -msgid "Language used in this remote resource" -msgstr "" - -#: ./src/pyams_content/component/links/interfaces/__init__.py:68 -msgid "Target address" -msgstr "" - #: ./src/pyams_content/component/links/interfaces/__init__.py:69 +msgid "Language used in this remote resource" +msgstr "" + +#: ./src/pyams_content/component/links/interfaces/__init__.py:77 +msgid "Target address" +msgstr "" + +#: ./src/pyams_content/component/links/interfaces/__init__.py:78 msgid "Target email address" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:72 +#: ./src/pyams_content/component/links/interfaces/__init__.py:81 msgid "Address name" msgstr "" -#: ./src/pyams_content/component/links/interfaces/__init__.py:73 +#: ./src/pyams_content/component/links/interfaces/__init__.py:82 msgid "Address as displayed in address book" msgstr "" @@ -1623,24 +1662,24 @@ msgid "Youtube settings" msgstr "" -#: ./src/pyams_content/component/video/zmi/paragraph.py:61 +#: ./src/pyams_content/component/video/zmi/paragraph.py:62 msgid "External video..." msgstr "" -#: ./src/pyams_content/component/video/zmi/paragraph.py:72 +#: ./src/pyams_content/component/video/zmi/paragraph.py:75 msgid "Add new external video..." msgstr "" -#: ./src/pyams_content/component/video/zmi/paragraph.py:145 +#: ./src/pyams_content/component/video/zmi/paragraph.py:126 msgid "Video provider is required" msgstr "" -#: ./src/pyams_content/component/video/zmi/paragraph.py:194 -#: ./src/pyams_content/component/video/zmi/paragraph.py:259 +#: ./src/pyams_content/component/video/zmi/paragraph.py:175 +#: ./src/pyams_content/component/video/zmi/paragraph.py:229 msgid "Video provider settings" msgstr "" -#: ./src/pyams_content/component/video/zmi/paragraph.py:174 +#: ./src/pyams_content/component/video/zmi/paragraph.py:155 msgid "Other settings" msgstr "" @@ -1652,19 +1691,19 @@ msgid "Name of external platform providing selected video" msgstr "" -#: ./src/pyams_content/shared/common/__init__.py:237 -#: ./src/pyams_content/shared/common/zmi/properties.py:72 -#: ./src/pyams_content/shared/common/zmi/manager.py:97 +#: ./src/pyams_content/shared/common/__init__.py:240 +#: ./src/pyams_content/shared/common/zmi/properties.py:70 +#: ./src/pyams_content/shared/common/zmi/manager.py:96 msgid "Properties" msgstr "" -#: ./src/pyams_content/shared/common/__init__.py:147 -#: ./src/pyams_content/shared/common/__init__.py:155 +#: ./src/pyams_content/shared/common/__init__.py:150 +#: ./src/pyams_content/shared/common/__init__.py:158 #, python-format msgid "{date} by {principal}" msgstr "" -#: ./src/pyams_content/shared/common/__init__.py:260 +#: ./src/pyams_content/shared/common/__init__.py:263 #, python-format msgid "title length should be between 40 and 66 characters ({length} actually)" msgstr "" @@ -1717,11 +1756,11 @@ msgid "Modified before..." msgstr "" -#: ./src/pyams_content/shared/common/zmi/properties.py:62 +#: ./src/pyams_content/shared/common/zmi/properties.py:60 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 "" @@ -1733,40 +1772,40 @@ msgid "Data type label" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:183 -#: ./src/pyams_content/shared/common/zmi/types.py:411 +#: ./src/pyams_content/shared/common/zmi/types.py:185 +#: ./src/pyams_content/shared/common/zmi/types.py:396 msgid "Default associations" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:211 +#: ./src/pyams_content/shared/common/zmi/types.py:213 msgid "Content data types" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:234 +#: ./src/pyams_content/shared/common/zmi/types.py:236 msgid "Add data type" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:245 +#: ./src/pyams_content/shared/common/zmi/types.py:248 msgid "Add new data type" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:291 +#: ./src/pyams_content/shared/common/zmi/types.py:285 msgid "Data type properties" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:374 +#: ./src/pyams_content/shared/common/zmi/types.py:359 msgid "Subtype label" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:455 +#: ./src/pyams_content/shared/common/zmi/types.py:440 msgid "Add subtype" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:466 +#: ./src/pyams_content/shared/common/zmi/types.py:452 msgid "Add new subtype" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:518 +#: ./src/pyams_content/shared/common/zmi/types.py:498 msgid "Data subtype properties" msgstr "" @@ -1774,70 +1813,70 @@ msgid "No currently defined data type." msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:273 +#: ./src/pyams_content/shared/common/zmi/types.py:275 msgid "Specified type name is already used!" msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:494 -msgid "Specified subtype name is already used!" -msgstr "" - -#: ./src/pyams_content/shared/common/zmi/types.py:505 +#: ./src/pyams_content/shared/common/zmi/types.py:474 msgid "Subtype was correctly added." msgstr "" -#: ./src/pyams_content/shared/common/zmi/types.py:155 +#: ./src/pyams_content/shared/common/zmi/types.py:488 +msgid "Specified subtype name is already used!" +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/types.py:157 msgid "Click to see subtypes" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:907 +#: ./src/pyams_content/shared/common/zmi/workflow.py:844 msgid "Prior checks" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:126 +#: ./src/pyams_content/shared/common/zmi/workflow.py:123 msgid "Request publication" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:218 +#: ./src/pyams_content/shared/common/zmi/workflow.py:210 #: ./src/pyams_content/workflow/__init__.py:315 msgid "Cancel publication request" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:263 +#: ./src/pyams_content/shared/common/zmi/workflow.py:250 msgid "Refuse publication request" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:322 +#: ./src/pyams_content/shared/common/zmi/workflow.py:304 #: ./src/pyams_content/workflow/basic.py:196 msgid "Publish" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:416 +#: ./src/pyams_content/shared/common/zmi/workflow.py:393 msgid "Request retire" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:477 +#: ./src/pyams_content/shared/common/zmi/workflow.py:449 msgid "Cancel retire request" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:522 +#: ./src/pyams_content/shared/common/zmi/workflow.py:489 msgid "Retire" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:568 +#: ./src/pyams_content/shared/common/zmi/workflow.py:530 #: ./src/pyams_content/workflow/__init__.py:436 msgid "Request archive" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:616 +#: ./src/pyams_content/shared/common/zmi/workflow.py:573 msgid "Cancel archive request" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:661 +#: ./src/pyams_content/shared/common/zmi/workflow.py:613 msgid "Archive" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:707 +#: ./src/pyams_content/shared/common/zmi/workflow.py:654 #: ./src/pyams_content/workflow/__init__.py:501 #: ./src/pyams_content/workflow/__init__.py:513 #: ./src/pyams_content/workflow/__init__.py:525 @@ -1848,50 +1887,50 @@ msgid "Create new version" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:763 +#: ./src/pyams_content/shared/common/zmi/workflow.py:705 #: ./src/pyams_content/workflow/__init__.py:561 #: ./src/pyams_content/workflow/basic.py:248 msgid "Delete version" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:853 +#: ./src/pyams_content/shared/common/zmi/workflow.py:790 msgid "Previewed content?" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:857 +#: ./src/pyams_content/shared/common/zmi/workflow.py:794 msgid "Verified content?" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:188 -#: ./src/pyams_content/shared/common/zmi/workflow.py:385 +#: ./src/pyams_content/shared/common/zmi/workflow.py:180 +#: ./src/pyams_content/shared/common/zmi/workflow.py:362 msgid "Publication start date is required" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:291 -#: ./src/pyams_content/shared/common/zmi/workflow.py:447 +#: ./src/pyams_content/shared/common/zmi/workflow.py:273 +#: ./src/pyams_content/shared/common/zmi/workflow.py:419 msgid "A comment is required" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:786 +#: ./src/pyams_content/shared/common/zmi/workflow.py:729 msgid "Delete content" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:795 +#: ./src/pyams_content/shared/common/zmi/workflow.py:738 msgid "Delete definitively" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:923 +#: ./src/pyams_content/shared/common/zmi/workflow.py:860 msgid "" "You must confirm that you previewed and checked this content before " "requesting publication!!" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:90 +#: ./src/pyams_content/shared/common/zmi/workflow.py:87 #, python-format msgid "{state} | by {principal}" msgstr "" -#: ./src/pyams_content/shared/common/zmi/workflow.py:86 +#: ./src/pyams_content/shared/common/zmi/workflow.py:83 #: ./src/pyams_content/workflow/__init__.py:648 #: ./src/pyams_content/workflow/__init__.py:619 #: ./src/pyams_content/workflow/basic.py:315 @@ -1900,7 +1939,7 @@ msgid "{state} {date}" msgstr "" -#: ./src/pyams_content/shared/common/zmi/__init__.py:266 +#: ./src/pyams_content/shared/common/zmi/__init__.py:265 msgid "Duplicate content..." msgstr "" @@ -1908,20 +1947,20 @@ msgid "Duplicate content" msgstr "" -#: ./src/pyams_content/shared/common/zmi/__init__.py:85 +#: ./src/pyams_content/shared/common/zmi/__init__.py:84 msgid "This title can be modified afterwards" msgstr "" -#: ./src/pyams_content/shared/common/zmi/__init__.py:277 +#: ./src/pyams_content/shared/common/zmi/__init__.py:276 msgid "Duplicate this content" msgstr "" -#: ./src/pyams_content/shared/common/zmi/__init__.py:338 +#: ./src/pyams_content/shared/common/zmi/__init__.py:337 #, python-format msgid "Clone created from version {source} of {oid} (in « {state} » state)" msgstr "" -#: ./src/pyams_content/shared/common/zmi/__init__.py:389 +#: ./src/pyams_content/shared/common/zmi/__init__.py:382 msgid "Created or modified in this version" msgstr "" @@ -1972,39 +2011,39 @@ msgid "Shared tool properties" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:132 +#: ./src/pyams_content/shared/common/zmi/manager.py:125 msgid "WARNING" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:134 +#: ./src/pyams_content/shared/common/zmi/manager.py:127 msgid "" "Workflow shouldn't be modified if this tool already contains any shared " "content!" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:157 +#: ./src/pyams_content/shared/common/zmi/manager.py:150 msgid "Languages" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:168 +#: ./src/pyams_content/shared/common/zmi/manager.py:162 msgid "Content languages" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:185 +#: ./src/pyams_content/shared/common/zmi/manager.py:172 msgid "" "Tool languages are used to translate own tool properties, and newly created " "contents will propose these languages by default" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:81 +#: ./src/pyams_content/shared/common/zmi/manager.py:80 msgid "Content management" msgstr "" -#: ./src/pyams_content/shared/common/zmi/manager.py:83 +#: ./src/pyams_content/shared/common/zmi/manager.py:82 msgid "Tool management" msgstr "" -#: ./src/pyams_content/shared/common/zmi/owner.py:51 +#: ./src/pyams_content/shared/common/zmi/owner.py:50 msgid "Change owner..." msgstr "" @@ -2012,38 +2051,75 @@ msgid "Change content's owner" msgstr "" -#: ./src/pyams_content/shared/common/zmi/owner.py:132 +#: ./src/pyams_content/shared/common/zmi/owner.py:125 msgid "" "All versions of this content which are not archived will be transferred to " "newly selected owner" msgstr "" +#: ./src/pyams_content/shared/common/zmi/owner.py:60 +msgid "New owner" +msgstr "" + #: ./src/pyams_content/shared/common/zmi/owner.py:61 -msgid "New owner" -msgstr "" - -#: ./src/pyams_content/shared/common/zmi/owner.py:62 msgid "The selected user will become the new content's owner" msgstr "" +#: ./src/pyams_content/shared/common/zmi/owner.py:63 +msgid "Keep previous owner as contributor" +msgstr "" + #: ./src/pyams_content/shared/common/zmi/owner.py:64 -msgid "Keep previous owner as contributor" -msgstr "" - -#: ./src/pyams_content/shared/common/zmi/owner.py:65 msgid "If 'yes', the previous owner will still be able to modify this content" msgstr "" -#: ./src/pyams_content/shared/common/zmi/owner.py:75 +#: ./src/pyams_content/shared/common/zmi/owner.py:74 msgid "Change owner" msgstr "" +#: ./src/pyams_content/shared/common/zmi/rename.py:62 +msgid "Change URL..." +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/rename.py:79 +msgid "Change item URL" +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/rename.py:86 +msgid "Item URL part" +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/rename.py:87 +msgid "URL part used to access this content" +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/rename.py:121 +msgid "You must provide an URL for this item!" +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 +msgid "Edit default template properties" +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/portal.py:56 +msgid "" +"**This form allows you to select shared content default template.**\n" +"\n" +"If you choose to use a shared template, you can only adjust settings of each portlet individually but can't change portlets list or page configuration.\n" +"\n" +"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" +msgstr "" + #: ./src/pyams_content/shared/common/zmi/dashboard.py:134 msgid "Unique ID" msgstr "" @@ -2061,7 +2137,7 @@ msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:273 -#: ./src/pyams_content/root/zmi/__init__.py:91 +#: ./src/pyams_content/root/zmi/__init__.py:110 msgid "Dashboard" msgstr "" @@ -2070,55 +2146,55 @@ msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:329 -#: ./src/pyams_content/root/zmi/__init__.py:140 +#: ./src/pyams_content/root/zmi/__init__.py:159 #, python-format msgid "MANAGER - {0} content waiting for your action" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:330 -#: ./src/pyams_content/root/zmi/__init__.py:141 +#: ./src/pyams_content/root/zmi/__init__.py:160 #, python-format msgid "MANAGER - {0} contents waiting for your action" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:370 -#: ./src/pyams_content/root/zmi/__init__.py:184 +#: ./src/pyams_content/root/zmi/__init__.py:203 #, python-format msgid "CONTRIBUTOR - {0} content waiting for action" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:371 -#: ./src/pyams_content/root/zmi/__init__.py:185 +#: ./src/pyams_content/root/zmi/__init__.py:204 #, python-format msgid "CONTRIBUTOR - {0} contents waiting for action" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:402 -#: ./src/pyams_content/root/zmi/__init__.py:219 +#: ./src/pyams_content/root/zmi/__init__.py:238 #, python-format msgid "CONTRIBUTOR - {0} modified content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:443 -#: ./src/pyams_content/root/zmi/__init__.py:262 +#: ./src/pyams_content/root/zmi/__init__.py:281 msgid "My contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:458 #: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:8 -#: ./src/pyams_content/root/zmi/__init__.py:277 +#: ./src/pyams_content/root/zmi/__init__.py:296 #: ./src/pyams_content/root/zmi/templates/dashboard.pt:8 msgid "My favorites" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:467 -#: ./src/pyams_content/root/zmi/__init__.py:286 +#: ./src/pyams_content/root/zmi/__init__.py:305 #, python-format msgid "CONTRIBUTOR - {0} favorite" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:468 -#: ./src/pyams_content/root/zmi/__init__.py:287 +#: ./src/pyams_content/root/zmi/__init__.py:306 #, python-format msgid "CONTRIBUTOR - {0} favorites" msgstr "" @@ -2129,188 +2205,188 @@ msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:543 -#: ./src/pyams_content/root/zmi/__init__.py:325 +#: ./src/pyams_content/root/zmi/__init__.py:344 msgid "Your favorites" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:556 -#: ./src/pyams_content/root/zmi/__init__.py:338 +#: ./src/pyams_content/root/zmi/__init__.py:357 msgid "My preparations" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:565 -#: ./src/pyams_content/root/zmi/__init__.py:347 +#: ./src/pyams_content/root/zmi/__init__.py:366 #, python-format msgid "CONTRIBUTOR - {0} prepared content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:566 -#: ./src/pyams_content/root/zmi/__init__.py:348 +#: ./src/pyams_content/root/zmi/__init__.py:367 #, python-format msgid "CONTRIBUTOR - {0} prepared contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:605 -#: ./src/pyams_content/root/zmi/__init__.py:386 +#: ./src/pyams_content/root/zmi/__init__.py:405 msgid "Your prepared contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:618 -#: ./src/pyams_content/root/zmi/__init__.py:399 +#: ./src/pyams_content/root/zmi/__init__.py:418 msgid "My submissions" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:627 -#: ./src/pyams_content/root/zmi/__init__.py:408 +#: ./src/pyams_content/root/zmi/__init__.py:427 #, python-format msgid "CONTRIBUTOR - {0} submitted content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:628 -#: ./src/pyams_content/root/zmi/__init__.py:409 +#: ./src/pyams_content/root/zmi/__init__.py:428 #, python-format msgid "CONTRIBUTOR - {0} submitted contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:667 -#: ./src/pyams_content/root/zmi/__init__.py:447 +#: ./src/pyams_content/root/zmi/__init__.py:466 msgid "Your submitted contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:680 -#: ./src/pyams_content/root/zmi/__init__.py:460 +#: ./src/pyams_content/root/zmi/__init__.py:479 msgid "My publications" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:689 -#: ./src/pyams_content/root/zmi/__init__.py:469 +#: ./src/pyams_content/root/zmi/__init__.py:488 #, python-format msgid "CONTRIBUTOR - {0} published content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:690 -#: ./src/pyams_content/root/zmi/__init__.py:470 +#: ./src/pyams_content/root/zmi/__init__.py:489 #, python-format msgid "CONTRIBUTOR - {0} published contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:729 -#: ./src/pyams_content/root/zmi/__init__.py:508 +#: ./src/pyams_content/root/zmi/__init__.py:527 msgid "Your published contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:742 -#: ./src/pyams_content/root/zmi/__init__.py:521 +#: ./src/pyams_content/root/zmi/__init__.py:540 msgid "My retired contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:751 -#: ./src/pyams_content/root/zmi/__init__.py:530 +#: ./src/pyams_content/root/zmi/__init__.py:549 #, python-format msgid "CONTRIBUTOR - {0} retired content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:752 -#: ./src/pyams_content/root/zmi/__init__.py:531 +#: ./src/pyams_content/root/zmi/__init__.py:550 #, python-format msgid "CONTRIBUTOR - {0} retired contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:792 -#: ./src/pyams_content/root/zmi/__init__.py:570 +#: ./src/pyams_content/root/zmi/__init__.py:589 msgid "Your retired contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:805 -#: ./src/pyams_content/root/zmi/__init__.py:583 +#: ./src/pyams_content/root/zmi/__init__.py:602 msgid "My archived contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:814 -#: ./src/pyams_content/root/zmi/__init__.py:592 +#: ./src/pyams_content/root/zmi/__init__.py:611 #, python-format msgid "CONTRIBUTOR - {0} archived content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:815 -#: ./src/pyams_content/root/zmi/__init__.py:593 +#: ./src/pyams_content/root/zmi/__init__.py:612 #, python-format msgid "CONTRIBUTOR - {0} archived contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:861 -#: ./src/pyams_content/root/zmi/__init__.py:638 +#: ./src/pyams_content/root/zmi/__init__.py:657 msgid "Your archived contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:875 -#: ./src/pyams_content/root/zmi/__init__.py:652 +#: ./src/pyams_content/root/zmi/__init__.py:671 msgid "Other interventions" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:890 -#: ./src/pyams_content/root/zmi/__init__.py:667 +#: ./src/pyams_content/root/zmi/__init__.py:686 msgid "Last publications" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:899 -#: ./src/pyams_content/root/zmi/__init__.py:676 +#: ./src/pyams_content/root/zmi/__init__.py:695 #, python-format msgid "CONTRIBUTORS - {0} published content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:945 -#: ./src/pyams_content/root/zmi/__init__.py:721 +#: ./src/pyams_content/root/zmi/__init__.py:740 msgid "Last published contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:958 -#: ./src/pyams_content/root/zmi/__init__.py:734 +#: ./src/pyams_content/root/zmi/__init__.py:753 msgid "Last updates" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:967 -#: ./src/pyams_content/root/zmi/__init__.py:743 +#: ./src/pyams_content/root/zmi/__init__.py:762 #, python-format msgid "CONTRIBUTORS - {0} updated content" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:1012 -#: ./src/pyams_content/root/zmi/__init__.py:787 +#: ./src/pyams_content/root/zmi/__init__.py:806 msgid "Last updated contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:407 -#: ./src/pyams_content/root/zmi/__init__.py:224 +#: ./src/pyams_content/root/zmi/__init__.py:243 #, python-format msgid "CONTRIBUTOR - {0} modified contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:409 -#: ./src/pyams_content/root/zmi/__init__.py:226 +#: ./src/pyams_content/root/zmi/__init__.py:245 #, python-format msgid "CONTRIBUTOR - Last {0} modified contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:904 -#: ./src/pyams_content/root/zmi/__init__.py:681 +#: ./src/pyams_content/root/zmi/__init__.py:700 #, python-format msgid "CONTRIBUTORS - Last {0} published contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:906 -#: ./src/pyams_content/root/zmi/__init__.py:683 +#: ./src/pyams_content/root/zmi/__init__.py:702 msgid "CONTRIBUTORS - Last published contents (in the limit of 50)" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:972 -#: ./src/pyams_content/root/zmi/__init__.py:748 +#: ./src/pyams_content/root/zmi/__init__.py:767 #, python-format msgid "CONTRIBUTORS - Last {0} updated contents" msgstr "" #: ./src/pyams_content/shared/common/zmi/dashboard.py:974 -#: ./src/pyams_content/root/zmi/__init__.py:750 +#: ./src/pyams_content/root/zmi/__init__.py:769 msgid "CONTRIBUTORS - Last updated contents (in the limit of 50)" msgstr "" @@ -2324,64 +2400,62 @@ msgid "Content publication start date is not passed yet" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:65 +#: ./src/pyams_content/shared/common/zmi/security.py:64 msgid "Contributors restrictions" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:74 +#: ./src/pyams_content/shared/common/zmi/security.py:73 msgid "Content contributors restrictions" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:108 +#: ./src/pyams_content/shared/common/zmi/security.py:107 msgid "Contributor name" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:119 -#: ./src/pyams_content/shared/common/zmi/security.py:277 -#: ./src/pyams_content/shared/common/interfaces/__init__.py:252 -#: ./src/pyams_content/shared/common/interfaces/__init__.py:277 -msgid "Publication checks" -msgstr "" - -#: ./src/pyams_content/shared/common/zmi/security.py:225 +#: ./src/pyams_content/shared/common/zmi/security.py:118 +#: ./src/pyams_content/shared/common/zmi/security.py:270 +msgid "Activated publication checks?" +msgstr "" + +#: ./src/pyams_content/shared/common/zmi/security.py:218 msgid "Managers restrictions" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:234 +#: ./src/pyams_content/shared/common/zmi/security.py:227 msgid "Content managers restrictions" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:266 +#: ./src/pyams_content/shared/common/zmi/security.py:259 msgid "Manager name" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:294 +#: ./src/pyams_content/shared/common/zmi/security.py:287 msgid "Restricted" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:311 +#: ./src/pyams_content/shared/common/zmi/security.py:304 msgid "Owners" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:401 +#: ./src/pyams_content/shared/common/zmi/security.py:394 msgid "Publication workflow" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:168 +#: ./src/pyams_content/shared/common/zmi/security.py:167 #, python-format msgid "Edit contributor restrictions for « {0} »" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:360 +#: ./src/pyams_content/shared/common/zmi/security.py:353 #, python-format msgid "Edit manager restrictions for « {0} »" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:407 +#: ./src/pyams_content/shared/common/zmi/security.py:400 msgid "Apply contents restrictions" msgstr "" -#: ./src/pyams_content/shared/common/zmi/security.py:409 +#: ./src/pyams_content/shared/common/zmi/security.py:402 msgid "" "You can specify which contents this manager will be able to manage. If you " "specify several criteria, the manager will be able to manage contents for " @@ -2451,9 +2525,10 @@ #: ./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:39 +#: ./src/pyams_content/shared/common/interfaces/types.py:40 #: ./src/pyams_content/shared/form/zmi/field.py:159 -#: ./src/pyams_content/shared/form/interfaces/__init__.py:61 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:62 +#: ./src/pyams_content/features/menu/zmi/__init__.py:208 msgid "Label" msgstr "" @@ -2462,18 +2537,18 @@ msgid "Audit" msgstr "" -#: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:28 -#: ./src/pyams_content/root/zmi/templates/dashboard.pt:28 +#: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:29 +#: ./src/pyams_content/root/zmi/templates/dashboard.pt:29 msgid "Quick search..." msgstr "" -#: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:33 -#: ./src/pyams_content/root/zmi/templates/dashboard.pt:33 +#: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:35 +#: ./src/pyams_content/root/zmi/templates/dashboard.pt:35 msgid "Advanced search..." msgstr "" -#: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:46 -#: ./src/pyams_content/root/zmi/templates/dashboard.pt:46 +#: ./src/pyams_content/shared/common/zmi/templates/dashboard.pt:49 +#: ./src/pyams_content/root/zmi/templates/dashboard.pt:49 msgid "You are not actually concerned by any content." msgstr "" @@ -2645,79 +2720,91 @@ msgid "This content is already retired and not visible." msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:35 -#: ./src/pyams_content/shared/form/zmi/field.py:148 -msgid "Name" +#: ./src/pyams_content/shared/common/portlet/content/__init__.py:44 +msgid "Context content" +msgstr "" + +#: ./src/pyams_content/shared/common/portlet/content/zmi/preview.pt:2 +msgid "This is where the content will be displayed!!" +msgstr "" + +#: ./src/pyams_content/shared/common/portlet/content/skin/__init__.py:36 +msgid "Default content renderer" msgstr "" #: ./src/pyams_content/shared/common/interfaces/types.py:36 +#: ./src/pyams_content/shared/form/zmi/field.py:148 +msgid "Name" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:37 msgid "Name of this data type; must be unique between all data types" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:42 -msgid "Navigation label" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/types.py:43 +msgid "Navigation label" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:44 msgid "Label used for navigation entries" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:46 -msgid "Tab-folder label" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/types.py:47 +msgid "Tab-folder label" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:48 msgid "Label used to include into tab folder" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:50 -msgid "'See also' label" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/types.py:51 +msgid "'See also' label" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:52 msgid "" "This label can be used when contents of this type will be displayed in a 'See" " also' entries block" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:55 +#: ./src/pyams_content/shared/common/interfaces/types.py:56 msgid "'Single value' label" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:56 +#: ./src/pyams_content/shared/common/interfaces/types.py:57 msgid "Label given to this type when a single value is displayed" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:59 -msgid "'Link to list' label" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/types.py:60 +msgid "'Link to list' label" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:61 msgid "Label used to display a link to a list of items of this type" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:63 -msgid "Next content label" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/types.py:64 +msgid "Next content label" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:65 msgid "Label used to announce next date for this type" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:68 +#: ./src/pyams_content/shared/common/interfaces/types.py:69 msgid "Image associated to this data type" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/types.py:81 -msgid "Field names" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/types.py:82 +msgid "Field names" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/types.py:83 msgid "List of fields associated with this data type" msgstr "" #: ./src/pyams_content/shared/common/interfaces/__init__.py:46 -#: ./src/pyams_content/root/interfaces/__init__.py:40 +#: ./src/pyams_content/root/interfaces/__init__.py:43 msgid "Webmasters" msgstr "" @@ -2736,19 +2823,19 @@ msgstr "" #: ./src/pyams_content/shared/common/interfaces/__init__.py:57 -#: ./src/pyams_content/shared/common/interfaces/__init__.py:174 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:187 msgid "Managers" msgstr "" #: ./src/pyams_content/shared/common/interfaces/__init__.py:58 -#: ./src/pyams_content/shared/common/interfaces/__init__.py:175 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:188 msgid "" "Managers can handle main operations in tool's workflow, like publish or " "retire contents" msgstr "" #: ./src/pyams_content/shared/common/interfaces/__init__.py:63 -#: ./src/pyams_content/shared/common/interfaces/__init__.py:180 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:193 msgid "Contributors" msgstr "" @@ -2756,159 +2843,174 @@ msgid "Contributors are users which are allowed to create new contents" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:90 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:68 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:199 +msgid "Designers" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/__init__.py:69 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:200 +msgid "Designers are users which are allowed to manage presentation templates" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/__init__.py:95 msgid "Workflow name" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:91 +#: ./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:115 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:124 msgid "Content URL" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:116 +#: ./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:121 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:130 msgid "Version creator" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:122 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:131 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:126 -msgid "First owner" -msgstr "" - -#: ./src/pyams_content/shared/common/interfaces/__init__.py:127 -msgid "Name of content's first version owner" -msgstr "" - -#: ./src/pyams_content/shared/common/interfaces/__init__.py:131 -msgid "Version creation" -msgstr "" - -#: ./src/pyams_content/shared/common/interfaces/__init__.py:134 -msgid "Version modifiers" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/__init__.py:135 +msgid "First owner" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/__init__.py:136 +msgid "Name of content's first version owner" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/__init__.py:140 +msgid "Version creation" +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:138 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:147 msgid "Last modifier" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:139 +#: ./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:142 -msgid "Last update" -msgstr "" - -#: ./src/pyams_content/shared/common/interfaces/__init__.py:146 -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" -msgstr "" - #: ./src/pyams_content/shared/common/interfaces/__init__.py:151 -msgid "Keywords" -msgstr "" - -#: ./src/pyams_content/shared/common/interfaces/__init__.py:152 -msgid "They will be included into HTML pages metadata" +msgid "Last update" msgstr "" #: ./src/pyams_content/shared/common/interfaces/__init__.py:155 -#: ./src/pyams_content/shared/site/zmi/folder.py:76 +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" +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:66 msgid "Notepad" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:156 -#: ./src/pyams_content/shared/site/zmi/folder.py:77 +#: ./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:67 msgid "Internal information to be known about this content" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:167 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:180 msgid "Content owner" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:168 -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:181 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:194 +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:186 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:204 msgid "Readers" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:187 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:205 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:192 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:210 msgid "Guests" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:193 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:211 msgid "" "Guests are users which are allowed to view contents with restricted access" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:213 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:231 msgid "Principal ID" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:253 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:270 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:295 +msgid "Publication checks" +msgstr "" + +#: ./src/pyams_content/shared/common/interfaces/__init__.py:271 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:278 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:296 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:283 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:301 msgid "Restricted contents" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:284 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:302 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:289 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:307 msgid "Selected owners" msgstr "" -#: ./src/pyams_content/shared/common/interfaces/__init__.py:290 +#: ./src/pyams_content/shared/common/interfaces/__init__.py:308 msgid "Manager will have access to contents owned by these principals" msgstr "" @@ -2995,7 +3097,7 @@ msgstr "" #: ./src/pyams_content/shared/form/zmi/field.py:170 -#: ./src/pyams_content/shared/form/interfaces/__init__.py:56 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:57 msgid "Field type" msgstr "" @@ -3004,11 +3106,11 @@ msgstr "" #: ./src/pyams_content/shared/form/zmi/field.py:226 -#: ./src/pyams_content/shared/form/zmi/field.py:237 +#: ./src/pyams_content/shared/form/zmi/field.py:239 msgid "Add form field" msgstr "" -#: ./src/pyams_content/shared/form/zmi/field.py:285 +#: ./src/pyams_content/shared/form/zmi/field.py:281 msgid "Edit form field properties" msgstr "" @@ -3020,139 +3122,139 @@ msgid "No currently defined form field." msgstr "" -#: ./src/pyams_content/shared/form/zmi/field.py:262 +#: ./src/pyams_content/shared/form/zmi/field.py:266 msgid "Specified name is already used!" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:34 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:35 msgid "Form" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:52 -msgid "Field name" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:53 +msgid "Field name" +msgstr "" + +#: ./src/pyams_content/shared/form/interfaces/__init__.py:54 msgid "Field internal name; must be unique for a given form" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:57 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:58 msgid "Selected field type" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:62 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:63 msgid "User field label" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:66 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:67 msgid "Field description can be displayed as hint" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:69 -msgid "Placeholder" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:70 +msgid "Placeholder" +msgstr "" + +#: ./src/pyams_content/shared/form/interfaces/__init__.py:71 msgid "Some field types like textline can display a placeholder" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:73 -msgid "Optional values" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:74 +msgid "Optional values" +msgstr "" + +#: ./src/pyams_content/shared/form/interfaces/__init__.py:75 msgid "List of available values (for 'choice' and 'list' field types)" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:77 -msgid "Default value" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:78 +msgid "Default value" +msgstr "" + +#: ./src/pyams_content/shared/form/interfaces/__init__.py:79 msgid "Give default value if field type can use it" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:81 -msgid "Required?" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:82 +msgid "Required?" +msgstr "" + +#: ./src/pyams_content/shared/form/interfaces/__init__.py:83 msgid "Select 'yes' to set field as mandatory" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:87 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:88 msgid "Select 'no' to hide given field..." msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:121 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:122 msgid "Form title" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:124 +#: ./src/pyams_content/shared/form/interfaces/__init__.py:125 msgid "Form header" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:127 -msgid "Form handler" -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" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:131 -msgid "Authenticated only?" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:132 +msgid "Authenticated only?" +msgstr "" + +#: ./src/pyams_content/shared/form/interfaces/__init__.py:133 msgid "If 'yes', only authenticated users will be able to see and submit form" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:136 -msgid "Use captcha?" -msgstr "" - #: ./src/pyams_content/shared/form/interfaces/__init__.py:137 +msgid "Use captcha?" +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:141 -msgid "Submit label" -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:179 -msgid "Source address" -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" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:183 -msgid "Source name" -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" msgstr "" -#: ./src/pyams_content/shared/form/interfaces/__init__.py:187 -msgid "Recipient address" -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:191 -msgid "Recipient name" -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 "" @@ -3170,7 +3272,7 @@ msgid "News topic « {title} »" msgstr "" -#: ./src/pyams_content/shared/news/interfaces/__init__.py:28 +#: ./src/pyams_content/shared/news/interfaces/__init__.py:29 msgid "News topic" msgstr "" @@ -3196,7 +3298,7 @@ msgid "View themes settings" msgstr "" -#: ./src/pyams_content/shared/view/zmi/reference.py:53 +#: ./src/pyams_content/shared/view/zmi/reference.py:52 msgid "References..." msgstr "" @@ -3204,15 +3306,7 @@ msgid "View internal references settings" msgstr "" -#: ./src/pyams_content/shared/view/zmi/templates/render.pt:2 -msgid "View result items" -msgstr "" - -#: ./src/pyams_content/shared/view/zmi/templates/render.pt:3 -msgid "WARNING: items displayed in this preview are out of context!!" -msgstr "" - -#: ./src/pyams_content/shared/view/portlet/__init__.py:56 +#: ./src/pyams_content/shared/view/portlet/__init__.py:58 msgid "View items" msgstr "" @@ -3229,7 +3323,7 @@ msgstr "" #: ./src/pyams_content/shared/view/interfaces/__init__.py:40 -#: ./src/pyams_content/interfaces/__init__.py:111 +#: ./src/pyams_content/interfaces/__init__.py:113 #: ./src/pyams_content/features/review/interfaces.py:74 msgid "Creation date" msgstr "" @@ -3302,15 +3396,23 @@ msgid "Specify how selected references are included into view results" msgstr "" -#: ./src/pyams_content/shared/view/interfaces/__init__.py:171 -msgid "Select context themes?" -msgstr "" - -#: ./src/pyams_content/shared/view/interfaces/__init__.py:172 -msgid "If 'yes', themes will be extracted from context" +#: ./src/pyams_content/shared/view/interfaces/__init__.py:164 +msgid "Exclude context?" +msgstr "" + +#: ./src/pyams_content/shared/view/interfaces/__init__.py:165 +msgid "If 'yes', context will be excluded from results list" msgstr "" #: ./src/pyams_content/shared/view/interfaces/__init__.py:176 +msgid "Select context themes?" +msgstr "" + +#: ./src/pyams_content/shared/view/interfaces/__init__.py:177 +msgid "If 'yes', themes will be extracted from context" +msgstr "" + +#: ./src/pyams_content/shared/view/interfaces/__init__.py:181 msgid "Other terms" msgstr "" @@ -3336,12 +3438,12 @@ msgid "Image map..." msgstr "" -#: ./src/pyams_content/shared/imagemap/zmi/paragraph.py:65 +#: ./src/pyams_content/shared/imagemap/zmi/paragraph.py:67 msgid "Add new image map" msgstr "" -#: ./src/pyams_content/shared/imagemap/zmi/paragraph.py:97 -#: ./src/pyams_content/shared/logo/zmi/paragraph.py:96 +#: ./src/pyams_content/shared/imagemap/zmi/paragraph.py:94 +#: ./src/pyams_content/shared/logo/zmi/paragraph.py:93 msgid "Edit paragraph properties" msgstr "" @@ -3401,15 +3503,15 @@ msgid "Bad query object_name parameter value!" msgstr "" -#: ./src/pyams_content/shared/imagemap/zmi/area.py:46 +#: ./src/pyams_content/shared/imagemap/zmi/area.py:47 msgid "Add image area" msgstr "" -#: ./src/pyams_content/shared/imagemap/zmi/area.py:64 +#: ./src/pyams_content/shared/imagemap/zmi/area.py:66 msgid "Add new image area" msgstr "" -#: ./src/pyams_content/shared/imagemap/zmi/area.py:108 +#: ./src/pyams_content/shared/imagemap/zmi/area.py:107 msgid "Edit image map properties" msgstr "" @@ -3455,7 +3557,7 @@ msgid "Image map template" msgstr "" -#: ./src/pyams_content/shared/site/folder.py:58 +#: ./src/pyams_content/shared/site/folder.py:59 msgid "Site folder" msgstr "" @@ -3463,39 +3565,44 @@ msgid "Content link" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:59 +#: ./src/pyams_content/shared/site/manager.py:68 +#: ./src/pyams_content/shared/site/zmi/manager.py:125 +msgid "Site manager" +msgstr "" + +#: ./src/pyams_content/shared/site/zmi/folder.py:61 msgid "Add site folder..." msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:90 +#: ./src/pyams_content/shared/site/zmi/folder.py:93 msgid "Add site folder" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:166 +#: ./src/pyams_content/shared/site/zmi/folder.py:162 msgid "Site folder management" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:177 +#: ./src/pyams_content/shared/site/zmi/folder.py:190 msgid "Site folder properties" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:69 -#: ./src/pyams_content/interfaces/__init__.py:100 +#: ./src/pyams_content/shared/site/zmi/folder.py:71 +#: ./src/pyams_content/interfaces/__init__.py:102 msgid "Visible label used to display content" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:72 +#: ./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:67 +#: ./src/pyams_content/shared/site/zmi/link.py:66 msgid "Parent" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:73 -#: ./src/pyams_content/shared/site/zmi/link.py:68 +#: ./src/pyams_content/shared/site/zmi/folder.py:75 +#: ./src/pyams_content/shared/site/zmi/link.py:67 msgid "Folder's parent" msgstr "" -#: ./src/pyams_content/shared/site/zmi/folder.py:150 +#: ./src/pyams_content/shared/site/zmi/folder.py:155 msgid "You must provide a folder name for default server language!" msgstr "" @@ -3507,7 +3614,7 @@ msgid "Add topic..." msgstr "" -#: ./src/pyams_content/shared/site/zmi/__init__.py:84 +#: ./src/pyams_content/shared/site/zmi/__init__.py:86 msgid "Add topic" msgstr "" @@ -3515,7 +3622,7 @@ msgid "Topic's parent" msgstr "" -#: ./src/pyams_content/shared/site/zmi/link.py:58 +#: ./src/pyams_content/shared/site/zmi/link.py:57 msgid "Rent content..." msgstr "" @@ -3523,85 +3630,81 @@ msgid "Rent existing content" msgstr "" -#: ./src/pyams_content/shared/site/zmi/link.py:141 +#: ./src/pyams_content/shared/site/zmi/link.py:135 msgid "Edit content link properties" msgstr "" #: ./src/pyams_content/shared/site/zmi/container.py:106 #: ./src/pyams_content/shared/site/zmi/container.py:118 -#: ./src/pyams_content/shared/blog/zmi/manager.py:160 -#: ./src/pyams_content/shared/blog/zmi/manager.py:172 +#: ./src/pyams_content/shared/blog/zmi/manager.py:155 +#: ./src/pyams_content/shared/blog/zmi/manager.py:167 msgid "Publication dates..." msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:131 -#: ./src/pyams_content/shared/blog/zmi/manager.py:185 +#: ./src/pyams_content/shared/site/zmi/container.py:132 +#: ./src/pyams_content/shared/blog/zmi/manager.py:181 msgid "Update publication dates" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:183 -#: ./src/pyams_content/shared/site/zmi/container.py:193 +#: ./src/pyams_content/shared/site/zmi/container.py:178 +#: ./src/pyams_content/shared/site/zmi/container.py:188 #: ./src/pyams_content/root/zmi/sites.py:68 msgid "Site tree" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:312 -#: ./src/pyams_content/shared/site/zmi/container.py:162 +#: ./src/pyams_content/shared/site/zmi/container.py:307 +#: ./src/pyams_content/shared/site/zmi/container.py:156 msgid "Visible element?" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:313 +#: ./src/pyams_content/shared/site/zmi/container.py:308 msgid "Switch element visibility" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:374 +#: ./src/pyams_content/shared/site/zmi/container.py:369 msgid "Folders and topics" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:410 -#: ./src/pyams_content/root/zmi/__init__.py:798 +#: ./src/pyams_content/shared/site/zmi/container.py:405 +#: ./src/pyams_content/root/zmi/__init__.py:817 msgid "Content" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:506 +#: ./src/pyams_content/shared/site/zmi/container.py:501 msgid "Delete site item" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:383 +#: ./src/pyams_content/shared/site/zmi/container.py:378 msgid "Click to open/close all folders" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:399 +#: ./src/pyams_content/shared/site/zmi/container.py:394 msgid "Click to show/hide inner folders" msgstr "" -#: ./src/pyams_content/shared/site/zmi/container.py:269 +#: ./src/pyams_content/shared/site/zmi/container.py:264 msgid "Can't reparent object to one of it's children. Reloading..." msgstr "" -#: ./src/pyams_content/shared/site/zmi/manager.py:58 +#: ./src/pyams_content/shared/site/zmi/manager.py:57 msgid "Site management" msgstr "" -#: ./src/pyams_content/shared/site/zmi/manager.py:88 -#: ./src/pyams_content/shared/site/zmi/manager.py:100 +#: ./src/pyams_content/shared/site/zmi/manager.py:112 +#: ./src/pyams_content/shared/site/zmi/manager.py:126 msgid "Add site manager" msgstr "" -#: ./src/pyams_content/shared/site/zmi/manager.py:99 -msgid "Site manager" -msgstr "" - -#: ./src/pyams_content/shared/site/zmi/manager.py:131 -#: ./src/pyams_content/shared/blog/zmi/manager.py:126 +#: ./src/pyams_content/shared/site/zmi/manager.py:156 +#: ./src/pyams_content/shared/blog/zmi/manager.py:127 msgid "You must provide a short name for default server language!" msgstr "" -#: ./src/pyams_content/shared/site/zmi/manager.py:135 +#: ./src/pyams_content/shared/site/zmi/manager.py:160 msgid "Specified site manager name is already used!" msgstr "" -#: ./src/pyams_content/shared/site/zmi/manager.py:139 +#: ./src/pyams_content/shared/site/zmi/manager.py:164 msgid "A site manager is already registered with this name!!" msgstr "" @@ -3655,11 +3758,11 @@ msgid "no URL defined" msgstr "" -#: ./src/pyams_content/shared/logo/zmi/paragraph.py:53 +#: ./src/pyams_content/shared/logo/zmi/paragraph.py:54 msgid "Logos..." msgstr "" -#: ./src/pyams_content/shared/logo/zmi/paragraph.py:64 +#: ./src/pyams_content/shared/logo/zmi/paragraph.py:67 msgid "Add new logos paragraph" msgstr "" @@ -3720,19 +3823,19 @@ msgstr "" #: ./src/pyams_content/shared/blog/zmi/manager.py:83 -#: ./src/pyams_content/shared/blog/zmi/manager.py:95 +#: ./src/pyams_content/shared/blog/zmi/manager.py:97 msgid "Add blog manager" msgstr "" -#: ./src/pyams_content/shared/blog/zmi/manager.py:94 +#: ./src/pyams_content/shared/blog/zmi/manager.py:96 msgid "Blog manager" msgstr "" -#: ./src/pyams_content/shared/blog/zmi/manager.py:130 +#: ./src/pyams_content/shared/blog/zmi/manager.py:131 msgid "Specified blog manager name is already used!" msgstr "" -#: ./src/pyams_content/shared/blog/zmi/manager.py:134 +#: ./src/pyams_content/shared/blog/zmi/manager.py:135 msgid "A blog manager is already registered with this name!!" msgstr "" @@ -3760,6 +3863,10 @@ msgid "Default length used for inner tables and dashboards" msgstr "" +#: ./src/pyams_content/root/__init__.py:67 +msgid "Site root" +msgstr "" + #: ./src/pyams_content/root/zmi/sites.py:78 msgid "Blogs and shared sites" msgstr "" @@ -3784,7 +3891,7 @@ msgid "Content types" msgstr "" -#: ./src/pyams_content/root/zmi/__init__.py:77 +#: ./src/pyams_content/root/zmi/__init__.py:78 msgid "Home" msgstr "" @@ -3796,19 +3903,19 @@ msgid "SEARCH - Between all contents" msgstr "" -#: ./src/pyams_content/root/interfaces/__init__.py:36 +#: ./src/pyams_content/root/interfaces/__init__.py:39 msgid "Site managers" msgstr "" -#: ./src/pyams_content/root/interfaces/__init__.py:44 +#: ./src/pyams_content/root/interfaces/__init__.py:47 msgid "Templates managers" msgstr "" -#: ./src/pyams_content/root/interfaces/__init__.py:48 +#: ./src/pyams_content/root/interfaces/__init__.py:51 msgid "Operators group" msgstr "" -#: ./src/pyams_content/root/interfaces/__init__.py:49 +#: ./src/pyams_content/root/interfaces/__init__.py:52 msgid "Name of group containing all roles owners" msgstr "" @@ -4129,11 +4236,11 @@ msgid "Automatic contents withdrawal:\n" msgstr "" -#: ./src/pyams_content/workflow/zmi/task.py:43 +#: ./src/pyams_content/workflow/zmi/task.py:42 msgid "Add content archiver task..." msgstr "" -#: ./src/pyams_content/workflow/zmi/task.py:54 +#: ./src/pyams_content/workflow/zmi/task.py:55 msgid "Add automatic content archiver" msgstr "" @@ -4162,18 +4269,20 @@ msgstr "" #: ./src/pyams_content/interfaces/__init__.py:96 -msgid "WARNING: this key can't be modified after creation!!!" -msgstr "" - -#: ./src/pyams_content/interfaces/__init__.py:103 +msgid "" +"WARNING: this key can't be modified after creation!!! Spaces, uppercase " +"letters ou accentuated characters will be replaced automatically." +msgstr "" + +#: ./src/pyams_content/interfaces/__init__.py:105 msgid "Short name" msgstr "" -#: ./src/pyams_content/interfaces/__init__.py:104 +#: ./src/pyams_content/interfaces/__init__.py:106 msgid "Short name used in breadcrumbs" msgstr "" -#: ./src/pyams_content/interfaces/__init__.py:115 +#: ./src/pyams_content/interfaces/__init__.py:117 msgid "Modification date" msgstr "" @@ -4194,11 +4303,11 @@ msgid "Properties..." msgstr "" -#: ./src/pyams_content/reference/zmi/table.py:156 +#: ./src/pyams_content/reference/zmi/table.py:157 msgid "Edit table properties" msgstr "" -#: ./src/pyams_content/reference/zmi/table.py:173 +#: ./src/pyams_content/reference/zmi/table.py:167 msgid "Table management" msgstr "" @@ -4206,11 +4315,16 @@ msgid "References" msgstr "" +#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:169 +#: ./src/pyams_content/reference/pictograms/zmi/widget.py:55 +msgid "Default header: --" +msgstr "" + #: ./src/pyams_content/reference/pictograms/zmi/manager.py:51 msgid "Pictograms selection..." msgstr "" -#: ./src/pyams_content/reference/pictograms/zmi/manager.py:62 +#: ./src/pyams_content/reference/pictograms/zmi/manager.py:63 #: ./src/pyams_content/reference/pictograms/zmi/templates/manager-selection.pt:34 #: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:73 msgid "Selected pictograms" @@ -4225,6 +4339,10 @@ msgid "Display pictogram properties" msgstr "" +#: ./src/pyams_content/reference/pictograms/zmi/templates/pictogram-header.pt:6 +msgid "Default header: ${header}" +msgstr "" + #: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:45 msgid "Pictogram content" msgstr "" @@ -4242,7 +4360,7 @@ msgid "List of selected pictograms which will be available to shared contents" msgstr "" -#: ./src/pyams_content/features/renderer/zmi/__init__.py:72 +#: ./src/pyams_content/features/renderer/zmi/__init__.py:70 #: ./src/pyams_content/features/renderer/zmi/templates/renderer-input.pt:4 msgid "Edit renderer properties" msgstr "" @@ -4322,7 +4440,7 @@ #. Default: Heading #: ./src/pyams_content/features/alert/interfaces.py:65 -#: ./src/pyams_content/features/alert/zmi/container.py:158 +#: ./src/pyams_content/features/alert/zmi/container.py:157 msgid "alert-header" msgstr "" @@ -4331,7 +4449,7 @@ msgstr "" #: ./src/pyams_content/features/alert/interfaces.py:69 -#: ./src/pyams_content/features/alert/zmi/container.py:170 +#: ./src/pyams_content/features/alert/zmi/container.py:169 msgid "Message" msgstr "" @@ -4371,7 +4489,7 @@ "set to 0 to always display the alert" msgstr "" -#: ./src/pyams_content/features/alert/zmi/__init__.py:46 +#: ./src/pyams_content/features/alert/zmi/__init__.py:45 msgid "Add alert" msgstr "" @@ -4379,7 +4497,7 @@ msgid "Add new alert" msgstr "" -#: ./src/pyams_content/features/alert/zmi/__init__.py:85 +#: ./src/pyams_content/features/alert/zmi/__init__.py:79 msgid "Edit alert properties" msgstr "" @@ -4387,31 +4505,104 @@ msgid "Alerts" msgstr "" -#: ./src/pyams_content/features/alert/zmi/container.py:192 +#: ./src/pyams_content/features/alert/zmi/container.py:191 msgid "Alert list" msgstr "" -#: ./src/pyams_content/features/alert/zmi/container.py:91 +#: ./src/pyams_content/features/alert/zmi/container.py:90 msgid "No currently defined alert." msgstr "" -#: ./src/pyams_content/features/footer/zmi/__init__.py:56 +#: ./src/pyams_content/features/menu/zmi/__init__.py:81 +msgid "Add menu..." +msgstr "" + +#: ./src/pyams_content/features/menu/zmi/__init__.py:92 +msgid "Add new menu" +msgstr "" + +#: ./src/pyams_content/features/menu/zmi/__init__.py:123 +msgid "Edit menu properties" +msgstr "" + +#: ./src/pyams_content/features/menu/zmi/__init__.py:110 +msgid "Menu was correctly added." +msgstr "" + +#: ./src/pyams_content/features/menu/zmi/__init__.py:388 +msgid "Link was correctly added." +msgstr "" + +#: ./src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt:7 +msgid "Click to see menu items" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/simple.py:68 +msgid "Simple navigation" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/double.py:68 +msgid "Double navigation" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/zmi/simple.py:70 +msgid "Navigation links" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/zmi/double.py:70 +msgid "Navigation menus" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:13 +msgid "Link has no illustration" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:32 +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:32 +msgid "Portlet main title" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:35 +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:35 +msgid "Subtitle" +msgstr "" + +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:36 +#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:36 +msgid "Portlet subtitle" +msgstr "" + +#: ./src/pyams_content/features/menu/interfaces/__init__.py:63 +msgid "Menu title" +msgstr "" + +#: ./src/pyams_content/features/menu/interfaces/__init__.py:64 +msgid "Displayed menu label" +msgstr "" + +#: ./src/pyams_content/features/footer/zmi/__init__.py:60 msgid "Page footer" msgstr "" -#: ./src/pyams_content/features/footer/zmi/__init__.py:74 +#: ./src/pyams_content/features/footer/zmi/__init__.py:78 msgid "Edit footer settings" msgstr "" -#: ./src/pyams_content/features/footer/zmi/__init__.py:172 +#: ./src/pyams_content/features/footer/zmi/__init__.py:152 +msgid "" +"WARNING: Footer properties are saved automatically when changing inherit " +"mode!!" +msgstr "" + +#: ./src/pyams_content/features/footer/zmi/__init__.py:220 msgid "Footer renderer settings" msgstr "" -#: ./src/pyams_content/features/footer/zmi/__init__.py:101 +#: ./src/pyams_content/features/footer/zmi/__init__.py:107 msgid "Don't inherit parent footer" msgstr "" -#: ./src/pyams_content/features/footer/skin/__init__.py:49 +#: ./src/pyams_content/features/footer/skin/__init__.py:53 msgid "Hidden footer" msgstr "" @@ -4423,17 +4614,17 @@ msgid "Presentation template used for this footer" msgstr "" -#: ./src/pyams_content/features/review/__init__.py:180 +#: ./src/pyams_content/features/review/__init__.py:181 #, python-format msgid "Request comment: {comment}" msgstr "" -#: ./src/pyams_content/features/review/__init__.py:210 +#: ./src/pyams_content/features/review/__init__.py:211 #, python-format msgid "A new comment was added on content « {0} »" msgstr "" -#: ./src/pyams_content/features/review/__init__.py:167 +#: ./src/pyams_content/features/review/__init__.py:168 #, python-format msgid "[{service_name}] A content review is requested" msgstr "" @@ -4478,15 +4669,15 @@ msgid "Ask for review..." msgstr "" -#: ./src/pyams_content/features/review/zmi/__init__.py:99 +#: ./src/pyams_content/features/review/zmi/__init__.py:100 msgid "Content review request" msgstr "" -#: ./src/pyams_content/features/review/zmi/__init__.py:172 +#: ./src/pyams_content/features/review/zmi/__init__.py:166 msgid "Comments" msgstr "" -#: ./src/pyams_content/features/review/zmi/__init__.py:192 +#: ./src/pyams_content/features/review/zmi/__init__.py:186 msgid "Review comments" msgstr "" @@ -4521,15 +4712,15 @@ msgid "Ask for content review" msgstr "" -#: ./src/pyams_content/features/review/zmi/__init__.py:153 +#: ./src/pyams_content/features/review/zmi/__init__.py:147 msgid "Request successful. No new notification have been sent" msgstr "" -#: ./src/pyams_content/features/review/zmi/__init__.py:266 +#: ./src/pyams_content/features/review/zmi/__init__.py:260 msgid "Message is mandatory!" msgstr "" -#: ./src/pyams_content/features/review/zmi/__init__.py:141 +#: ./src/pyams_content/features/review/zmi/__init__.py:135 #, python-format msgid "Request successful. {count} new notification(s) have been sent" msgstr "" @@ -4605,22 +4796,28 @@ msgid "Thank you." msgstr "" -#: ./src/pyams_content/features/header/zmi/__init__.py:62 +#: ./src/pyams_content/features/header/zmi/__init__.py:66 msgid "Page header" msgstr "" -#: ./src/pyams_content/features/header/zmi/__init__.py:80 +#: ./src/pyams_content/features/header/zmi/__init__.py:84 msgid "Edit header settings" msgstr "" -#: ./src/pyams_content/features/header/zmi/__init__.py:178 +#: ./src/pyams_content/features/header/zmi/__init__.py:161 +msgid "" +"WARNING: Header properties are saved automatically when changing inherit " +"mode!!" +msgstr "" + +#: ./src/pyams_content/features/header/zmi/__init__.py:229 msgid "Header renderer settings" msgstr "" -#: ./src/pyams_content/features/header/zmi/__init__.py:107 +#: ./src/pyams_content/features/header/zmi/__init__.py:113 msgid "Don't inherit parent header" msgstr "" -#: ./src/pyams_content/features/header/skin/__init__.py:49 +#: ./src/pyams_content/features/header/skin/__init__.py:53 msgid "Hidden header" msgstr "" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/reference/pictograms/manager.py --- a/src/pyams_content/reference/pictograms/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/reference/pictograms/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -54,12 +54,16 @@ terms = [] table = query_utility(IPictogramTable) if table is not None: + request = check_request() target = get_parent(context, IPictogramManagerTarget) if target is not None: - request = check_request() manager = IPictogramManager(target) - pictograms = [table.get(name) for name in manager.selected_pictograms] + pictograms = [table.get(name) for name in manager.selected_pictograms or ()] terms = [SimpleTerm(v.__name__, title=II18n(v).query_attribute('title', request=request)) for v in pictograms if v is not None] + else: + terms = [SimpleTerm(v.__name__, + title=II18n(v).query_attribute('title', request=request)) + for v in table.values()] super(SelectedPictogramsVocabulary, self).__init__(terms) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/reference/pictograms/zmi/__init__.py --- a/src/pyams_content/reference/pictograms/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/reference/pictograms/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -14,9 +14,6 @@ # import standard library -import sys - -from random import randint from uuid import uuid4 # import interfaces @@ -32,6 +29,7 @@ # import packages from pyams_content.reference.pictograms import Pictogram +from pyams_file.zmi.image import render_image from pyams_form.form import AJAXAddForm, ajax_config from pyams_i18n.column import I18nAttrColumn from pyams_pagelet.pagelet import pagelet_config @@ -40,10 +38,10 @@ from pyams_skin.viewlet.toolbar import ToolbarAction from pyams_utils.adapter import adapter_config 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 pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest +from pyramid.httpexceptions import HTTPNotFound +from pyramid.renderers import render, render_to_response from pyramid.response import Response from pyramid.view import view_config from z3c.form import field @@ -141,8 +139,8 @@ def getValue(self, obj): image = II18n(obj).query_attribute('image', request=self.request) if image: - timestamp = randint(0, sys.maxsize) - return ''.format(absolute_url(image, self.request, '++thumb++32x32'), timestamp) + return render_image(image, 32, 32, timestamp=True) + return '--' @adapter_config(name='name', context=(IPictogramTable, IAdminLayer, PictogramTableContentsTable), provides=IColumn) @@ -163,16 +161,22 @@ @view_config(name='get-pictogram-header.html', context=IPictogramTable, request_type=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) -def get_pictogram_label(request): - """Get alternate label associated with a given pictogram""" +def get_pictogram_header_view(request): + """View used to get thumbnail and alternate label associated with a given pictogram""" + translate = request.localizer.translate name = request.params.get('value') - if not name: - raise HTTPBadRequest() - translate = request.localizer.translate - if name == '--NOVALUE--': + if (not name) or (name == '--NOVALUE--'): return Response(translate(_("Default header: --"))) pictogram = request.context.get(name) if pictogram is None: raise HTTPNotFound() - return Response(translate(_("Default header: {0}")).format( - II18n(pictogram).query_attribute('header', request=request) or '--')) + return render_to_response('templates/pictogram-header.pt', { + 'context': pictogram + }, request=request) + + +def get_pictogram_header(pictogram, request=None): + """Get thumbnail and alternate label associated with a given pictogram""" + return render('templates/pictogram-header.pt', { + 'context': pictogram + }, request=request) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/reference/pictograms/zmi/templates/manager-selection.pt --- a/src/pyams_content/reference/pictograms/zmi/templates/manager-selection.pt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/reference/pictograms/zmi/templates/manager-selection.pt Wed Jun 27 16:42:01 2018 +0200 @@ -22,9 +22,9 @@
- +
Title @@ -49,9 +49,9 @@
- +
Title diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/reference/pictograms/zmi/templates/pictogram-header.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/reference/pictograms/zmi/templates/pictogram-header.pt Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,9 @@ +
+ + Default header: + + +
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/reference/pictograms/zmi/widget.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/reference/pictograms/zmi/widget.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,69 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.reference.pictograms import IPictogramTable +from pyams_utils.interfaces.data import IObjectData + +# import packages +from pyams_content.reference.pictograms.zmi import get_pictogram_header +from pyams_utils.registry import query_utility +from pyams_utils.url import absolute_url +from z3c.form.browser.select import SelectWidget +from z3c.form.widget import FieldWidget +from zope.interface import implementer + +from pyams_content import _ + + +@implementer(IObjectData) +class PictogramSelectWidget(SelectWidget): + """Pictogram selection widget""" + + pictograms = None + label_id = None + after_widget_notice = None + + def update(self): + super(PictogramSelectWidget, self).update() + self.label_id = '{0}_header'.format(self.id) + self.pictograms = query_utility(IPictogramTable) + if self.value and (self.pictograms is not None): + pictogram = self.pictograms.get(self.value[0]) + if pictogram is not None: + self.after_widget_notice = '{1}'.format( + self.label_id, + get_pictogram_header(pictogram, self.request)) + return + self.after_widget_notice = '{1}'.format( + self.label_id, + self.request.localizer.translate(_("Default header: --"))) + + @property + def object_data(self): + return { + 'ams-change-handler': 'MyAMS.helpers.select2ChangeHelper', + 'ams-stop-propagation': 'true', + 'ams-select2-helper-type': 'html', + 'ams-select2-helper-url': absolute_url(self.pictograms, self.request, 'get-pictogram-header.html'), + 'ams-select2-helper-target': '#{0}'.format(self.label_id) + } + + +def PictogramSelectFieldWidget(field, request): + return FieldWidget(field, PictogramSelectWidget(request)) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/root/__init__.py --- a/src/pyams_content/root/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/root/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -27,10 +27,11 @@ from pyams_content.root.interfaces import ISiteRootRoles, ISiteRootConfiguration, ISiteRoot, \ ISiteRootToolsConfiguration, ISiteRootBackOfficeConfiguration from pyams_form.interfaces.form import IFormContextPermissionChecker -from pyams_portal.interfaces import IPortalContext -from pyams_security.interfaces import IDefaultProtectionPolicy, IGrantedRoleEvent, ISecurityManager +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 IConfigurationFactory, IBackOfficeConfigurationFactory, ISiteRootFactory +from pyams_utils.interfaces.site import ISiteRootFactory # import packages from persistent import Persistent @@ -39,26 +40,31 @@ from pyams_skin.configuration import Configuration, BackOfficeConfiguration from pyams_skin.skin import UserSkinnableContent from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter +from pyams_utils.factory import factory_config from pyams_utils.registry import get_utility, utility_config from pyams_utils.site import BaseSiteRoot from pyams_utils.traversing import get_parent from pyramid.events import subscriber from zope.interface import implementer +from pyams_content import _ + @implementer(IDefaultProtectionPolicy, ISiteRoot, ISiteRootRoles, IPortalContext, IIllustrationTarget, IHeaderTarget, IFooterTarget, IAlertTarget, IPreviewTarget) class SiteRoot(ProtectedObject, BaseSiteRoot, UserSkinnableContent): """Main site root""" - __roles__ = ('system.Manager', WEBMASTER_ROLE, OPERATOR_ROLE, 'pyams.TemplatesManager') + __roles__ = (SYSTEM_ADMIN_ROLE, WEBMASTER_ROLE, OPERATOR_ROLE, DESIGNER_ROLE) roles_interface = ISiteRootRoles managers = RolePrincipalsFieldProperty(ISiteRootRoles['managers']) webmasters = RolePrincipalsFieldProperty(ISiteRootRoles['webmasters']) operators = RolePrincipalsFieldProperty(ISiteRootRoles['operators']) - templates_managers = RolePrincipalsFieldProperty(ISiteRootRoles['templates_managers']) + designers = RolePrincipalsFieldProperty(ISiteRootRoles['designers']) + + content_name = _("Site root") @utility_config(provides=ISiteRootFactory) @@ -70,30 +76,22 @@ @implementer(ISiteRootConfiguration) +@factory_config(provided=IConfiguration) class SiteRootConfiguration(Configuration): """Site root configuration""" -@adapter_config(context=ISiteRoot, provides=IConfigurationFactory) -def site_root_configuration_factory(context): - return SiteRootConfiguration - - @implementer(ISiteRootBackOfficeConfiguration) +@factory_config(provided=IBackOfficeConfiguration) class SiteRootBackOfficeConfiguration(BackOfficeConfiguration): """Site root back-office configuration""" -@adapter_config(context=ISiteRoot, provides=IBackOfficeConfigurationFactory) -def site_root_back_office_configuration_factory(context): - return SiteRootBackOfficeConfiguration - - @subscriber(IGrantedRoleEvent) def handle_granted_role(event): """Add principals to operators group when a role is granted""" role_id = event.role_id - if (role_id == 'pyams.Operator') or (not role_id.startswith('pyams.')): + if (role_id == OPERATOR_ROLE) or (not role_id.startswith('pyams.')): return root = get_parent(event.object, ISiteRoot) if not root.operators: diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/root/interfaces/__init__.py --- a/src/pyams_content/root/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/root/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,6 +16,9 @@ # import standard library # import interfaces +from pyams_content.interfaces import WEBMASTER_ROLE, OPERATOR_ROLE +from pyams_portal.interfaces import DESIGNER_ROLE +from pyams_security.interfaces import SYSTEM_ADMIN_ROLE from pyams_skin.interfaces.configuration import IConfiguration, IBackOfficeConfiguration from pyams_utils.interfaces.site import ISiteRoot as ISiteRootBase @@ -34,20 +37,20 @@ """Main site roles""" managers = PrincipalsSet(title=_("Site managers"), - role_id='system.Manager', + role_id=SYSTEM_ADMIN_ROLE, required=False) webmasters = PrincipalsSet(title=_("Webmasters"), - role_id='pyams.Webmaster', + role_id=WEBMASTER_ROLE, required=False) - templates_managers = PrincipalsSet(title=_("Templates managers"), - role_id='pyams.TemplatesManager', - required=False) + designers = PrincipalsSet(title=_("Templates managers"), + role_id=DESIGNER_ROLE, + required=False) operators = Principal(title=_("Operators group"), description=_("Name of group containing all roles owners"), - role_id='pyams.Operator', + role_id=OPERATOR_ROLE, required=False) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/root/zmi/__init__.py --- a/src/pyams_content/root/zmi/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/root/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -25,7 +25,8 @@ from pyams_content.skin.zmi.interfaces import IDashboardMenu, IMyDashboardMenu, IAllContentsMenu from pyams_i18n.interfaces import II18n from pyams_skin.interfaces import IInnerPage, IPageHeader -from pyams_skin.interfaces.configuration import IBackOfficeConfiguration +from pyams_skin.interfaces.configuration import IBackOfficeConfiguration, IConfiguration +from pyams_skin.interfaces.container import ITableElementName, ITableElementEditor from pyams_skin.interfaces.viewlet import IBreadcrumbItem from pyams_skin.layer import IPyAMSLayer from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION @@ -45,11 +46,11 @@ from pyams_pagelet.pagelet import pagelet_config from pyams_skin.container import ContainerView from pyams_skin.page import DefaultPageHeaderAdapter -from pyams_skin.table import I18nColumn +from pyams_skin.table import I18nColumn, DefaultElementEditorAdapter from pyams_skin.viewlet.breadcrumb import BreadcrumbItem from pyams_skin.viewlet.menu import MenuItem from pyams_template.template import template_config -from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter +from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter from pyams_utils.list import unique from pyams_utils.registry import get_utility, get_all_utilities_registered_for from pyams_viewlet.manager import viewletmanager_config @@ -77,6 +78,24 @@ label = _("Home") +@adapter_config(context=(ISiteRoot, IPyAMSLayer), provides=ITableElementName) +class SiteRootTableElementNameAdapter(ContextRequestAdapter): + """Site root table element name adapter""" + + @property + def name(self): + configuration = IConfiguration(self.context) + return II18n(configuration).query_attribute('short_title', request=self.request) + + +@adapter_config(context=(ISiteRoot, IAdminLayer, Interface), provides=ITableElementEditor) +class SiteRootTableElementEditorAdapter(DefaultElementEditorAdapter): + """Site root table element editor adapter""" + + view_name = 'admin#site-tree.html' + modal_target = False + + # # Main dashboard menu # @@ -153,6 +172,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = Eq(catalog['parents'], intids.register(tool)) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Any(catalog['workflow_state'], workflow.waiting_states) params = params | query if params else query return filter(self.check_access, @@ -199,6 +219,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = Eq(catalog['parents'], intids.register(tool)) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Any(catalog['workflow_state'], workflow.waiting_states) & \ Eq(catalog['workflow_principal'], self.request.principal.id) params = params | query if params else query @@ -360,6 +381,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Eq(catalog['workflow_state'], workflow.initial_state)) @@ -421,6 +443,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.waiting_states)) @@ -482,6 +505,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.published_states)) @@ -543,6 +567,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.retired_states)) @@ -606,6 +631,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], principal_id), Eq(catalog['role:contributor'], principal_id)), Any(catalog['workflow_state'], workflow.archived_states)) @@ -695,6 +721,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Any(catalog['workflow_state'], workflow.published_states)) params = params | query if params else query return unique(CatalogResultSet(CatalogQuery(catalog).query(params, @@ -800,4 +827,7 @@ weight = 1 def getValue(self, obj): - return self.request.localizer.translate(obj.content_name) + try: + return self.request.localizer.translate(obj.content_name) + except AttributeError: + return '--' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/root/zmi/templates/dashboard.pt --- a/src/pyams_content/root/zmi/templates/dashboard.pt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/root/zmi/templates/dashboard.pt Wed Jun 27 16:42:01 2018 +0200 @@ -25,7 +25,9 @@
@@ -36,7 +38,8 @@
-
+
+ @@ -46,6 +49,6 @@
You are not actually concerned by any content.
-
+
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/blog/__init__.py --- a/src/pyams_content/shared/blog/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/blog/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration import IIllustrationTarget +from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget from pyams_content.component.theme.interfaces import IThemesTarget from pyams_content.features.preview.interfaces import IPreviewTarget @@ -31,8 +31,8 @@ from zope.interface import implementer, provider -@implementer(IWfBlogPost, IParagraphContainerTarget, IThemesTarget, - IIllustrationTarget, IPreviewTarget, IReviewTarget) +@implementer(IWfBlogPost, IParagraphContainerTarget, IThemesTarget, IIllustrationTarget, + ILinkIllustrationTarget, IPreviewTarget, IReviewTarget) class WfBlogPost(WfSharedContent): """Base blog post""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/blog/interfaces/__init__.py --- a/src/pyams_content/shared/blog/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/blog/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,8 +16,8 @@ # import standard library # import interfaces -from pyams_content.shared.common.interfaces import ISharedSite, IBaseSharedTool, IWfSharedContent, ISharedContent, \ - IDeletableElement +from pyams_content.shared.common.interfaces import ISharedSite, IBaseSharedTool, ISharedContent, \ + IDeletableElement, IWfSharedContentPortalContext from pyams_sequence.interfaces import ISequentialIdTarget from pyams_workflow.interfaces import IWorkflowPublicationSupport from zope.container.interfaces import IContainer @@ -33,7 +33,7 @@ BLOG_CONTENT_NAME = _("Blog post") -class IWfBlogPost(IWfSharedContent): +class IWfBlogPost(IWfSharedContentPortalContext): """Blog topic interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/blog/manager.py --- a/src/pyams_content/shared/blog/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/blog/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration import IIllustrationTarget +from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphFactorySettings from pyams_content.component.theme.interfaces import IThemesManagerTarget from pyams_content.features.footer.interfaces import IFooterTarget @@ -27,7 +27,6 @@ from pyams_content.shared.blog.interfaces import IBlogManager, IBlogFolder, IBlogFolderFactory, IBlogManagerFactory from pyams_content.shared.common.interfaces import ISharedContentFactory from pyams_portal.interfaces import IPortalContext -from zope.annotation.interfaces import IAttributeAnnotatable from zope.component.interfaces import ISite from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent @@ -55,7 +54,7 @@ @implementer(IBlogManager, IParagraphFactorySettings, IThemesManagerTarget, IPictogramManagerTarget, - IIllustrationTarget, IPortalContext, IHeaderTarget, IFooterTarget, IPreviewTarget, IAttributeAnnotatable) + IIllustrationTarget, ILinkIllustrationTarget, IHeaderTarget, IFooterTarget, IPortalContext, IPreviewTarget) class BlogManager(Folder, BaseSharedTool, UserSkinnableContent): """Nlog manager class""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/blog/zmi/manager.py --- a/src/pyams_content/shared/blog/zmi/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/blog/zmi/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -186,6 +186,6 @@ def updateWidgets(self, prefix=None): super(BlogManagerWorkflowPublicationEditForm, self).updateWidgets(prefix) if 'publication_effective_date' in self.widgets: - widget = self.widgets['publication_effective_date'] - if not widget.value: - widget.value = tztime(datetime.utcnow()).strftime('%d/%m/%y %H:%M') + pub_info = IWorkflowPublicationInfo(self.context) + if pub_info.publication_effective_date is None: + self.widgets['publication_effective_date'].value = tztime(datetime.utcnow()).strftime('%d/%m/%y %H:%M') diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/__init__.py --- a/src/pyams_content/shared/common/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -17,12 +17,14 @@ # import interfaces from hypatia.interfaces import ICatalog -from pyams_content.interfaces import IBaseContentInfo +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 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 @@ -113,12 +115,13 @@ class WfSharedContent(ProtectedObject, Persistent, Contained, I18nManagerMixin): """Shared data content class""" - __roles__ = ('pyams.Owner', 'pyams.Manager', 'pyams.Contributors', 'pyams.Reader', 'pyams.Guest') + __roles__ = (OWNER_ROLE, MANAGER_ROLE, CONTRIBUTOR_ROLE, DESIGNER_ROLE, READER_ROLE, GUEST_ROLE) roles_interface = IWfSharedContentRoles owner = RolePrincipalsFieldProperty(IWfSharedContentRoles['owner']) managers = RolePrincipalsFieldProperty(IWfSharedContentRoles['managers']) contributors = RolePrincipalsFieldProperty(IWfSharedContentRoles['contributors']) + designers = RolePrincipalsFieldProperty(IWfSharedContentRoles['designers']) readers = RolePrincipalsFieldProperty(IWfSharedContentRoles['readers']) guests = RolePrincipalsFieldProperty(IWfSharedContentRoles['guests']) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/interfaces/__init__.py --- a/src/pyams_content/shared/common/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -18,7 +18,7 @@ # 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_content.root.interfaces import ISiteRoot +from pyams_portal.interfaces import IPortalContext, DESIGNER_ROLE from pyams_workflow.interfaces import IWorkflowManagedContent from zope.container.interfaces import IContainer @@ -65,17 +65,22 @@ role_id=CONTRIBUTOR_ROLE, required=False) + designers = PrincipalsSet(title=_("Designers"), + description=_("Designers are users which are allowed to manage presentation templates"), + role_id=DESIGNER_ROLE, + required=False) + class ISharedSite(IBaseContent, IDeletableElement): """Shared site interface""" - containers(ISiteRoot) + containers('pyams_content.root.interfaces.ISiteRoot') class ISharedToolContainer(IBaseContent, IContainer): """Shared tools container""" - containers(ISiteRoot) + containers('pyams_content.root.interfaces.ISiteRoot') contains('.ISharedTool') @@ -102,6 +107,10 @@ shared_content_factory = Attribute("Shared data factory") +class ISharedToolPortalContext(ISharedTool, IPortalContext): + """Shared tool with portal context""" + + class ISharedToolRoles(IBaseContentManagerRoles): """Shared tool roles""" @@ -157,6 +166,10 @@ required=False) +class IWfSharedContentPortalContext(IWfSharedContent, IPortalContext): + """Shared content with portal support""" + + class IWfSharedContentFactory(Interface): """Shared content factory interface""" @@ -180,9 +193,14 @@ contributors = PrincipalsSet(title=_("Contributors"), description=_("Contributors are users which are allowed to update this content in " "addition to it's owner"), - role_id='pyams.Contributor', + role_id=CONTRIBUTOR_ROLE, required=False) + designers = PrincipalsSet(title=_("Designers"), + description=_("Designers are users which are allowed to manage presentation templates"), + role_id=DESIGNER_ROLE, + required=False) + readers = PrincipalsSet(title=_("Readers"), description=_("Readers are users which are asked to verify and comment contents before " "they are published"), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/interfaces/types.py --- a/src/pyams_content/shared/common/interfaces/types.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/interfaces/types.py Wed Jun 27 16:42:01 2018 +0200 @@ -17,6 +17,7 @@ # import interfaces from pyams_content.shared.common.interfaces import ISharedTool +from pyams_portal.interfaces import IPortalContext from zope.container.interfaces import IContainer from zope.location.interfaces import ILocation @@ -100,3 +101,7 @@ """Shared tool containing typed data""" shared_content_types_fields = Attribute("Content fields interface") + + +class ITypedSharedToolPortalContext(ITypedSharedTool, IPortalContext): + """Typed shared tool with portal context""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/manager.py --- a/src/pyams_content/shared/common/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,6 +19,7 @@ from pyams_content.interfaces import WEBMASTER_ROLE, PILOT_ROLE, MANAGER_ROLE, CONTRIBUTOR_ROLE from pyams_content.shared.common.interfaces import ISharedToolContainer, IBaseSharedTool, ISharedTool, ISharedToolRoles, \ ISharedContentFactory +from pyams_portal.interfaces import DESIGNER_ROLE from pyams_security.interfaces import IDefaultProtectionPolicy from pyams_workflow.interfaces import IWorkflow from zope.annotation.interfaces import IAttributeAnnotatable @@ -42,11 +43,11 @@ short_name = FieldProperty(ISharedToolContainer['short_name']) -@implementer(IDefaultProtectionPolicy, IBaseSharedTool, ISharedToolRoles, IAttributeAnnotatable) +@implementer(IDefaultProtectionPolicy, IBaseSharedTool, ISharedToolRoles) class BaseSharedTool(ProtectedObject, I18nManagerMixin): """Base shared tool class""" - __roles__ = (WEBMASTER_ROLE, PILOT_ROLE, MANAGER_ROLE, CONTRIBUTOR_ROLE) + __roles__ = (WEBMASTER_ROLE, PILOT_ROLE, MANAGER_ROLE, DESIGNER_ROLE, CONTRIBUTOR_ROLE) roles_interface = ISharedToolRoles @@ -54,6 +55,7 @@ pilots = RolePrincipalsFieldProperty(ISharedToolRoles['pilots']) managers = RolePrincipalsFieldProperty(ISharedToolRoles['managers']) contributors = RolePrincipalsFieldProperty(ISharedToolRoles['contributors']) + designers = RolePrincipalsFieldProperty(ISharedToolRoles['designers']) title = FieldProperty(IBaseSharedTool['title']) short_name = FieldProperty(IBaseSharedTool['short_name']) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portal.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portal.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,43 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.shared.common.interfaces import IBaseSharedTool, IWfSharedContentPortalContext +from pyams_portal.interfaces import IPortalPage, PORTAL_PAGE_KEY + +# import packages +from pyams_portal.page import PortalPage +from pyams_utils.adapter import adapter_config, get_annotation_adapter +from pyams_utils.traversing import get_parent + + +class SharedContentPortalPage(PortalPage): + """Shared content portal page""" + + @property + def can_inherit(self): + return IPortalPage(self.parent).template is not None + + @property + def parent(self): + return get_parent(self, IBaseSharedTool, allow_context=False) + + +@adapter_config(context=IWfSharedContentPortalContext, provides=IPortalPage) +def shared_content_portal_page_adapter(context): + """Shared content portal page adapter""" + return get_annotation_adapter(context, PORTAL_PAGE_KEY, SharedContentPortalPage) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portlet/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,19 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +# import standard library + +# import interfaces + +# import packages diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portlet/content/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/content/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,46 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.shared.common.portlet.content.interfaces import ISharedContentPortletSettings +from pyams_utils.interfaces import VIEW_PERMISSION + +# import packages +from pyams_portal.portlet import PortletSettings, portlet_config, Portlet +from pyams_utils.factory import factory_config +from zope.interface import implementer + +from pyams_content import _ + + +SHARED_CONTENT_PORTLET_NAME = 'pyams_content.portlet.content' + + +@implementer(ISharedContentPortletSettings) +@factory_config(provided=ISharedContentPortletSettings) +class SharedContentPortletSettings(PortletSettings): + """Shared content portlet persistent settings""" + + +@portlet_config(permission=VIEW_PERMISSION) +class SharedContentPortlet(Portlet): + """Shared content portlet""" + + name = SHARED_CONTENT_PORTLET_NAME + label = _("Context content") + + settings_factory = ISharedContentPortletSettings diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portlet/content/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/content/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,25 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_portal.interfaces import IPortletSettings + +# import packages + + +class ISharedContentPortletSettings(IPortletSettings): + """Shared content portlet settings interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portlet/content/skin/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/content/skin/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,54 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.shared.common.portlet.content.interfaces import ISharedContentPortletSettings +from pyams_content.features.renderer.interfaces import ISharedContentRenderer +from pyams_portal.interfaces import IPortalContext, IPortletRenderer +from pyams_skin.layer import IPyAMSLayer + +# import packages +from pyams_portal.portlet import PortletRenderer +from pyams_utils.adapter import adapter_config +from zope.interface import Interface + +from pyams_content import _ + + +@adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, ISharedContentPortletSettings), + provides=IPortletRenderer) +class SharedContentPortletRenderer(PortletRenderer): + """Shared content portlet renderer""" + + label = _("Default content renderer") + + def __init__(self, context, request, view, settings): + super(SharedContentPortletRenderer, self).__init__(context, request, view, settings) + registry = self.request.registry + self.renderers = [adapter for name, adapter in sorted(registry.getAdapters((self.context, self.request), + ISharedContentRenderer), + key=lambda x: x[1].weight)] + + 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 diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portlet/content/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/content/zmi/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,52 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.shared.common.portlet.content.interfaces import ISharedContentPortletSettings +from pyams_pagelet.interfaces import IPagelet +from pyams_portal.interfaces import IPortletPreviewer +from pyams_skin.layer import IPyAMSLayer +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION + +# import packages +from pyams_form.form import AJAXEditForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_portal.portlet import PortletPreviewer +from pyams_portal.zmi.portlet import PortletSettingsEditor +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from zope.interface import Interface + + +@pagelet_config(name='properties.html', context=ISharedContentPortletSettings, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +class SharedContentPortletSettingsEditor(PortletSettingsEditor): + """Shared content portlet settings editor""" + + settings = ISharedContentPortletSettings + + +@adapter_config(name='properties.json', context=(ISharedContentPortletSettings, IPyAMSLayer), provides=IPagelet) +class SharedContentPortletConfigurationAJAXEditor(AJAXEditForm, SharedContentPortletSettingsEditor): + """Shared content portlet settings editor, JSON renderer""" + + +@adapter_config(context=(Interface, IPyAMSLayer, Interface, ISharedContentPortletSettings), + provides=IPortletPreviewer) +@template_config(template='preview.pt', layer=IPyAMSLayer) +class SharedContentPortletPreviewer(PortletPreviewer): + """Shared content portlet previewer""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/portlet/content/zmi/preview.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/content/zmi/preview.pt Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,3 @@ + + This is where the content will be displayed!! + diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/skin/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/skin/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/skin/oid.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/skin/oid.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,56 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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_sequence.interfaces import ISequentialIntIds +from pyams_skin.layer import IPyAMSUserLayer +from pyams_utils.interfaces.url import DISPLAY_CONTEXT +from pyams_workflow.interfaces import IWorkflow, IWorkflowVersions +from zope.traversing.interfaces import ITraversable + +# import packages +from pyams_sequence.utility import get_reference_target +from pyams_utils.adapter import adapter_config, ContextRequestAdapter +from pyams_utils.registry import get_utility +from pyramid.exceptions import NotFound +from zope.interface import Interface + + +@adapter_config(name='oid', context=(Interface, IPyAMSUserLayer), provides=ITraversable) +class OidTraverser(ContextRequestAdapter): + """++oid++ traverser""" + + def traverse(self, name, furtherpath=None): + if not name: + raise NotFound() + if '::' in name: + oid, label = name.split('::', 1) + else: + oid = name + sequence = get_utility(ISequentialIntIds) + reference = sequence.get_full_oid(oid) + target = get_reference_target(reference) + if target is not None: + workflow = IWorkflow(target, None) + if workflow is not None: + versions = IWorkflowVersions(target).get_versions(workflow.published_states, sort=True) + if versions: + target = versions[-1] + if target is not None: + self.request.annotations[DISPLAY_CONTEXT] = self.context + return target + raise NotFound() diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/skin/url.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/skin/url.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,37 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.shared.common import IWfSharedContent +from pyams_sequence.interfaces import ISequentialIdInfo +from pyams_skin.layer import IPyAMSUserLayer +from pyams_utils.interfaces.url import IRelativeURL + +# import packages +from pyams_utils.adapter import adapter_config, ContextRequestAdapter +from pyams_utils.url import absolute_url + + +@adapter_config(context=(IWfSharedContent, IPyAMSUserLayer), provides=IRelativeURL) +class SharedContentRelativeUrlAdapter(ContextRequestAdapter): + """Shared content relative URL adapter""" + + def get_url(self, display_context=None, view_name=None, query=None): + return absolute_url(display_context, self.request, + '++oid++{0}::{1}.html'.format( + ISequentialIdInfo(self.context).get_base_oid().strip(), + self.context.content_url)) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/dashboard.py --- a/src/pyams_content/shared/common/zmi/dashboard.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/dashboard.py Wed Jun 27 16:42:01 2018 +0200 @@ -340,6 +340,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = Eq(catalog['parents'], intids.register(self.context)) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Any(catalog['workflow_state'], workflow.waiting_states) return filter(self.check_access, unique(map(lambda x: sorted(IWorkflowVersions(x).get_versions(IWorkflowState(x).state), @@ -383,6 +384,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = Eq(catalog['parents'], intids.register(self.context)) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Any(catalog['workflow_state'], workflow.waiting_states) & \ Eq(catalog['workflow_principal'], self.request.principal.id) return unique(map(lambda x: sorted(IWorkflowVersions(x).get_versions(IWorkflowState(x).state), @@ -576,6 +578,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Eq(catalog['workflow_state'], workflow.initial_state)) @@ -638,6 +641,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.waiting_states)) @@ -700,6 +704,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.published_states)) @@ -762,6 +767,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.retired_states)) @@ -826,6 +832,7 @@ principal_id = self.request.principal.id workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Or(Eq(catalog['role:owner'], principal_id), Eq(catalog['role:contributor'], principal_id)), Any(catalog['workflow_state'], workflow.archived_states)) @@ -916,6 +923,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ Any(catalog['workflow_state'], workflow.published_states)) return unique(CatalogResultSet(CatalogQuery(catalog).query(params, limit=50, diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/manager.py --- a/src/pyams_content/shared/common/zmi/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -120,7 +120,7 @@ class SharedToolPropertiesHelpAdapter(FormHelp): """Shared tool properties help adapter""" - permission = MANAGE_TOOL_PERMISSION + permission = MANAGE_SYSTEM_PERMISSION header = _("WARNING") status = 'danger' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/portal.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/zmi/portal.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,72 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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.shared.common import IWfSharedContent +from pyams_content.shared.common.interfaces import IWfSharedContentPortalContext, ISharedToolPortalContext, ISharedTool +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_pagelet.pagelet import pagelet_config +from pyams_portal.zmi.page import PortalContextTemplatePropertiesEditForm +from pyams_utils.adapter import adapter_config + +from pyams_content import _ + + +@pagelet_config(name='template-properties.html', context=ISharedToolPortalContext, layer=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION) +@pagelet_config(name='template-properties.html', context=ITypedSharedToolPortalContext, layer=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION) +@ajax_config(name='template-properties.json', context=ISharedToolPortalContext, layer=IPyAMSLayer) +@ajax_config(name='template-properties.json', context=ITypedSharedToolPortalContext, layer=IPyAMSLayer) +class SharedToolTemplatePropertiesEditForm(PortalContextTemplatePropertiesEditForm): + """Shared content template properties edit form""" + + legend = _("Edit default template properties") + + +@adapter_config(context=(ISharedToolPortalContext, IAdminLayer, SharedToolTemplatePropertiesEditForm), + provides=IFormHelp) +@adapter_config(context=(ITypedSharedToolPortalContext, IAdminLayer, SharedToolTemplatePropertiesEditForm), + provides=IFormHelp) +class SharedToolPortalContextPropertiesEditFormHelpAdapter(FormHelp): + """Shared tool template properties edit form help adapter""" + + message = _("**This form allows you to select shared content default template.**\n" + "\n" + "If you choose to use a shared template, you can only adjust settings of " + "each portlet individually but can't change portlets list or page configuration.\n" + "\n" + "If you use a local template, you can define a whole custom " + "configuration but the template definition can't be reused anywhere...""") + message_format = 'rest' + + +@pagelet_config(name='template-properties.html', context=IWfSharedContentPortalContext, layer=IPyAMSLayer, + permission=MANAGE_TEMPLATE_PERMISSION) +@ajax_config(name='template-properties.json', context=IWfSharedContent, layer=IPyAMSLayer) +class SharedContentTemplatePropertiesEditForm(PortalContextTemplatePropertiesEditForm): + """Shared content template properties edit form""" + + override_legend = _("Override tool default template") diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/rename.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/zmi/rename.py Wed Jun 27 16:42:01 2018 +0200 @@ -0,0 +1,121 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# 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 import MANAGE_SITE_PERMISSION +from pyams_content.shared.common.interfaces import ISharedSite +from pyams_content.shared.site.interfaces import ISiteFolder +from pyams_content.skin.zmi.interfaces import ISiteTreeTable +from pyams_skin.interfaces.viewlet import ITableItemColumnActionsMenu, IContextActions +from pyams_skin.layer import IPyAMSLayer +from z3c.form.interfaces import IDataExtractedEvent +from zope.location.interfaces import ILocation + +# import packages +from pyams_form.form import ajax_config +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.viewlet.toolbar import ToolbarMenuItem +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 AdminDialogEditForm +from pyramid.events import subscriber +from z3c.form import field +from zope.interface import Interface, Invalid + +from pyams_content import _ + + +# +# Site container rename view +# + +@viewlet_config(name='rename-item.menu', context=ISharedSite, layer=IPyAMSLayer, + view=ISiteTreeTable, manager=ITableItemColumnActionsMenu, + permission=MANAGE_SITE_PERMISSION, weight=900) +@viewlet_config(name='rename-item.menu', context=ISharedSite, layer=IPyAMSLayer, + view=Interface, manager=IContextActions, + permission=MANAGE_SITE_PERMISSION, weight=900) +@viewlet_config(name='rename-item.menu', context=ISiteFolder, layer=IPyAMSLayer, + view=ISiteTreeTable, manager=ITableItemColumnActionsMenu, + permission=MANAGE_SITE_PERMISSION, weight=900) +@viewlet_config(name='rename-item.menu', context=ISiteFolder, layer=IPyAMSLayer, + view=Interface, manager=IContextActions, + permission=MANAGE_SITE_PERMISSION, weight=900) +class SiteContainerRenameMenu(ToolbarMenuItem): + """Site container rename menu""" + + label = _("Change URL...") + label_css_class = 'fa fa-fw fa-edit' + url = 'rename-item.html' + modal_target = True + + +@pagelet_config(name='rename-item.html', context=ISharedSite, layer=IPyAMSLayer, + permission=MANAGE_SITE_PERMISSION) +@ajax_config(name='rename-item.json', context=ISharedSite, layer=IPyAMSLayer) +@pagelet_config(name='rename-item.html', context=ISiteFolder, layer=IPyAMSLayer, + permission=MANAGE_SITE_PERMISSION) +@ajax_config(name='rename-item.json', context=ISiteFolder, layer=IPyAMSLayer) +class SiteContainerRenameForm(AdminDialogEditForm): + """Site container rename form""" + + prefix = 'rename_item.' + + legend = _("Change item URL") + + fields = field.Fields(ILocation).select('__name__') + edit_permission = MANAGE_SITE_PERMISSION + + def updateWidgets(self, prefix=None): + super(SiteContainerRenameForm, self).updateWidgets(prefix) + self.widgets['__name__'].label = _("Item URL part") + self.widgets['__name__'].description = _("URL part used to access this content") + + def update_content(self, content, data): + data = data.get(self, data) + old_name = content.__name__ + new_name = data['__name__'] = translate_string(data['__name__'], spaces='-', keep_chars='-') + changes = super(SiteContainerRenameForm, self).update_content(content, data) + if changes: + # revert rename to adjust container properties + content.__name__ = old_name + parent = content.__parent__ + parent[new_name] = content + del parent[old_name] + return changes + + def get_ajax_output(self, changes): + if changes: + return { + 'status': 'redirect', + 'location': absolute_url(self.context, self.request, 'admin'), + 'smallbox': { + 'status': 'success', + 'message': self.request.localizer.translate(self.successMessage) + } + } + else: + return super(SiteContainerRenameForm, self).get_ajax_output(changes) + + +@subscriber(IDataExtractedEvent, form_selector=SiteContainerRenameForm) +def handle_rename_form_data_extraction(event): + """Handle rename form data extraction""" + name = event.data.get('__name__') + if not name: + event.form.widgets.errors += (Invalid(_("You must provide an URL for this item!")),) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/security.py --- a/src/pyams_content/shared/common/zmi/security.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/security.py Wed Jun 27 16:42:01 2018 +0200 @@ -115,7 +115,7 @@ class SharedToolContributorsRestrictionsChecksColumn(I18nColumn, GetAttrColumn): """Shared tool contributor enabled publication checks column""" - _header = _("Publication checks") + _header = _("Activated publication checks?") weight = 20 cssClasses = {'td': 'center'} @@ -267,7 +267,7 @@ class SharedToolManagerRestrictionsChecksColumn(I18nColumn, GetAttrColumn): """Shared tool manager enabled publication checks column""" - _header = _("Publication checks") + _header = _("Activated publication checks?") weight = 40 cssClasses = {'td': 'center'} diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/templates/dashboard.pt --- a/src/pyams_content/shared/common/zmi/templates/dashboard.pt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/templates/dashboard.pt Wed Jun 27 16:42:01 2018 +0200 @@ -25,7 +25,9 @@
@@ -36,7 +38,8 @@
-
+
+ @@ -46,6 +49,6 @@
You are not actually concerned by any content.
-
+ diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/types.py --- a/src/pyams_content/shared/common/zmi/types.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/types.py Wed Jun 27 16:42:01 2018 +0200 @@ -146,7 +146,9 @@ def renderCell(self, item): return '' \ + ' data-ams-click-handler="MyAMS.skin.switchCellContent" ' \ + ' data-ams-switch-handler="get-subtypes-table.json" ' \ + ' data-ams-switch-target=".subtypes">' \ ' ' \ ' ' \ ' ' \ @@ -315,8 +317,6 @@ attributes = super(DatatypeSubtypesTable, self).data_attributes attributes['table'] = { 'id': self.id, - 'data-ams-plugins': 'pyams_content', - 'data-ams-plugin-pyams_content-src': get_resource_path(pyams_content), 'data-ams-location': absolute_url(self.context, self.request), 'data-ams-tablednd-drag-handle': 'td.sorter', 'data-ams-tablednd-drop-target': 'set-subtypes-order.json' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/common/zmi/workflow.py --- a/src/pyams_content/shared/common/zmi/workflow.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/workflow.py Wed Jun 27 16:42:01 2018 +0200 @@ -9,12 +9,6 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # -from z3c.form.browser.radio import RadioWidget -from z3c.form.widget import FieldWidget - -from pyams_form.group import NamedWidgetsGroup -from pyams_form.interfaces import IFormLayer -from pyams_form.widget import widgettemplate_config __docformat__ = 'restructuredtext' @@ -26,6 +20,7 @@ from pyams_content.interfaces import PUBLISH_CONTENT_PERMISSION, CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION from pyams_content.shared.common.interfaces import IWfSharedContent, IBaseSharedTool, ISharedContent, \ IContributorRestrictions, IManagerRestrictions +from pyams_form.interfaces import IFormLayer from pyams_form.interfaces.form import IWidgetsPrefixViewletsManager, IFormSuffixViewletsManager, IInnerSubForm from pyams_security.interfaces import ISecurityManager from pyams_skin.layer import IPyAMSLayer @@ -38,6 +33,7 @@ from pyams_content.workflow import DRAFT, DELETED from pyams_form.form import AJAXAddForm, ajax_config from pyams_form.schema import CloseButton +from pyams_form.widget import widgettemplate_config from pyams_pagelet.pagelet import pagelet_config from pyams_template.template import template_config from pyams_utils.adapter import adapter_config @@ -48,11 +44,12 @@ from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config, Viewlet -from pyams_workflow.zmi.transition import WorkflowContentTransitionForm, WorkflowContentTransitionAJAXForm +from pyams_workflow.zmi.transition import WorkflowContentTransitionForm from pyams_zmi.form import InnerAdminAddForm from pyramid.events import subscriber -from pyramid.view import view_config from z3c.form import field, button +from z3c.form.browser.radio import RadioWidget +from z3c.form.widget import FieldWidget from zope.interface import Interface, Invalid from zope.schema import Bool @@ -129,7 +126,7 @@ @pagelet_config(name='wf-propose.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-propose.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationRequestForm(WorkflowContentTransitionForm): """Shared content publication request form""" @@ -216,7 +213,7 @@ @pagelet_config(name='wf-cancel-propose.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-cancel-propose.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationRequestCancelForm(WorkflowContentTransitionForm): """Shared content publication request cancel form""" @@ -256,7 +253,7 @@ @pagelet_config(name='wf-refuse.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=PUBLISH_CONTENT_PERMISSION) @ajax_config(name='wf-refuse.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=PUBLISH_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=PUBLISH_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationRequestRefuseForm(WorkflowContentTransitionForm): """Shared content publication request refuse form""" @@ -310,7 +307,7 @@ @pagelet_config(name='wf-publish.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=PUBLISH_CONTENT_PERMISSION) @ajax_config(name='wf-publish.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=PUBLISH_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=PUBLISH_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationForm(WorkflowContentTransitionForm): """Shared content publication form""" @@ -399,7 +396,7 @@ @pagelet_config(name='wf-retiring.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-retiring.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationRetireRequestForm(WorkflowContentTransitionForm): """Shared content publication request refuse form""" @@ -455,7 +452,7 @@ @pagelet_config(name='wf-cancel-retiring.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-cancel-retiring.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationRetireCancelForm(WorkflowContentTransitionForm): """Shared content publication retire request cancel form""" @@ -495,7 +492,7 @@ @pagelet_config(name='wf-retire.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=PUBLISH_CONTENT_PERMISSION) @ajax_config(name='wf-retire.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=PUBLISH_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=PUBLISH_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationRetireForm(WorkflowContentTransitionForm): """Shared content publication retire form""" @@ -536,7 +533,7 @@ @pagelet_config(name='wf-archiving.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-archiving.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationArchiveRequestForm(WorkflowContentTransitionForm): """Shared content publication request archive form""" @@ -579,7 +576,7 @@ @pagelet_config(name='wf-cancel-archiving.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-cancel-archiving.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationArchiveCancelForm(WorkflowContentTransitionForm): """Shared content publication archive request cancel form""" @@ -619,7 +616,7 @@ @pagelet_config(name='wf-archive.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=PUBLISH_CONTENT_PERMISSION) @ajax_config(name='wf-archive.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=PUBLISH_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=PUBLISH_CONTENT_PERMISSION, base=AJAXAddForm) class PublicationArchiveForm(WorkflowContentTransitionForm): """Shared content publication archive form""" @@ -711,7 +708,7 @@ @pagelet_config(name='wf-delete.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='wf-delete.json', context=IWfSharedContent, layer=IPyAMSLayer, - permission=MANAGE_CONTENT_PERMISSION, base=WorkflowContentTransitionAJAXForm) + permission=MANAGE_CONTENT_PERMISSION, base=AJAXAddForm) class SharedContentDeleteForm(WorkflowContentTransitionForm): """Shared content delete form""" @@ -835,7 +832,7 @@ (manager_restrictions.check_access(context, request=request)) and \ (not manager_restrictions.publication_checks): return None - if isinstance(form, PublicationForm): + if isinstance(form, PublicationRequestForm): restrictions = IContributorRestrictions(context, None) if restrictions is not None: contributor_restrictions = restrictions.get_restrictions(principal_id) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/form/__init__.py diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/form/interfaces/__init__.py --- a/src/pyams_content/shared/form/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/form/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,8 @@ # import standard library # import interfaces -from pyams_content.shared.common.interfaces import ISharedTool, IWfSharedContent, ISharedContent +from pyams_content.shared.common.interfaces import ISharedContent, IWfSharedContentPortalContext, \ + ISharedToolPortalContext from zope.annotation.interfaces import IAttributeAnnotatable from zope.container.interfaces import IContainer, IContained @@ -36,7 +37,7 @@ FORM_FIELD_CONTAINER_KEY = 'pyams_content.shared.form_fields' -class IFormsManager(ISharedTool): +class IFormsManager(ISharedToolPortalContext): """Forms manager interface""" @@ -115,7 +116,7 @@ """Form fields container target marker interface""" -class IWfForm(IWfSharedContent): +class IWfForm(IWfSharedContentPortalContext): """Form interface""" user_title = I18nTextLineField(title=_("Form title"), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/form/manager.py --- a/src/pyams_content/shared/form/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/form/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -18,7 +18,7 @@ # import interfaces from pyams_content.shared.common.interfaces import ISharedContentFactory from pyams_content.shared.form.interfaces import IFormsManager, FORM_CONTENT_TYPE, IFormsManagerFactory -from zope.annotation.interfaces import IAttributeAnnotatable +from pyams_portal.interfaces import IPortalContext from zope.component.interfaces import ISite from zope.lifecycleevent.interfaces import IObjectAddedEvent @@ -32,7 +32,7 @@ from zope.interface import implementer -@implementer(IFormsManager, IAttributeAnnotatable) +@implementer(IFormsManager) class FormsManager(SharedTool): """Forms manager class""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/form/zmi/render.py --- a/src/pyams_content/shared/form/zmi/render.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/form/zmi/render.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.features.renderer.interfaces import IContentRenderer +from pyams_content.features.renderer.interfaces import ISharedContentRenderer from pyams_content.shared.form.interfaces import IFormFieldContainerTarget, IFormFieldContainer from pyams_form.interfaces.form import IFormHelp from pyams_i18n.interfaces import II18n @@ -77,7 +77,7 @@ @adapter_config(name='form-render', context=(IFormFieldContainerTarget, IPyAMSLayer), - provides=IContentRenderer) + provides=ISharedContentRenderer) class FormFieldContainerRenderer(BaseContentRenderer): """Form field container renderer""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/imagemap/zmi/area.py --- a/src/pyams_content/shared/imagemap/zmi/area.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/imagemap/zmi/area.py Wed Jun 27 16:42:01 2018 +0200 @@ -9,6 +9,8 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # +from pyams_skin.event import get_json_table_row_refresh_event +from pyams_utils.traversing import get_parent __docformat__ = 'restructuredtext' @@ -24,7 +26,7 @@ # import packages from pyams_content.shared.imagemap import ImageMapArea -from pyams_content.shared.imagemap.zmi.container import ImagemapAreasContainerView +from pyams_content.shared.imagemap.zmi.container import ImagemapAreasContainerView, ImagemapAreasTable from pyams_content.shared.imagemap.zmi.widget import ImgareaInputFieldWidget from pyams_form.form import AJAXAddForm, ajax_config from pyams_pagelet.pagelet import pagelet_config @@ -63,6 +65,9 @@ legend = _("Add new image area") + label_css_class = 'control-label col-md-2' + input_css_class = 'col-md-10' + @property def dialog_class(self): image = II18n(self.context).query_attribute('image', request=self.request) @@ -101,6 +106,9 @@ legend = _("Edit image map properties") + label_css_class = 'control-label col-md-2' + input_css_class = 'col-md-10' + @property def dialog_class(self): image = II18n(self.context.__parent__).query_attribute('image', request=self.request) @@ -119,3 +127,11 @@ fields['area'].widgetFactory = ImgareaInputFieldWidget edit_permission = MANAGE_CONTENT_PERMISSION + + def get_ajax_output(self, changes): + output = super(self.__class__, self).get_ajax_output(changes) + if changes: + container = get_parent(self.context, IWfImageMap) + output.setdefault('events', []).append( + get_json_table_row_refresh_event(container, self.request, ImagemapAreasTable, self.context)) + return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/imagemap/zmi/container.py --- a/src/pyams_content/shared/imagemap/zmi/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/imagemap/zmi/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -89,11 +89,11 @@ @property def data_attributes(self): attributes = super(ImagemapAreasTable, self).data_attributes - attributes['table'] = { + attributes.setdefault('table', {}).update({ 'data-ams-location': absolute_url(self.context, self.request), 'data-ams-datatable-sort': 'false', 'data-ams-datatable-pagination': 'false' - } + }) return attributes @reify diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/imagemap/zmi/templates/paragraph-render.pt --- a/src/pyams_content/shared/imagemap/zmi/templates/paragraph-render.pt Wed Jun 27 16:34:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -

title

-
- - - - - - - - -
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/imagemap/zmi/templates/render.pt --- a/src/pyams_content/shared/imagemap/zmi/templates/render.pt Wed Jun 27 16:34:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -
- - - - - - - - -
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/news/__init__.py --- a/src/pyams_content/shared/news/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/news/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration import IIllustrationTarget +from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget from pyams_content.component.theme.interfaces import IThemesTarget from pyams_content.features.preview.interfaces import IPreviewTarget @@ -30,7 +30,7 @@ from zope.interface import implementer, provider -@implementer(IWfNewsEvent, IIllustrationTarget, IParagraphContainerTarget, IThemesTarget, +@implementer(IWfNewsEvent, IIllustrationTarget, ILinkIllustrationTarget, IParagraphContainerTarget, IThemesTarget, IPreviewTarget, IReviewTarget) class WfNewsEvent(WfSharedContent): """Base news event""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/news/interfaces/__init__.py --- a/src/pyams_content/shared/news/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/news/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,8 @@ # import standard library # import interfaces -from pyams_content.shared.common.interfaces import ISharedTool, IWfSharedContent, ISharedContent +from pyams_content.shared.common.interfaces import ISharedContent, \ + IWfSharedContentPortalContext, ISharedToolPortalContext # import packages from zope.interface import Interface @@ -28,7 +29,7 @@ NEWS_CONTENT_NAME = _("News topic") -class INewsManager(ISharedTool): +class INewsManager(ISharedToolPortalContext): """News manager interface""" @@ -36,7 +37,7 @@ """News manager factory interface""" -class IWfNewsEvent(IWfSharedContent): +class IWfNewsEvent(IWfSharedContentPortalContext): """News event interface""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/news/manager.py diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/__init__.py --- a/src/pyams_content/shared/site/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration import IIllustrationTarget +from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget from pyams_content.component.theme.interfaces import IThemesTarget from pyams_content.features.preview.interfaces import IPreviewTarget @@ -31,8 +31,8 @@ from zope.interface import implementer, provider -@implementer(IWfTopic, IParagraphContainerTarget, IThemesTarget, - IIllustrationTarget, IPreviewTarget, IReviewTarget) +@implementer(IWfTopic, IIllustrationTarget, ILinkIllustrationTarget, IParagraphContainerTarget, + IThemesTarget, IPreviewTarget, IReviewTarget) class WfTopic(WfSharedContent): """Base topic""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/folder.py --- a/src/pyams_content/shared/site/folder.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/folder.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration import IIllustrationTarget +from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.interfaces import MANAGE_SITE_PERMISSION from pyams_content.shared.site.interfaces import ISiteFolder, ISiteManager, ISiteFolderRoles @@ -24,7 +24,6 @@ from pyams_i18n.interfaces import II18n from pyams_portal.interfaces import IPortalContext from pyams_security.interfaces import IDefaultProtectionPolicy -from zope.annotation.interfaces import IAttributeAnnotatable from zope.intid.interfaces import IIntIds # import packages @@ -43,9 +42,11 @@ from pyams_content import _ +from pyams_content import _ + @implementer(IDefaultProtectionPolicy, ISiteFolder, ISiteFolderRoles, - IIllustrationTarget, IPortalContext, IPreviewTarget, IAttributeAnnotatable) + IIllustrationTarget, ILinkIllustrationTarget, IPortalContext, IPreviewTarget) class SiteFolder(SiteContainerMixin, OrderedContainer, BaseSharedTool): """Site folder persistent class""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/interfaces/__init__.py --- a/src/pyams_content/shared/site/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,11 +19,12 @@ from pyams_content.interfaces import IBaseContent from pyams_sequence.interfaces import ISequentialIdTarget, IInternalReference from pyams_workflow.interfaces import IWorkflowPublicationSupport +from zope.annotation.interfaces import IAttributeAnnotatable from zope.container.interfaces import IContainer, IContained # import packages -from pyams_content.shared.common.interfaces import ISharedSite, IWfSharedContent, ISharedContent, \ - IBaseContentManagerRoles, IBaseSharedTool, IDeletableElement +from pyams_content.shared.common.interfaces import ISharedSite, ISharedContent, \ + IBaseContentManagerRoles, IBaseSharedTool, IDeletableElement, IWfSharedContentPortalContext from pyams_i18n.schema import I18nTextLineField, I18nTextField from zope.container.constraints import containers, contains from zope.interface import Interface, Attribute @@ -95,7 +96,7 @@ TOPIC_CONTENT_NAME = _("Topic") -class IWfTopic(IWfSharedContent): +class IWfTopic(IWfSharedContentPortalContext): """Topic interface""" @@ -107,7 +108,7 @@ """Workflow managed topic interface""" -class IContentLink(ISiteElement, IInternalReference): +class IContentLink(ISiteElement, IInternalReference, IAttributeAnnotatable): """Rented content interface""" alt_title = I18nTextLineField(title=_("Alternate title"), diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/link.py --- a/src/pyams_content/shared/site/link.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/link.py Wed Jun 27 16:42:01 2018 +0200 @@ -17,12 +17,14 @@ # import interfaces from pyams_content.shared.site.interfaces import IContentLink +from pyams_utils.interfaces.url import IRelativeURL from pyams_workflow.interfaces import IWorkflow, IWorkflowVersion, IWorkflowVersions, IWorkflowPublicationInfo, \ IWorkflowState # import packages from persistent import Persistent from pyams_sequence.utility import get_reference_target +from pyams_skin.layer import IPyAMSUserLayer from pyams_utils.adapter import adapter_config from zope.container.contained import Contained from zope.interface import implementer @@ -83,3 +85,11 @@ target = context.get_target() if target is not None: return IWorkflowPublicationInfo(target, None) + + +@adapter_config(context=(IContentLink, IPyAMSUserLayer), provides=IRelativeURL) +def content_link_relative_url(context): + """Content link relative URL""" + target = context.get_target() + if target is not None: + return IRelativeURL(target, None) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/manager.py --- a/src/pyams_content/shared/site/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,7 +16,7 @@ # import standard library # import interfaces -from pyams_content.component.illustration import IIllustrationTarget +from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphFactorySettings from pyams_content.component.theme.interfaces import IThemesManagerTarget from pyams_content.features.footer.interfaces import IFooterTarget @@ -30,7 +30,6 @@ from pyams_form.interfaces.form import IFormContextPermissionChecker from pyams_i18n.interfaces import II18n from pyams_portal.interfaces import IPortalContext -from zope.annotation.interfaces import IAttributeAnnotatable from zope.component.interfaces import ISite from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent @@ -51,9 +50,12 @@ from zope.schema.fieldproperty import FieldProperty from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary +from pyams_content import _ + @implementer(ISiteManager, IParagraphFactorySettings, IThemesManagerTarget, IPictogramManagerTarget, - IIllustrationTarget, IPortalContext, IHeaderTarget, IFooterTarget, IPreviewTarget, IAttributeAnnotatable) + IIllustrationTarget, ILinkIllustrationTarget, IPortalContext, IHeaderTarget, + IFooterTarget, IPreviewTarget) class SiteManager(SiteContainerMixin, OrderedContainer, BaseSharedTool, UserSkinnableContent): """Site manager persistent class""" @@ -63,6 +65,8 @@ sequence_name = '' # use default sequence generator sequence_prefix = '' + content_name = _("Site manager") + @property def folder_factory(self): return ISiteFolderFactory(self, SiteFolder) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/zmi/container.py --- a/src/pyams_content/shared/site/zmi/container.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/container.py Wed Jun 27 16:42:01 2018 +0200 @@ -68,7 +68,7 @@ from pyramid.view import view_config from z3c.form import field from z3c.table.column import GetAttrColumn -from zope.interface import implementer +from zope.interface import implementer, Interface from zope.lifecycleevent import ObjectMovedEvent from pyams_content import _ @@ -137,9 +137,9 @@ def updateWidgets(self, prefix=None): super(SiteContainerWorkflowPublicationEditForm, self).updateWidgets(prefix) if 'publication_effective_date' in self.widgets: - widget = self.widgets['publication_effective_date'] - if not widget.value: - widget.value = tztime(datetime.utcnow()).strftime('%d/%m/%y %H:%M') + pub_info = IWorkflowPublicationInfo(self.context) + if pub_info.publication_effective_date is None: + self.widgets['publication_effective_date'].value = tztime(datetime.utcnow()).strftime('%d/%m/%y %H:%M') def get_ajax_output(self, changes): output = super(self.__class__, self).get_ajax_output(changes) @@ -203,7 +203,10 @@ permission = self.permission if self.can_sort and ((not permission) or self.request.has_permission(permission, self.context)): classes.append('table-dnd') - return {'table': ' '.join(classes)} + return { + 'table': ' '.join(classes), + 'tr.selected': lambda item, col, row: 'current' if item is self.context else '' + } @property def data_attributes(self): diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/zmi/folder.py --- a/src/pyams_content/shared/site/zmi/folder.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/folder.py Wed Jun 27 16:42:01 2018 +0200 @@ -20,6 +20,7 @@ from pyams_content.shared.common.interfaces import IBaseSharedTool from pyams_content.shared.site.interfaces import ISiteContainer, ISiteManager, ISiteFolder from pyams_i18n.interfaces import INegotiator, II18n +from pyams_skin.interfaces.container import ITableElementName, ITableElementEditor from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader from pyams_skin.layer import IPyAMSLayer from pyams_zmi.interfaces.menu import ISiteManagementMenu @@ -33,6 +34,7 @@ from pyams_form.form import AJAXAddForm, AJAXEditForm, ajax_config from pyams_i18n.schema import I18nTextLineField from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.table import DefaultElementEditorAdapter from pyams_skin.viewlet.toolbar import ToolbarMenuItem from pyams_utils.adapter import adapter_config, ContextRequestAdapter from pyams_utils.registry import get_utility @@ -164,6 +166,23 @@ # Site folder edit form # +@adapter_config(context=(ISiteFolder, IPyAMSLayer), provides=ITableElementName) +class SiteFolderTableElementNameAdapter(ContextRequestAdapter): + """Site folder table element name adapter""" + + @property + def name(self): + return II18n(self.context).query_attribute('short_name', request=self.request) + + +@adapter_config(context=(ISiteFolder, IAdminLayer, Interface), provides=ITableElementEditor) +class SiteFolderTableElementEditorAdapter(DefaultElementEditorAdapter): + """Site folder table element editor adapter""" + + view_name = 'admin#site-tree.html' + modal_target = False + + @pagelet_config(name='properties.html', context=ISiteFolder, layer=IPyAMSLayer, permission=MANAGE_TOOL_PERMISSION) class SiteFolderPropertiesEditForm(SharedToolPropertiesEditForm): """Site folder properties edit form""" diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/zmi/link.py --- a/src/pyams_content/shared/site/zmi/link.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/link.py Wed Jun 27 16:42:01 2018 +0200 @@ -9,6 +9,7 @@ # 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' @@ -21,7 +22,6 @@ from pyams_content.shared.site.interfaces import ISiteContainer, IContentLink from pyams_content.skin.zmi.interfaces import ISiteTreeTable from pyams_i18n.interfaces import II18n -from pyams_sequence.interfaces import IInternalReference from pyams_skin.interfaces.container import ITableElementName from pyams_skin.interfaces.viewlet import IToolbarAddingMenu from pyams_skin.layer import IPyAMSLayer @@ -31,7 +31,7 @@ # import packages from pyams_content.shared.site.link import ContentLink -from pyams_content.shared.site.zmi.container import SiteContainerTreeTable, SiteContainerTreeNameColumn +from pyams_content.shared.site.zmi.container import SiteContainerTreeTable from pyams_content.shared.site.zmi.widget import SiteManagerFoldersSelectorFieldWidget from pyams_form.form import AJAXAddForm, ajax_config from pyams_pagelet.pagelet import pagelet_config @@ -140,7 +140,7 @@ def get_ajax_output(self, changes): output = super(self.__class__, self).get_ajax_output(changes) intids = get_utility(IIntIds) - if 'reference' in changes.get(IInternalReference, ()): + if changes: table = SiteContainerTreeTable(self.context.__parent__, self.request) table.update() row = table.setUpRow(self.context) @@ -152,16 +152,4 @@ 'row': table.renderRow(row) } }) - elif 'alt_title' in changes.get(IContentLink, ()): - adapter = ContentLinkTableElementName(self.context, self.request, None) - column = SiteContainerTreeNameColumn(self.context, self.request, None) - output.setdefault('events', []).append({ - 'event': 'myams.refresh', - 'options': { - 'handler': 'MyAMS.skin.refreshRowCell', - 'object_id': '{0}::{1}'.format(SiteContainerTreeTable.id, intids.queryId(self.context)), - 'col_name': 'name', - 'cell': column.renderCell(self.context, name=adapter.name) - } - }) return output diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/site/zmi/manager.py --- a/src/pyams_content/shared/site/zmi/manager.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/manager.py Wed Jun 27 16:42:01 2018 +0200 @@ -21,7 +21,7 @@ from pyams_content.shared.site.interfaces import ISiteManager, ISiteManagerFactory from pyams_content.skin.zmi.interfaces import ISiteTreeTable, IUserAddingsMenuLabel from pyams_i18n.interfaces import II18n, INegotiator -from pyams_skin.interfaces.container import ITableElementEditor +from pyams_skin.interfaces.container import ITableElementEditor, ITableElementName from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IBreadcrumbItem, IMenuHeader from pyams_skin.layer import IPyAMSLayer from pyams_zmi.interfaces.menu import ISiteManagementMenu @@ -45,7 +45,7 @@ from pyramid.events import subscriber from pyramid.path import DottedNameResolver from z3c.form import field -from zope.interface import Invalid +from zope.interface import Invalid, Interface from pyams_content import _ @@ -68,6 +68,31 @@ css_class = 'strong' +@adapter_config(context=(ISiteManager, IPyAMSLayer), provides=ITableElementName) +class SiteManagerTableElementNameAdapter(ContextRequestAdapter): + """Site manager table element name adapter""" + + @property + def name(self): + return II18n(self.context).query_attribute('short_name', request=self.request) + + +@adapter_config(context=(ISiteManager, IAdminLayer, Interface), provides=ITableElementEditor) +class SiteManagerTableElementEditorAdapter(DefaultElementEditorAdapter): + """Site manager table element editor adapter""" + + view_name = 'admin#site-tree.html' + modal_target = False + + +@adapter_config(context=(ISiteManager, IAdminLayer, ISiteTreeTable), provides=ITableElementEditor) +class SiteManagerTableElementEditor(DefaultElementEditorAdapter): + """Site tree table element editor""" + + view_name = 'admin#site-tree.html' + modal_target = False + + @adapter_config(context=(ISiteManager, IAdminLayer), provides=IUserAddingsMenuLabel) class SiteManagerUserAddingsMenuLabelAdapter(ContextRequestAdapter): """Site manager user addings menu label adapter""" @@ -137,11 +162,3 @@ site = query_utility(ISiteManager, name=short_name) if site is not None: event.form.widgets.errors += (Invalid(_("A site manager is already registered with this name!!")),) - - -@adapter_config(context=(ISiteManager, IAdminLayer, ISiteTreeTable), provides=ITableElementEditor) -class SiteManagerTableElementEditor(DefaultElementEditorAdapter): - """Site tree table element editor""" - - view_name = 'admin#site-tree.html' - modal_target = False diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/__init__.py --- a/src/pyams_content/shared/view/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/view/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -25,6 +25,7 @@ from pyams_content.features.review.interfaces import IReviewTarget 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 from zope.intid.interfaces import IIntIds from zope.lifecycleevent.interfaces import IObjectModifiedEvent @@ -86,13 +87,12 @@ return list(content_types) def get_results(self, context): - intids = get_utility(IIntIds) views_cache = get_cache(VIEWS_CACHE_REGION, VIEWS_CACHE_NAME) if self.is_using_context: - cache_key = VIEW_CONTEXT_CACHE_KEY.format(view=intids.queryId(self), - context=intids.queryId(context)) + cache_key = VIEW_CONTEXT_CACHE_KEY.format(view=ICacheKeyValue(self), + context=ICacheKeyValue(context)) else: - cache_key = VIEW_CACHE_KEY.format(view=intids.queryId(self)) + cache_key = VIEW_CACHE_KEY.format(ICacheKeyValue(self)) try: results = views_cache.get_value(cache_key) except KeyError: @@ -101,6 +101,7 @@ if adapter is None: adapter = registry.getAdapter(self, IViewQuery) results = adapter.get_results(context, self.limit) + intids = get_utility(IIntIds) views_cache.set_value(cache_key, [intids.queryId(item) for item in results]) logger.debug("Storing view items to cache key {0}".format(cache_key)) else: diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/interfaces/__init__.py --- a/src/pyams_content/shared/view/interfaces/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/view/interfaces/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -161,6 +161,11 @@ required=True, default=ALWAYS_REFERENCE_MODE) + exclude_context = Bool(title=_("Exclude context?"), + description=_("If 'yes', context will be excluded from results list"), + required=True, + default=True) + VIEW_THEMES_SETTINGS_KEY = 'pyams_content.view.themes' diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/portlet/__init__.py --- a/src/pyams_content/shared/view/portlet/__init__.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/view/portlet/__init__.py Wed Jun 27 16:42:01 2018 +0200 @@ -23,6 +23,7 @@ from pyams_content.workflow import PUBLISHED_STATES from pyams_portal.portlet import PortletSettings, portlet_config, Portlet from pyams_sequence.utility import get_sequence_target +from pyams_utils.factory import factory_config from zope.interface import implementer from zope.schema.fieldproperty import FieldProperty @@ -33,6 +34,7 @@ @implementer(IViewItemsPortletSettings) +@factory_config(provided=IViewItemsPortletSettings) class ViewItemsPortletSettings(PortletSettings): """View items portlet settings""" @@ -58,4 +60,4 @@ toolbar_image = None toolbar_css_class = 'fa fa-fw fa-2x fa-th-list' - settings_class = ViewItemsPortletSettings + settings_factory = IViewItemsPortletSettings diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/portlet/templates/view-items-list.pt --- a/src/pyams_content/shared/view/portlet/templates/view-items-list.pt Wed Jun 27 16:34:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -
- -
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/portlet/templates/view-with-images-list.pt diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt --- a/src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt Wed Jun 27 16:42:01 2018 +0200 @@ -1,22 +1,12 @@ - - - -
- -
-
- - No result found - -
-
- -
- - - - -
-
+ + +
+ +
+
+ + No result found + +
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/reference.py --- a/src/pyams_content/shared/view/reference.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/view/reference.py Wed Jun 27 16:42:01 2018 +0200 @@ -9,6 +9,7 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # +from pyams_sequence.interfaces import ISequentialIdInfo __docformat__ = 'restructuredtext' @@ -19,12 +20,12 @@ # import interfaces from hypatia.interfaces import ICatalog from pyams_content.shared.view.interfaces import IWfView, IViewSettings, IViewInternalReferencesSettings, \ - IViewQueryFilterExtension, VIEW_REFERENCES_SETTINGS_KEY, ALWAYS_REFERENCE_MODE + IViewQueryParamsExtension, IViewQueryFilterExtension, VIEW_REFERENCES_SETTINGS_KEY, ALWAYS_REFERENCE_MODE # import packages from hypatia.catalog import CatalogQuery -from hypatia.query import Any -from pyams_catalog.query import CatalogResultSet +from hypatia.query import Any, Not, NotEq +from pyams_catalog.query import CatalogResultSet, and_ from pyams_content.workflow import VISIBLE_STATES from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter from pyams_utils.registry import get_utility @@ -39,6 +40,7 @@ references = FieldProperty(IViewInternalReferencesSettings['references']) references_mode = FieldProperty(IViewInternalReferencesSettings['references_mode']) + exclude_context = FieldProperty(IViewInternalReferencesSettings['exclude_context']) @property def is_using_context(self): @@ -53,6 +55,23 @@ name='++view:references++') +@adapter_config(name='references', context=IWfView, provides=IViewQueryParamsExtension) +class ViewThemesQueryParamsExtension(ContextAdapter): + """View internal references query params extension""" + + weight = 50 + + def get_params(self, context): + catalog = get_utility(ICatalog) + settings = IViewInternalReferencesSettings(self.context) + params = None + # check themes + if settings.exclude_context: + oid = ISequentialIdInfo(context).hex_oid + params = and_(params, NotEq(catalog['oid'], oid)) + return params + + @adapter_config(name='references', context=IWfView, provides=IViewQueryFilterExtension) class ViewInternalReferencesQueryFilterExtension(ContextAdapter): """View internal references filter extension""" @@ -65,6 +84,7 @@ return items if (not items) or (settings.references_mode == ALWAYS_REFERENCE_MODE): catalog = get_utility(ICatalog) - params = Any(catalog['oid'], settings.references) & Any(catalog['workflow_state'], VISIBLE_STATES) + params = Any(catalog['oid'], settings.references) & \ + Any(catalog['workflow_state'], VISIBLE_STATES) items.prepend(CatalogResultSet(CatalogQuery(catalog).query(params))) return items diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/theme.py --- a/src/pyams_content/shared/view/theme.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/shared/view/theme.py Wed Jun 27 16:42:01 2018 +0200 @@ -16,12 +16,18 @@ # import standard library # import interfaces +from hypatia.interfaces import ICatalog from pyams_content.component.theme.interfaces import IThemesInfo -from pyams_content.shared.view.interfaces import IWfView, IViewSettings, IViewThemesSettings, VIEW_THEMES_SETTINGS_KEY +from pyams_content.shared.view.interfaces import IWfView, IViewSettings, IViewThemesSettings, \ + IViewQueryParamsExtension, VIEW_THEMES_SETTINGS_KEY +from zope.intid.interfaces import IIntIds # import packages +from hypatia.query import Any from persistent import Persistent -from pyams_utils.adapter import adapter_config, get_annotation_adapter +from pyams_catalog.query import and_ +from pyams_utils.adapter import adapter_config, get_annotation_adapter, ContextAdapter +from pyams_utils.registry import get_utility from zope.container.contained import Contained from zope.interface import implementer from zope.schema.fieldproperty import FieldProperty @@ -49,7 +55,8 @@ return themes def get_themes_index(self, context): - return [theme.label for theme in self.get_themes(context)] + intids = get_utility(IIntIds) + return [intids.register(term) for term in self.get_themes(context)] @adapter_config(context=IWfView, provides=IViewThemesSettings) @@ -58,3 +65,20 @@ """View themes settings factory""" return get_annotation_adapter(view, VIEW_THEMES_SETTINGS_KEY, ViewThemesSettings, name='++view:themes++') + + +@adapter_config(name='themes', context=IWfView, provides=IViewQueryParamsExtension) +class ViewThemesQueryParamsExtension(ContextAdapter): + """View themes query params extension""" + + weight = 50 + + def get_params(self, context): + catalog = get_utility(ICatalog) + settings = IViewThemesSettings(self.context) + params = None + # check themes + themes = settings.get_themes_index(context) + if themes: + params = and_(params, Any(catalog['themes'], themes)) + return params diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/zmi/render.py --- a/src/pyams_content/shared/view/zmi/render.py Wed Jun 27 16:34:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -# -# Copyright (c) 2008-2015 Thierry Florac -# 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.renderer.interfaces import IContentRenderer -from pyams_content.shared.view.interfaces import IWfView -from pyams_skin.layer import IPyAMSLayer - -# import packages -from pyams_content.features.renderer.skin import BaseContentRenderer -from pyams_template.template import template_config -from pyams_utils.adapter import adapter_config - - -@adapter_config(name='view-render', context=(IWfView, IPyAMSLayer), provides=IContentRenderer) -@template_config(template='templates/render.pt', layer=IPyAMSLayer) -class ViewRenderer(BaseContentRenderer): - """Shared view renderer""" - - weight = 20 - - @property - def items(self): - return self.context.get_results(self.context) diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/shared/view/zmi/templates/render.pt --- a/src/pyams_content/shared/view/zmi/templates/render.pt Wed Jun 27 16:34:12 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -
- View result items -
- WARNING: items displayed in this preview are out of context!! -
- -
-
-
diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/site.py --- a/src/pyams_content/site.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/site.py Wed Jun 27 16:42:01 2018 +0200 @@ -19,6 +19,7 @@ # 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 @@ -38,6 +39,9 @@ for document in find_objects_providing(application, IWfSharedContent): 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) finally: set_local_registry(None) transaction.commit() diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/skin/resources/js/pyams_content.js --- a/src/pyams_content/skin/resources/js/pyams_content.js Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/skin/resources/js/pyams_content.js Wed Jun 27 16:42:01 2018 +0200 @@ -337,7 +337,6 @@ }, updateMarkers: function(settings) { - debugger; var para = $('tr[id="' + settings.object_id + '"]'); var toolbar = $('.title-toolbar', para); var marker = $('DIV.action.' + settings.marker_type, toolbar); @@ -468,39 +467,6 @@ }, /** - * Types management - */ - types: { - - switchSubtypes: function(element) { - var source = $(this); - var switcher = $('i.switch', source); - var td = source.parents('td'); - var subtypes = $('.subtypes', td); - var datatype = source.parents('tr'); - if (switcher.hasClass('fa-plus-square-o')) { - var container = datatype.parents('table'); - subtypes.html('

'); - MyAMS.ajax.post(container.data('ams-location') + '/get-subtypes-table.json', - {object_name: datatype.data('ams-element-name')}, - function(result) { - subtypes.html(result); - if (result) { - MyAMS.initContent(subtypes); - switcher.removeClass('fa-plus-square-o') - .addClass('fa-minus-square-o'); - } - }); - } else { - MyAMS.skin.cleanContainer(subtypes); - subtypes.empty(); - switcher.removeClass('fa-minus-square-o') - .addClass('fa-plus-square-o'); - } - } - }, - - /** * Site management */ site: { @@ -607,6 +573,28 @@ }, /** + * Header management + */ + header: { + + submitEditForm: function() { + var form = $(this).parents('form').first(); + MyAMS.form.submit(form, {form_data: {'autosubmit': true}}); + } + }, + + /** + * Footer management + */ + footer: { + + submitEditForm: function() { + var form = $(this).parents('form').first(); + MyAMS.form.submit(form, {form_data: {'autosubmit': true}}); + } + }, + + /** * User profile management */ profile: { diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/skin/resources/js/pyams_content.min.js --- a/src/pyams_content/skin/resources/js/pyams_content.min.js Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/skin/resources/js/pyams_content.min.js Wed Jun 27 16:42:01 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(''+e.data.title+"")}})}})}),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:'  '+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('
')}},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('

'),a.ajax.post(l.data("ams-location")+"/get-paragraph-editor.json",{object_name:o.data("ams-element-name")},function(t){r.html(t),t&&(a.initContent(r),n.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),o.data("ams-disabled-handlers",!0),a.skin.scrollTo(r,{offset:r.height()-o.height()}))})}else a.skin.cleanContainer(r),r.empty(),n.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o.removeData("ams-disabled-handlers")},switchLastEditor:function(e){var a=t('table[id="'+e+'"]'),i=t("tr:last",a);t('[data-ams-click-handler="PyAMS_content.paragraphs.switchEditor"]',i).click()},switchAllEditors:function(e){var i=t(this),n=t("i",i),s=i.parents("table");n.hasClass("fa-plus-square-o")?(n.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),a.ajax.post(s.data("ams-location")+"/get-paragraphs-editors.json",{},function(e){for(var i in e)if(e.hasOwnProperty(i)){var r=t('tr[data-ams-element-name="'+i+'"]',s),o=t(".editor",r);o.is(":empty")&&o.html(e[i]),t(".fa-plus-square-o",r).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),r.data("ams-disabled-handlers",!0)}t("i.fa-plus-square-o",t("tbody",s)).exists()||n.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o"),a.initContent(s)})):(t(".editor",s).each(function(){a.skin.cleanContainer(t(this)),t(this).empty()}),t(".fa-minus-square-o",s).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),t("tr",s).removeData("ams-disabled-handlers"))},updateToolbar:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i);n.replaceWith(e.toolbar_tag),n=t(".title-toolbar",i),a.initContent(n)},updateMarkers:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i),s=t("DIV.action."+e.marker_type,n);s.exists()?s.replaceWith(e.marker_tag):t(e.marker_tag).appendTo(n),e.marker_tag&&(s=t("DIV.action."+e.marker_type,n),a.initContent(s)),a.helpers.sort(n,"weight")}},pictograms:{initManagerSelection:function(){var e=t(this),a=t('input[type="hidden"]',t(".selected-pictograms",e)).listattr("value");return{selected:JSON.stringify(a)}},switchPictogram:function(){var e=t(this),a=e.parents(".pictograms"),i=a.parents(".pictograms-manager");a.hasClass("available-pictograms")?t(".selected-pictograms",i).append(e):t(".available-pictograms",i).append(e)}},themes:{initExtracts:function(e){var i=t('select[name="form.widgets.thesaurus_name:list"]',e).val(),n=t('select[name="form.widgets.extract_name:list"]',e),s=n.val();i&&a.jsonrpc.post("getExtracts",{thesaurus_name:i},{url:"/api/thesaurus/json"},function(e){n.empty(),t(e.result).each(function(){t("").attr("value",this.id).attr("selected",this.id===s).text(this.text).appendTo(n)})}),n.attr("data-ams-events-handlers",'{"select2-open": "PyAMS_content.themes.getExtracts"}')},getExtracts:function(e){var i=t(e.currentTarget).parents("form"),n=t('select[name="form.widgets.thesaurus_name:list"]',i).val();n&&a.jsonrpc.post("getExtracts",{thesaurus_name:n},{url:"/api/thesaurus/json"},function(e){var a=t('select[name="form.widgets.extract_name:list"]',i).data("select2");a.results.empty(),a.opts.populateResults.call(a,a.results,e.result,{term:""})})}},fields:{refreshField:function(e){var a=t('table[id="form_fields_list"]'),i=t('tr[data-ams-element-name="'+e.object_name+'"]',a);t("td:nth-child(4)",i).html(e.title)}},imgmap:{init:function(){var e=t(this);a.ajax.check(t.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+a.devext+".js",function(){e.canvasAreaDraw({imageUrl:e.data("ams-image-url")})})},initPreview:function(){var e=t(this);a.ajax.check(t.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+a.devext+".js",function(){e.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},types:{switchSubtypes:function(e){var i=t(this),n=t("i.switch",i),s=i.parents("td"),r=t(".subtypes",s),o=i.parents("tr");if(n.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('

'),a.ajax.post(l.data("ams-location")+"/get-subtypes-table.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"))})}else a.skin.cleanContainer(r),r.empty(),n.removeClass("fa-minus-square-o").addClass("fa-plus-square-o")}},site:{switchVisibility:function(){return function(){var e=t(this),i=e.parents("tr").first();a.ajax.post(i.data("ams-location")+"/switch-content-visibility.json",{object_name:i.data("ams-element-name")},function(a,i){var n="fa-eye";a.visible||(n+="-slash"),a.published||(n+=" text-danger"),t("i",e).attr("class","fa fa-fw "+n)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(e){var n=t(".chat-body",e);n.animate({scrollTop:n[0].scrollHeight},1e3),clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.chat),a.skin.registerCleanCallback(i.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)},updateComments:function(){var e,i=t(".badge",'nav a[href="#review-comments.html"]'),n=t(".chat-body",".widget-body");e=n.exists()?t(".message",n).length:parseInt(i.text()),a.ajax.post("get-last-review-comments.json",{count:e},function(a){n.exists()&&i.removeClass("bg-color-danger").addClass("bg-color-info"),e!==a.count&&(i.text(a.count).removeClass("hidden"),n.exists()&&(t(".messages",n).append(a.content),n.animate({scrollTop:n[0].scrollHeight},1e3)),n.exists()||i.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){t(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(e){var a=t(".chat-body",".widget-body");return{count:t(".message",a).length}},addCommentAction:function(){return function(){t('textarea[name="comment"]').focus()}},addCommentCallback:function(e){var a=t(this),i=a.parents(".widget-body");t(".messages",i).append(e.content),t('textarea[name="comment"]',a).val("");var n=t(".chat-body",i);n.animate({scrollTop:n[0].scrollHeight},1e3),t(".badge",'nav a[href="#review-comments.html"]').text(e.count).removeClass("hidden")}},profile:{switchFavorite:function(){var e=t(this),i=e.data("sequence-oid");a.ajax.post("switch-user-favorite.json",{oid:i},function(t,a){t.favorite?e.removeClass("fa-star-o").addClass("fa-star"):e.removeClass("fa-star").addClass("fa-star-o")})}}};t(".badge",'nav a[href="#review-comments.html"]').exists()&&(i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)),e.PyAMS_content=i}(jQuery,this); +!function(o,t){"use strict";var l=t.MyAMS,a={widget:{treeview:{selectFolder:function(t,e){o(t.target).siblings('input[type="hidden"]').val(e.id)},unselectFolder:function(t,e){o(t.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(t){return tinyMCE.addI18n("fr",{"Link list":"Liste de liens","Toggle h3 header":"En-tête H3","Toggle h4 header":"En-tête H4","Insert internal link":"Insérer un lien interne","Link title":"Texte à afficher","Internal number":"N° interne"}),tinymce.PluginManager.add("internal_links",function(e,t){e.addButton("internal_links",{icon:"cloud-check",tooltip:"Insert internal link",image:"/--static--/pyams_content/img/internal-link.png",onclick:function(){e.windowManager.open({title:"Insert internal link",body:[{type:"textbox",name:"oid",label:"Internal number"},{type:"textbox",name:"title",label:"Link title",value:e.selection.getContent()}],onsubmit:function(t){e.insertContent(''+t.data.title+"")}})}})}),tinyMCE.PluginManager.add("headers",function(i,t){["h3","h4"].forEach(function(a){i.addButton("header-"+a,{tooltip:"Toggle "+a+" header",text:a.toUpperCase(),onClick:function(){i.execCommand("mceToggleFormat",!1,a)},onPostRender:function(){var e=this,t=function(){i.formatter.formatChanged(a,function(t){e.active(t)})};i.formatter?t():i.on("init",t)}})})}),t.image_list=a.TinyMCE.getImagesList,t.link_list=a.TinyMCE.getLinksList,t.style_formats=[{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}],t.plugins+=" internal_links headers",t.toolbar1&&(t.toolbar1="undo redo | header-h3 header-h4 styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent"),t.toolbar2&&(t.toolbar2="forecolor backcolor | charmap internal_links link | fullscreen preview print | code"),t},getImagesList:function(t){var e=o(document.activeElement).parents("form");if(e.exists()){var a=e.attr("data-ams-form-handler")||e.attr("action"),i=a.substr(0,a.lastIndexOf("/")+1);return l.ajax.post(i+"get-images-list.json",{},t)}},getLinksList:function(t){var e=o(document.activeElement).parents("form");if(e.exists()){var a=e.attr("data-ams-form-handler")||e.attr("action"),i=a.substr(0,a.lastIndexOf("/")+1);return l.ajax.post(i+"get-links-list.json",{},t)}}},galleries:{updateMediaTitle:function(t){o('img[id="'+t.media_id+'"]').attr("original-title",t.title)},switchMediaVisibility:function(t){return function(){var a=o(this),t=a.parents(".media"),e=t.parents(".gallery");l.ajax.post(e.data("ams-location")+"/set-media-visibility.json",{object_name:t.data("ams-element-name")},function(t,e){t.visible?(o("i",a).attr("class","fa fa-fw fa-eye"),a.parents(".btn-group").siblings("a.fancyimg").removeClass("not-visible")):(o("i",a).attr("class","fa fa-fw fa-eye-slash text-danger"),a.parents(".btn-group").siblings("a.fancyimg").addClass("not-visible"))})}},setOrder:function(t,e){if(!e||!e.item.hasClass("already-dropped")){var a=e.item.parents(".gallery"),i=o(".media",a).listattr("data-ams-element-name");l.ajax.post(a.data("ams-location")+"/set-medias-order.json",{medias:JSON.stringify(i)})}},removeMedia:function(t){return function(){var n=o(this);l.skin.bigBox({title:l.i18n.WARNING,content:'  '+l.i18n.DELETE_WARNING,buttons:l.i18n.BTN_OK_CANCEL},function(t){if(t===l.i18n.BTN_OK){var e=n.parents(".gallery").data("ams-location"),a=n.parents(".media"),i=a.data("ams-element-name");l.ajax.post(e+"/delete-element.json",{object_name:i},function(t,e){a.remove()})}})}},afterFancyboxLoad:function(t,e){t.element.hasClass("not-visible")&&t.inner.prepend('
')}},paragraphs:{preReload:function(){a.paragraphs.switched=o("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){o(a.paragraphs.switched).each(function(){o("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete a.paragraphs.switched},refreshParagraph:function(t){var e=o('tr[id="'+t.object_id+'"]');o("span.title",e).html(t.title||" - - - - - - - -")},switchEditor:function(t){var e=o(this),a=o("i.switch",e),i=e.parents("td"),n=o(".editor",i),s=e.parents("tr");if(a.hasClass("fa-plus-square-o")){var r=s.parents("table");n.html('

'),l.ajax.post(r.data("ams-location")+"/get-paragraph-editor.json",{object_name:s.data("ams-element-name")},function(t){n.html(t),t&&(l.initContent(n),a.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),s.data("ams-disabled-handlers",!0),l.skin.scrollTo(n,{offset:n.height()-s.height()}))})}else l.skin.cleanContainer(n),n.empty(),a.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),s.removeData("ams-disabled-handlers")},switchLastEditor:function(t){var e=o('table[id="'+t+'"]'),a=o("tr:last",e);o('[data-ams-click-handler="PyAMS_content.paragraphs.switchEditor"]',a).click()},switchAllEditors:function(t){var e=o(this),n=o("i",e),s=e.parents("table");n.hasClass("fa-plus-square-o")?(n.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),l.ajax.post(s.data("ams-location")+"/get-paragraphs-editors.json",{},function(t){for(var e in t)if(t.hasOwnProperty(e)){var a=o('tr[data-ams-element-name="'+e+'"]',s),i=o(".editor",a);i.is(":empty")&&i.html(t[e]),o(".fa-plus-square-o",a).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),a.data("ams-disabled-handlers",!0)}o("i.fa-plus-square-o",o("tbody",s)).exists()||n.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o"),l.initContent(s)})):(o(".editor",s).each(function(){l.skin.cleanContainer(o(this)),o(this).empty()}),o(".fa-minus-square-o",s).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o("tr",s).removeData("ams-disabled-handlers"))},updateToolbar:function(t){var e=o('tr[id="'+t.object_id+'"]'),a=o(".title-toolbar",e);a.replaceWith(t.toolbar_tag),a=o(".title-toolbar",e),l.initContent(a)},updateMarkers:function(t){var e=o('tr[id="'+t.object_id+'"]'),a=o(".title-toolbar",e),i=o("DIV.action."+t.marker_type,a);i.exists()?i.replaceWith(t.marker_tag):o(t.marker_tag).appendTo(a),t.marker_tag&&(i=o("DIV.action."+t.marker_type,a),l.initContent(i)),l.helpers.sort(a,"weight")}},pictograms:{initManagerSelection:function(){var t=o(this),e=o('input[type="hidden"]',o(".selected-pictograms",t)).listattr("value");return{selected:JSON.stringify(e)}},switchPictogram:function(){var t=o(this),e=t.parents(".pictograms"),a=e.parents(".pictograms-manager");e.hasClass("available-pictograms")?o(".selected-pictograms",a).append(t):o(".available-pictograms",a).append(t)}},themes:{initExtracts:function(t){var e=o('select[name="form.widgets.thesaurus_name:list"]',t).val(),a=o('select[name="form.widgets.extract_name:list"]',t),i=a.val();e&&l.jsonrpc.post("getExtracts",{thesaurus_name:e},{url:"/api/thesaurus/json"},function(t){a.empty(),o(t.result).each(function(){o("").attr("value",this.id).attr("selected",this.id===i).text(this.text).appendTo(a)})}),a.attr("data-ams-events-handlers",'{"select2-open": "PyAMS_content.themes.getExtracts"}')},getExtracts:function(t){var a=o(t.currentTarget).parents("form"),e=o('select[name="form.widgets.thesaurus_name:list"]',a).val();e&&l.jsonrpc.post("getExtracts",{thesaurus_name:e},{url:"/api/thesaurus/json"},function(t){var e=o('select[name="form.widgets.extract_name:list"]',a).data("select2");e.results.empty(),e.opts.populateResults.call(e,e.results,t.result,{term:""})})}},fields:{refreshField:function(t){var e=o('table[id="form_fields_list"]'),a=o('tr[data-ams-element-name="'+t.object_name+'"]',e);o("td:nth-child(4)",a).html(t.title)}},imgmap:{init:function(){var t=o(this);l.ajax.check(o.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+l.devext+".js",function(){t.canvasAreaDraw({imageUrl:t.data("ams-image-url")})})},initPreview:function(){var t=o(this);l.ajax.check(o.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+l.devext+".js",function(){t.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},site:{switchVisibility:function(){return function(){var i=o(this),t=i.parents("tr").first();l.ajax.post(t.data("ams-location")+"/switch-content-visibility.json",{object_name:t.data("ams-element-name")},function(t,e){var a="fa-eye";t.visible||(a+="-slash"),t.published||(a+=" text-danger"),o("i",i).attr("class","fa fa-fw "+a)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(t){var e=o(".chat-body",t);e.animate({scrollTop:e[0].scrollHeight},1e3),clearInterval(a.review.timer),a.review.timer=setInterval(a.review.updateComments,a.review.timer_duration.chat),l.skin.registerCleanCallback(a.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(a.review.timer),a.review.timer=setInterval(a.review.updateComments,a.review.timer_duration.general)},updateComments:function(){var e,a=o(".badge",'nav a[href="#review-comments.html"]'),i=o(".chat-body",".widget-body");e=i.exists()?o(".message",i).length:parseInt(a.text()),l.ajax.post("get-last-review-comments.json",{count:e},function(t){i.exists()&&a.removeClass("bg-color-danger").addClass("bg-color-info"),e!==t.count&&(a.text(t.count).removeClass("hidden"),i.exists()&&(o(".messages",i).append(t.content),i.animate({scrollTop:i[0].scrollHeight},1e3)),i.exists()||a.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){o(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(t){var e=o(".chat-body",".widget-body");return{count:o(".message",e).length}},addCommentAction:function(){return function(){o('textarea[name="comment"]').focus()}},addCommentCallback:function(t){var e=o(this),a=e.parents(".widget-body");o(".messages",a).append(t.content),o('textarea[name="comment"]',e).val("");var i=o(".chat-body",a);i.animate({scrollTop:i[0].scrollHeight},1e3),o(".badge",'nav a[href="#review-comments.html"]').text(t.count).removeClass("hidden")}},header:{submitEditForm:function(){var t=o(this).parents("form").first();l.form.submit(t,{form_data:{autosubmit:!0}})}},footer:{submitEditForm:function(){var t=o(this).parents("form").first();l.form.submit(t,{form_data:{autosubmit:!0}})}},profile:{switchFavorite:function(){var a=o(this),t=a.data("sequence-oid");l.ajax.post("switch-user-favorite.json",{oid:t},function(t,e){t.favorite?a.removeClass("fa-star-o").addClass("fa-star"):a.removeClass("fa-star").addClass("fa-star-o")})}}};o(".badge",'nav a[href="#review-comments.html"]').exists()&&(a.review.timer=setInterval(a.review.updateComments,a.review.timer_duration.general)),t.PyAMS_content=a}(jQuery,this); diff -r 5ee242d90312 -r d8261b628787 src/pyams_content/skin/routes.py --- a/src/pyams_content/skin/routes.py Wed Jun 27 16:34:12 2018 +0200 +++ b/src/pyams_content/skin/routes.py Wed Jun 27 16:42:01 2018 +0200 @@ -26,7 +26,7 @@ from pyams_catalog.query import CatalogResultSet from pyams_content.workflow import VISIBLE_STATES from pyams_utils.registry import get_utility -from pyams_utils.url import absolute_url +from pyams_utils.url import absolute_url, canonical_url from pyramid.exceptions import NotFound from pyramid.response import Response from pyramid.view import view_config @@ -51,12 +51,13 @@ params &= Any(catalog['workflow_state'], VISIBLE_STATES) results = list(CatalogResultSet(CatalogQuery(catalog).query(params))) if results: + response = Response() + response.status_code = 302 if view_name: # back-office access => last version version = IWorkflowVersions(results[0]).get_last_versions()[0] + response.location = absolute_url(version, request, '/'.join(view_name)) else: version = results[0] - response = Response() - response.status_code = 302 - response.location = absolute_url(version, request, '/'.join(view_name)) + response.location = canonical_url(version, request) return response raise NotFound()