Skip to content

Commit

Permalink
Add support for the "accept" attribute on file inputs.
Browse files Browse the repository at this point in the history
If the widget's field - if there is one - has the "accept" attribute set (the
`NamedImage` field has `image/*` set by default) then this is rendered as an
`accept` attribute on the file input.

This would restrict the allowed file types before uploading while still being
checked on the server side.

Fixes: #66
Depends on: plone/plone.namedfile#158
[thet]
  • Loading branch information
thet committed Mar 15, 2024
1 parent 9214d6c commit 4dd3de3
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 3 deletions.
12 changes: 12 additions & 0 deletions news/67.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Add support for the "accept" attribute on file inputs.

If the widget's field - if there is one - has the "accept" attribute set (the
`NamedImage` field has `image/*` set by default) then this is rendered as an
`accept` attribute on the file input.

This would restrict the allowed file types before uploading while still being
checked on the server side.

Fixes: https://github.com/plone/plone.formwidget.namedfile/issues/66
Depends on: https://github.com/plone/plone.namedfile/pull/158
[thet]
1 change: 1 addition & 0 deletions plone/formwidget/namedfile/file_input.pt
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
type="file"
tal:attributes="id string:${view/id}-input;
name view/name;
accept view/accept;
size view/size;
disabled view/disabled;
maxlength view/maxlength;"
Expand Down
1 change: 1 addition & 0 deletions plone/formwidget/namedfile/image_input.pt
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
type="file"
tal:attributes="id string:${view/id}-input;
name view/name;
accept view/accept;
size view/size;
disabled view/disabled;
maxlength view/maxlength;"
Expand Down
6 changes: 6 additions & 0 deletions plone/formwidget/namedfile/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ class NamedFileWidget(Explicit, file.FileWidget):
value = None # don't default to a string
_file_upload_id = None

@property
def accept(self):
accept = getattr(self.field, "accept", None)
if accept:
return ", ".join(accept)

@property
def is_uploaded(self):
return utils.is_file_upload(self.value)\
Expand Down
65 changes: 63 additions & 2 deletions plone/formwidget/namedfile/widget.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ First use a GET request::
>>> image_widget.extract()
<ZPublisher.HTTPRequest.FileUpload ...>

The rendering is unchanged:
The rendering is unchanged::

>>> print(file_widget.render())
<span id="widget.id.file" class="named-file-widget">
Expand Down Expand Up @@ -292,7 +292,7 @@ At first, there is no value, so the behaviour is much like before::
>>> print(image_widget.render())
<span id="widget.id.image" class="named-image-widget required namedimage-field">
<input type="file" id="widget.id.image-input"
name="widget.name.image" />
name="widget.name.image" accept="image/*" />
</span>

However, if we now set a value, we will have the option of keeping it,
Expand Down Expand Up @@ -396,6 +396,67 @@ stored in the field::
True


Rendering field widgets with constraints on allowed media types
-----------------------------------------------------------------

The NamedImage already has a constraint on `image/*` mime types for files and
this is also rendered for the input element. See above.
You can also customize the allowed media types with the `accept` attribute,
like shown here::

>>> class IContentConstrained(Interface):
... file_field = field.NamedFile(
... title=u"File",
... accept=("audio/mp3", "audio/flac", ".wav")
... )
... image_field = field.NamedImage(
... title=u"Image",
... accept=("image/webp", "image/png", ".jpg")
... )

>>> @implementer(IContentConstrained, IImageScaleTraversable, IAttributeAnnotatable)
... class ContentConstrained(object):
... def __init__(self, file, image):
... self.file_field = file
... self.image_field = image
... self._p_mtime = DateTime()
... self.path = '/content_constrained'
...
... def absolute_url(self):
... return root_url + self.path
...
... def Title(self):
... return 'A content item'

>>> content_constrained = ContentConstrained(None, None)

>>> file_widget_constrained = NamedFileFieldWidget(IContentConstrained['file_field'], make_request())
>>> image_widget_constrained = NamedImageFieldWidget(IContentConstrained['image_field'], make_request())

>>> file_widget_constrained.context = content_constrained
>>> image_widget_constrained.context = content_constrained

>>> file_widget_constrained.id = 'widget.id.file'
>>> file_widget_constrained.name = 'widget.name.file'

>>> image_widget_constrained.id = 'widget.id.image'
>>> image_widget_constrained.name = 'widget.name.image'

At first, there is no value, so the behaviour is much like before::

>>> file_widget_constrained.update()
>>> print(file_widget_constrained.render())
<span id="widget.id.file" class="named-file-widget required namedfile-field">
<input type="file" id="widget.id.file-input" name="widget.name.file" accept="audio/mp3, audio/flac, .wav" />
</span>

>>> image_widget_constrained.update()
>>> print(image_widget_constrained.render())
<span id="widget.id.image" class="named-image-widget required namedimage-field">
<input type="file" id="widget.id.image-input" name="widget.name.image" accept="image/webp, image/png, .jpg" />
</span>


Download view
-------------

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
zip_safe=False,
install_requires=[
'setuptools',
'plone.namedfile',
"plone.namedfile>5.6.1",
'plone.z3cform >= 0.7.4',
'six',
'z3c.form',
Expand Down

0 comments on commit 4dd3de3

Please sign in to comment.