From c03bc4036504574b1f894637de540b4001f09a2b Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Apr 2019 13:32:38 +0200 Subject: [PATCH 1/5] add alt text behavior --- plone/app/contenttypes/behaviors/alt_text.py | 53 +++++++++++++++++++ .../app/contenttypes/behaviors/configure.zcml | 9 ++++ .../contenttypes/browser/templates/image.pt | 3 +- .../profiles/default/metadata.xml | 2 +- plone/app/contenttypes/upgrades.py | 14 +++++ plone/app/contenttypes/upgrades.zcml | 9 +++- 6 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 plone/app/contenttypes/behaviors/alt_text.py diff --git a/plone/app/contenttypes/behaviors/alt_text.py b/plone/app/contenttypes/behaviors/alt_text.py new file mode 100644 index 000000000..919d8027c --- /dev/null +++ b/plone/app/contenttypes/behaviors/alt_text.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +from plone.app.contenttypes import _ +from plone.autoform.interfaces import IFormFieldProvider +from plone.dexterity.interfaces import IDexterityContent +from plone.supermodel import model +from zope import schema +from zope.component import adapter +from zope.interface import implementer +from zope.interface import provider +from zope.interface import Interface + + +class IAltText(Interface): + pass + + +@provider(IFormFieldProvider) +class IAltTextBehavior(model.Schema): + + alt_text = schema.TextLine( + title=_('label_alt_text', default=u'Alt Text'), + description=_( + 'label_alt_text_help', + default=u'Briefly describe the meaning of the image for people' + u'using assistive technology like screen readers.' + u'This will be used when the image is viewed by itself.' + u'Do not duplicate the Title or Description fields, ' + u'since they will also be read by screen readers.' + u'Alt text should describe what a sighted user sees ' + u'when looking at the image.' + u'This might include text the image contains, or even ' + u'a description of an abstract pattern.' + u'This field should never be left blank on sites that ' + u'want to be compliant with accessibility standards.' + ), + required=False, + ) + + +@implementer(IAltTextBehavior) +@adapter(IDexterityContent) +class AltText(object): + + def __init__(self, context): + self.context = context + + @property + def alt_text(self): + return self.context.alt_text + + @alt_text.setter + def alt_text(self, value): + self.context.alt_text = value diff --git a/plone/app/contenttypes/behaviors/configure.zcml b/plone/app/contenttypes/behaviors/configure.zcml index a51368583..6e404dc0b 100644 --- a/plone/app/contenttypes/behaviors/configure.zcml +++ b/plone/app/contenttypes/behaviors/configure.zcml @@ -64,6 +64,15 @@ provides=".thumb_icon.IThumbIconHandling" /> + +
diff --git a/plone/app/contenttypes/profiles/default/metadata.xml b/plone/app/contenttypes/profiles/default/metadata.xml index 73b9cd24f..687667d6c 100644 --- a/plone/app/contenttypes/profiles/default/metadata.xml +++ b/plone/app/contenttypes/profiles/default/metadata.xml @@ -1,5 +1,5 @@ - 1106 + 1107 profile-plone.app.dexterity:default profile-plone.app.event:default diff --git a/plone/app/contenttypes/upgrades.py b/plone/app/contenttypes/upgrades.py index 19c838195..32501962b 100644 --- a/plone/app/contenttypes/upgrades.py +++ b/plone/app/contenttypes/upgrades.py @@ -254,3 +254,17 @@ def searchabletext_richtext(context): objs = _brains2objs(brains) for obj in objs: obj.reindexObject(idxs=['SearchableText']) + + +def add_alt_text(context): + fti = queryUtility( + IDexterityFTI, + name='Image' + ) + behavior = 'plone.app.contenttypes.behaviors.alt_text.IAltText' + if behavior in fti.behaviors: + return + behaviors = list(fti.behaviors) + behaviors.append(behavior) + behaviors = tuple(behaviors) + fti._updateProperty('behaviors', behaviors) diff --git a/plone/app/contenttypes/upgrades.zcml b/plone/app/contenttypes/upgrades.zcml index 0ad9f2ac7..c898ad5e9 100644 --- a/plone/app/contenttypes/upgrades.zcml +++ b/plone/app/contenttypes/upgrades.zcml @@ -86,5 +86,12 @@ profile="plone.app.contenttypes:default" handler=".upgrades.searchabletext_richtext" /> - + + From 47faf1f59e22d3a3c0594584b045bb44248ffb94 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Apr 2019 16:28:39 +0200 Subject: [PATCH 2/5] remove behavior and add field to image schema --- plone/app/contenttypes/behaviors/alt_text.py | 53 ------------------- .../app/contenttypes/behaviors/configure.zcml | 9 ---- plone/app/contenttypes/schema/image.xml | 13 +++++ 3 files changed, 13 insertions(+), 62 deletions(-) delete mode 100644 plone/app/contenttypes/behaviors/alt_text.py diff --git a/plone/app/contenttypes/behaviors/alt_text.py b/plone/app/contenttypes/behaviors/alt_text.py deleted file mode 100644 index 919d8027c..000000000 --- a/plone/app/contenttypes/behaviors/alt_text.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -from plone.app.contenttypes import _ -from plone.autoform.interfaces import IFormFieldProvider -from plone.dexterity.interfaces import IDexterityContent -from plone.supermodel import model -from zope import schema -from zope.component import adapter -from zope.interface import implementer -from zope.interface import provider -from zope.interface import Interface - - -class IAltText(Interface): - pass - - -@provider(IFormFieldProvider) -class IAltTextBehavior(model.Schema): - - alt_text = schema.TextLine( - title=_('label_alt_text', default=u'Alt Text'), - description=_( - 'label_alt_text_help', - default=u'Briefly describe the meaning of the image for people' - u'using assistive technology like screen readers.' - u'This will be used when the image is viewed by itself.' - u'Do not duplicate the Title or Description fields, ' - u'since they will also be read by screen readers.' - u'Alt text should describe what a sighted user sees ' - u'when looking at the image.' - u'This might include text the image contains, or even ' - u'a description of an abstract pattern.' - u'This field should never be left blank on sites that ' - u'want to be compliant with accessibility standards.' - ), - required=False, - ) - - -@implementer(IAltTextBehavior) -@adapter(IDexterityContent) -class AltText(object): - - def __init__(self, context): - self.context = context - - @property - def alt_text(self): - return self.context.alt_text - - @alt_text.setter - def alt_text(self, value): - self.context.alt_text = value diff --git a/plone/app/contenttypes/behaviors/configure.zcml b/plone/app/contenttypes/behaviors/configure.zcml index 6e404dc0b..a51368583 100644 --- a/plone/app/contenttypes/behaviors/configure.zcml +++ b/plone/app/contenttypes/behaviors/configure.zcml @@ -64,15 +64,6 @@ provides=".thumb_icon.IThumbIconHandling" /> - - Image + + + Briefly describe the meaning of the image for people using assistive technology like screen readers. + This will be used when the image is viewed by itself. + Do not duplicate the Title or Description fields, since they will also be read by screen readers. + Alt text should describe what a sighted user sees when looking at the image. + This might include text the image contains, or even a description of an abstract pattern. + This field should never be left blank on sites that want to be compliant with accessibility standards. + + False + Alt Text + From e586046b673af558e36885f95cc9aa683bfde6ac Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 17 Apr 2019 17:55:49 +0200 Subject: [PATCH 3/5] add tests and remove useless upgrade-step --- news/2837.feature | 2 + .../profiles/default/metadata.xml | 2 +- plone/app/contenttypes/tests/test_image.py | 44 ++++++++++++++++++- plone/app/contenttypes/upgrades.py | 15 +------ plone/app/contenttypes/upgrades.zcml | 7 --- 5 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 news/2837.feature diff --git a/news/2837.feature b/news/2837.feature new file mode 100644 index 000000000..6dadf1b6b --- /dev/null +++ b/news/2837.feature @@ -0,0 +1,2 @@ +Add alt_text field to images for allow users to set an alt text manually. +[cekk] diff --git a/plone/app/contenttypes/profiles/default/metadata.xml b/plone/app/contenttypes/profiles/default/metadata.xml index 687667d6c..73b9cd24f 100644 --- a/plone/app/contenttypes/profiles/default/metadata.xml +++ b/plone/app/contenttypes/profiles/default/metadata.xml @@ -1,5 +1,5 @@ - 1107 + 1106 profile-plone.app.dexterity:default profile-plone.app.event:default diff --git a/plone/app/contenttypes/tests/test_image.py b/plone/app/contenttypes/tests/test_image.py index 9974c82e7..09a7e8d7a 100644 --- a/plone/app/contenttypes/tests/test_image.py +++ b/plone/app/contenttypes/tests/test_image.py @@ -94,7 +94,16 @@ def setUp(self): image.title = 'My Image' image.description = 'This is my image.' image.image = dummy_image() + + self.portal.invokeFactory('Image', 'image-with-alt') + image_alt = self.portal['image-with-alt'] + image_alt.title = 'My Image 2' + image_alt.description = 'This is my second image.' + image_alt.alt_text = 'An alt text' + image.image = dummy_image() + self.image = image + self.image_alt = image_alt self.request.set('URL', image.absolute_url()) self.request.set('ACTUAL_URL', image.absolute_url()) alsoProvides(self.request, IPloneFormLayer) @@ -106,6 +115,31 @@ def test_image_view(self): self.assertEqual(view.request.response.status, 200) self.assertTrue('My Image' in view()) self.assertTrue('This is my image.' in view()) + self.assertFalse('An alt text' in view()) + + def test_image_view_alt(self): + view = self.image_alt.restrictedTraverse('@@view') + + self.assertTrue(view()) + self.assertEqual(view.request.response.status, 200) + self.assertTrue('My Image 2' in view()) + self.assertTrue('This is my second image.' in view()) + self.assertTrue('An alt text' in view()) + + def test_image_alt_in_listing_view(self): + self.image_alt.image = dummy_image(u'image.svg') + view = self.portal.restrictedTraverse('@@listing_view') + self.assertTrue('An alt text' in view()) + + def test_image_alt_in_summary_view(self): + self.image_alt.image = dummy_image(u'image.svg') + view = self.portal.restrictedTraverse('@@summary_view') + self.assertTrue('An alt text' in view()) + + def test_image_alt_in_album_view(self): + self.image_alt.image = dummy_image(u'image.svg') + view = self.portal.restrictedTraverse('@@album_view') + self.assertTrue('An alt text' in view()) # XXX: Not working. See ImageFunctionalTest test_image_view_fullscreen # Problem seems to be that the image is not properly uploaded. @@ -124,7 +158,15 @@ def test_svg_image(self): scale = self.image.restrictedTraverse('@@images') self.assertRegex( scale.scale('image', scale='large').tag(), - r'My Image' # noqa: E501 + r'' # noqa: E501 + ) + + def test_svg_image_alt(self): + self.image_alt.image = dummy_image(u'image.svg') + scale = self.image_alt.restrictedTraverse('@@images') + self.assertRegex( + scale.scale('image', scale='large').tag(), + r'An alt text' # noqa: E501 ) diff --git a/plone/app/contenttypes/upgrades.py b/plone/app/contenttypes/upgrades.py index 32501962b..872e9e901 100644 --- a/plone/app/contenttypes/upgrades.py +++ b/plone/app/contenttypes/upgrades.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from plone import api from plone.app.contenttypes.utils import DEFAULT_TYPES from plone.dexterity.interfaces import IDexterityFTI from Products.CMFCore.utils import getToolByName @@ -254,17 +255,3 @@ def searchabletext_richtext(context): objs = _brains2objs(brains) for obj in objs: obj.reindexObject(idxs=['SearchableText']) - - -def add_alt_text(context): - fti = queryUtility( - IDexterityFTI, - name='Image' - ) - behavior = 'plone.app.contenttypes.behaviors.alt_text.IAltText' - if behavior in fti.behaviors: - return - behaviors = list(fti.behaviors) - behaviors.append(behavior) - behaviors = tuple(behaviors) - fti._updateProperty('behaviors', behaviors) diff --git a/plone/app/contenttypes/upgrades.zcml b/plone/app/contenttypes/upgrades.zcml index c898ad5e9..49944ab13 100644 --- a/plone/app/contenttypes/upgrades.zcml +++ b/plone/app/contenttypes/upgrades.zcml @@ -87,11 +87,4 @@ handler=".upgrades.searchabletext_richtext" /> - From 589614349f4089c50fa5bfc7202cc79337586895 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Thu, 18 Apr 2019 09:34:19 +0200 Subject: [PATCH 4/5] add support for alt_text also for leadimage behavior --- news/2837.feature | 2 +- plone/app/contenttypes/behaviors/leadimage.py | 25 +++++++++++++++++++ plone/app/contenttypes/schema/image.xml | 4 +-- .../tests/test_behaviors_leadimage.py | 18 +++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/news/2837.feature b/news/2837.feature index 6dadf1b6b..739e8fbbf 100644 --- a/news/2837.feature +++ b/news/2837.feature @@ -1,2 +1,2 @@ -Add alt_text field to images for allow users to set an alt text manually. +Add alt_text field to images and lead image behavior. This allows users to manually set the value of alt tag. [cekk] diff --git a/plone/app/contenttypes/behaviors/leadimage.py b/plone/app/contenttypes/behaviors/leadimage.py index f7bebbddf..3cacde92d 100644 --- a/plone/app/contenttypes/behaviors/leadimage.py +++ b/plone/app/contenttypes/behaviors/leadimage.py @@ -30,6 +30,23 @@ class ILeadImageBehavior(model.Schema): required=False, ) + alt_text = schema.TextLine( + title=_(u'label_alt_text', default=u'Alt Text'), + description=_( + u'label_alt_text_description', + default=u'Briefly describe the meaning of the image for people ' + u'using assistive technology like screen readers. This will be ' + u'used when the image is viewed by itself. Do not duplicate the ' + u'Title or Description fields, since they will also be read by ' + u'screen readers. Alt text should describe what a sighted user ' + u'sees when looking at the image. This might include text the ' + u'image contains, or even a description of an abstract pattern. ' + u'This field should never be left blank on sites that want to be ' + u'compliant with accessibility standards.' + ), + required=False, + ) + @implementer(ILeadImageBehavior) @adapter(IDexterityContent) @@ -53,3 +70,11 @@ def image_caption(self): @image_caption.setter def image_caption(self, value): self.context.image_caption = value + + @property + def alt_text(self): + return self.context.alt_text + + @alt_text.setter + def alt_text(self, value): + self.context.alt_text = value diff --git a/plone/app/contenttypes/schema/image.xml b/plone/app/contenttypes/schema/image.xml index 9b0310839..72bbd8c18 100644 --- a/plone/app/contenttypes/schema/image.xml +++ b/plone/app/contenttypes/schema/image.xml @@ -20,7 +20,7 @@ - + Briefly describe the meaning of the image for people using assistive technology like screen readers. This will be used when the image is viewed by itself. Do not duplicate the Title or Description fields, since they will also be read by screen readers. @@ -29,7 +29,7 @@ This field should never be left blank on sites that want to be compliant with accessibility standards. False - Alt Text + Alt Text diff --git a/plone/app/contenttypes/tests/test_behaviors_leadimage.py b/plone/app/contenttypes/tests/test_behaviors_leadimage.py index a42331db8..0390d7e83 100644 --- a/plone/app/contenttypes/tests/test_behaviors_leadimage.py +++ b/plone/app/contenttypes/tests/test_behaviors_leadimage.py @@ -79,3 +79,21 @@ def test_lead_image_viewlet_shows_up(self): # But doesn't show up on folder_contents, which is not a default view self.browser.open(self.portal_url + '/leadimagefolder/folder_contents') self.assertTrue('
' not in self.browser.contents) + + def test_lead_image_viewlet_shows_alt_text(self): + self.browser.open(self.portal_url + '/leadimagefolder/edit') + # Image upload + file_path = os.path.join(os.path.dirname(__file__), 'image.jpg') + file_ctl = self.browser.getControl( + name='form.widgets.ILeadImageBehavior.image' + ) + with io.FileIO(file_path, 'rb') as f: + file_ctl.add_file(f, 'image/png', 'image.jpg') + # Image caption + self.browser.getControl( + name='form.widgets.ILeadImageBehavior.alt_text' + ).value = 'alternative text' + # Submit form + self.browser.getControl('Save').click() + + self.assertTrue('alternative text' in self.browser.contents) From c16c09d99eff4536ced3e154950c6bce9d5970b2 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Thu, 18 Apr 2019 09:39:54 +0200 Subject: [PATCH 5/5] change changelog issue number --- news/{2837.feature => 518.feature} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename news/{2837.feature => 518.feature} (100%) diff --git a/news/2837.feature b/news/518.feature similarity index 100% rename from news/2837.feature rename to news/518.feature