diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 738faed172..d36e7d7fea 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -37,6 +37,7 @@ Changelog * Move translations in `nl_NL` to `nl` (Loïc Teixeira, Coen van der Kamp) * Add documentation for how to redirect to a separate page on Form builder submissions using ``RoutablePageMixin`` (Nick Smith) * Refactored index listing views and made column sort-by headings more consistent (Matt Westcott) + * Added the ability to customise the pre-filled Image title on upload and it now defaults to the filename without the file extension (LB Johnston) * Fix: Delete button is now correct colour on snippets and modeladmin listings (Brandon Murch) * Fix: Ensure that StreamBlock / ListBlock-level validation errors are counted towards error counts (Matt Westcott) * Fix: InlinePanel add button is now keyboard navigatable (Jesse Menn) diff --git a/docs/advanced_topics/images/index.rst b/docs/advanced_topics/images/index.rst index 8876ac7ed7..5633d2ae0c 100644 --- a/docs/advanced_topics/images/index.rst +++ b/docs/advanced_topics/images/index.rst @@ -13,3 +13,4 @@ Images feature_detection image_serve_view focal_points + title_generation_on_upload diff --git a/docs/advanced_topics/images/title_generation_on_upload.md b/docs/advanced_topics/images/title_generation_on_upload.md new file mode 100644 index 0000000000..ad2affba60 --- /dev/null +++ b/docs/advanced_topics/images/title_generation_on_upload.md @@ -0,0 +1,108 @@ +# Title generation on upload + +Override how the title is set when adding a single image, multiple images or uploading an image within a chooser modal. + +When a file is dropped into the multi-upload page or selected on the single file selection form a title will be automatically populated into the Title field. The default behaviour is to use the image's filename excluding the extension. + +You can customise the resolved value of this title using a JavaScript [event listener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) which will listen to the `'wagtail:images-upload'` event. + +The simplest way to add JavaScript to the editor is via the [`insert_global_admin_js` hook](../../reference/hooks.html#insert-global-admin-js), however any JavaScript that adds the event listener will work. + +## DOM Event + +The event name to listen for is `'wagtail:images-upload'`. It will be dispatched on the image upload `form`. The event's `detail` attribute will contain: + +- `data` - An object which includes the `title` to be used. It is the filename with the extension removed. +- `maxTitleLength` - An integer (or `null`) which is the maximum length of the `Image` model title field. +- `filename` - The original filename without the extension removed. + +To modify the generated `Image` title, access and update `event.detail.data.title`, no return value is needed. + +For single image uploads, the custom event will only run if the title does not already have a value so that we do not overwrite whatever the user has typed. + +You can prevent the default behaviour by calling `event.preventDefault()`. For the single upload page or modals, this will not pre-fill any value into the title. For multiple upload, this will avoid any title submission and use the filename title only (with file extension) as a title is required to save the image. + +The event will 'bubble' up so that you can simply add a global `document` listener to capture all of these events, or you can scope your listener or handler logic as needed to ensure you only adjust titles in some specific scenarios. + +See MDN for more information about [custom JavasScript events](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events). + +## Code Examples + +### Removing any url unsafe characters from the title + +```python +# wagtail_hooks.py +from django.utils.safestring import mark_safe + +from wagtail.core import hooks + + +@hooks.register("insert_global_admin_js") +def get_global_admin_js(): + return mark_safe( + """ + + """ + ) +``` + +### Changing generated titles on the page editor only to remove dashes/underscores + +Using the [`insert_editor_js` hook](../../reference/hooks.html#insert-editor-js) instead so that this script will not run on the `Image` upload page, only on page editors. + +```python +# wagtail_hooks.py +from django.utils.safestring import mark_safe + +from wagtail.core import hooks + + +@hooks.register("insert_editor_js") +def get_global_admin_js(): + return mark_safe( + """ + + """ + ) +``` + +### Stopping pre-filling of title based on filename + +```python +# wagtail_hooks.py +from django.utils.safestring import mark_safe + +from wagtail.core import hooks + + +@hooks.register("insert_global_admin_js") +def get_global_admin_js(): + return mark_safe( + """ + + """ + ) +``` diff --git a/docs/releases/2.15.rst b/docs/releases/2.15.rst index 1d5e071490..cdf1dc7c1c 100644 --- a/docs/releases/2.15.rst +++ b/docs/releases/2.15.rst @@ -53,6 +53,7 @@ Other features * Translations in ``nl_NL`` are moved to the ``nl`` po files. ``nl_NL`` translation files are deleted. Projects that use ``LANGUAGE_CODE = 'nl-nl'`` will automatically fallback to ``nl``. (Loïc Teixeira, Coen van der Kamp) * Add documentation for how to redirect to a separate page on Form builder submissions using ``RoutablePageMixin`` (Nick Smith) * Refactored index listing views and made column sort-by headings more consistent (Matt Westcott) + * Added the ability to customise the pre-filled Image title on upload and it now defaults to the filename without the file extension (LB Johnston) Bug fixes ~~~~~~~~~ diff --git a/wagtail/admin/views/generic/multiple_upload.py b/wagtail/admin/views/generic/multiple_upload.py index f81837e04f..e33c391a87 100644 --- a/wagtail/admin/views/generic/multiple_upload.py +++ b/wagtail/admin/views/generic/multiple_upload.py @@ -125,7 +125,7 @@ class AddView(PermissionCheckedMixin, TemplateView): # Build a form for validation upload_form_class = self.get_upload_form_class() form = upload_form_class({ - 'title': request.FILES['files[]'].name, + 'title': request.POST.get('title', request.FILES['files[]'].name), 'collection': request.POST.get('collection'), }, { 'file': request.FILES['files[]'], diff --git a/wagtail/images/static_src/wagtailimages/js/add-multiple.js b/wagtail/images/static_src/wagtailimages/js/add-multiple.js index 183b0f89ff..c9825fbf8b 100644 --- a/wagtail/images/static_src/wagtailimages/js/add-multiple.js +++ b/wagtail/images/static_src/wagtailimages/js/add-multiple.js @@ -97,6 +97,35 @@ $(function() { } }, + /** + * Allow a custom title to be defined by an event handler for this form. + * If event.preventDefault is called, the original behaviour of using the raw + * filename (with extension) as the title is preserved. + * + * @example + * document.addEventListener('wagtail:images-upload', function(event) { + * // remove file extension + * var newTitle = (event.detail.data.title || '').replace(/\.[^\.]+$/, ""); + * event.detail.data.title = newTitle; + * }); + * + * @param {HtmlElement[]} form + * @returns {{name: 'string', value: *}[]} + */ + formData: function(form) { + var filename = this.files[0].name; + var data = { title: filename.replace(/\.[^\.]+$/, '') }; + var maxTitleLength = window.fileupload_opts.max_title_length; + + var event = form.get(0).dispatchEvent(new CustomEvent( + 'wagtail:images-upload', + { bubbles: true, cancelable: true, detail: { data: data, filename: filename, maxTitleLength: maxTitleLength } } + )); + + // default behaviour (title is just file name) + return event ? form.serializeArray().concat({ name:'title', value: data.title }) : form.serializeArray(); + }, + done: function(e, data) { var itemElement = $(data.context); var response = JSON.parse(data.result); diff --git a/wagtail/images/static_src/wagtailimages/js/image-chooser-modal.js b/wagtail/images/static_src/wagtailimages/js/image-chooser-modal.js index 8b46c3f4b3..cdc47ec0c8 100644 --- a/wagtail/images/static_src/wagtailimages/js/image-chooser-modal.js +++ b/wagtail/images/static_src/wagtailimages/js/image-chooser-modal.js @@ -34,11 +34,26 @@ function ajaxifyImageUploadForm(modal) { fileWidget.on('change', function () { var titleWidget = $('#id_image-chooser-upload-title', modal.body); var title = titleWidget.val(); + // do not override a title that already exists (from manual editing or previous upload) if (title === '') { // The file widget value example: `C:\fakepath\image.jpg` var parts = fileWidget.val().split('\\'); - var fileName = parts[parts.length - 1]; - titleWidget.val(fileName); + var filename = parts[parts.length - 1]; + + // allow event handler to override filename (used for title) & provide maxLength as int to event + var maxTitleLength = parseInt(titleWidget.attr('maxLength') || '0', 10) || null; + var data = { title: filename.replace(/\.[^\.]+$/, '') }; + + // allow an event handler to customise data or call event.preventDefault to stop any title pre-filling + var form = fileWidget.closest('form').get(0); + var event = form.dispatchEvent(new CustomEvent( + 'wagtail:images-upload', + { bubbles: true, cancelable: true, detail: { data: data, filename: filename, maxTitleLength: maxTitleLength } } + )); + + if (!event) return; // do not set a title if event.preventDefault(); is called by handler + + titleWidget.val(data.title); } }); } diff --git a/wagtail/images/templates/wagtailimages/images/add.html b/wagtail/images/templates/wagtailimages/images/add.html index 849048d391..c88d35a71a 100644 --- a/wagtail/images/templates/wagtailimages/images/add.html +++ b/wagtail/images/templates/wagtailimages/images/add.html @@ -11,6 +11,31 @@ {% url 'wagtailadmin_tag_autocomplete' as autocomplete_url %}