Client-Side Attachment Validation
Reference
The xwiki:actions:beforeUpload event is fired in the browser once per file the reader has picked, before anything is sent to the server. A listener that calls event.preventDefault() turns that one file down. The Attachment Validation Application listens to it twice, for the maximum attachment size and for the allowed and blocked mimetypes, and an extension adds a check of its own the same way.
Where the Event Is Fired
| Upload | Fired | Payload |
|---|---|---|
| The "Attachments" tab of a Page, and every other HTML5 upload field | Once per file of the selection | file |
| The attachmentSelector macro | Once per file field, as the form is submitted | file |
| The image dialog of the WYSIWYG editor | Once, as "Upload" is selected | file, documentReference |
Payload
| Key | Value | Set by |
|---|---|---|
| file | The File about to be uploaded. The shipped checks read its name, size and type | Every upload above |
| documentReference | The reference of the Page the attachment will be written to, serialized. It is what lets a check read the configuration of that Page rather than of the Page the editor is open on | The image dialog of the WYSIWYG editor only |
The payload reaches a jQuery listener as its second argument. Two of the three uploads fire the event through Prototype, so a listener that does not require xwiki-events-bridge never runs for them, and sees only the WYSIWYG image dialog:
require(['jquery', 'xwiki-events-bridge'], function ($) {
$(document).on('xwiki:actions:beforeUpload', function (event, data) {
if (data.file.name.toLowerCase().endsWith('.exe')) {
new XWiki.widgets.Notification('Executables cannot be attached.', 'error');
event.preventDefault();
}
});
});Rules of a Listener
| Rule | Behaviour |
|---|---|
| Cancelling silently | The file leaves the selection with nothing said. Report the reason first, as the shipped checks do. |
| Cancelling late | The event is read as soon as the listener returns, so an asynchronous check, one reading the file with a FileReader for instance, cannot turn the upload down. |
| Several listeners | Every one of them runs, and a single preventDefault() is enough to refuse the file. |
| Throwing | The HTML5 upload field catches it, reports it in place of that file and carries on with the rest of the selection. The two other uploads do not catch it. |
| What the check is worth | Nothing is enforced in the browser. The server validates the attachment again, so an upload that never runs this JavaScript, a REST client for one, is refused all the same. |
FAQ
Where does the JavaScript go?
In a JavaScript Skin Extension used on all Pages, which is how the shipped size and mimetype checks are themselves written.