Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide alt text for image content-type and lead image #518

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions news/518.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add alt_text field to images and lead image behavior. This allows users to manually set the value of alt tag.
[cekk]
25 changes: 25 additions & 0 deletions plone/app/contenttypes/behaviors/leadimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
3 changes: 2 additions & 1 deletion plone/app/contenttypes/browser/templates/image.pt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
<a class="discreet"
tal:attributes="href string:${context/@@plone_context_state/object_url}/image_view_fullscreen"
tal:define="scale context/@@images;
img_tag python:scale.scale('image', scale='large').tag()"
alt_text context/alt_text|nothing;
img_tag python:scale.scale('image', scale='large').tag(alt=alt_text)"
tal:on-error="string: Image cannot be displayed">
<img tal:replace="structure img_tag" />
<figcaption class="discreet">
Expand Down
13 changes: 13 additions & 0 deletions plone/app/contenttypes/schema/image.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,18 @@
<description />
<title i18n:translate="label_image">Image</title>
</field>
<field name="alt_text"
type="zope.schema.TextLine">
<description i18n:translate="label_alt_text_help">
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.
</description>
<required>False</required>
<title i18n:translate="label_alt_text">Alt Text</title>
</field>
</schema>
</model>
18 changes: 18 additions & 0 deletions plone/app/contenttypes/tests/test_behaviors_leadimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -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('<div class="leadImage">' 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)
44 changes: 43 additions & 1 deletion plone/app/contenttypes/tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand All @@ -124,7 +158,15 @@ def test_svg_image(self):
scale = self.image.restrictedTraverse('@@images')
self.assertRegex(
scale.scale('image', scale='large').tag(),
r'<img src="http://nohost/plone/image/@@images/[a-z0-9--]*.svg" alt="My Image" title="My Image" height="768" width="768" />' # noqa: E501
r'<img src="http://nohost/plone/image/@@images/[a-z0-9--]*.svg" height="768" width="768" />' # 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'<img src="http://nohost/plone/image-with-alt/@@images/[a-z0-9--]*.svg" alt="An alt text" height="768" width="768" />' # noqa: E501
)


Expand Down
1 change: 1 addition & 0 deletions plone/app/contenttypes/upgrades.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion plone/app/contenttypes/upgrades.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,5 @@
profile="plone.app.contenttypes:default"
handler=".upgrades.searchabletext_richtext"
/>

</configure>