Skip to content
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repos:
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.0.277'
rev: 'v0.0.278'
hooks:
- id: ruff
- repo: https://github.com/adamchainz/blacken-docs
Expand Down
20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@

# Changelog

## [Unreleased]

## [0.14.3] - 2023-07-19

### Added

- Support for Wagtail 5.1

### Changed

- Switched to trusted PyPI publishing
- Clarified the defaults for `WAGTAILMEDIA` in README
- Improved coverage configuration

### Fixed

- Long-running buttons for Wagtail 5+
- Tag field initialisation when using the generic media chooser
- Title population from file name.


## [0.14.2] - 2023-06-08

### Changed
Expand Down
2 changes: 1 addition & 1 deletion src/wagtailmedia/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.14.2"
__version__ = "0.14.3"
129 changes: 72 additions & 57 deletions src/wagtailmedia/static/wagtailmedia/js/media-chooser-modal.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
MEDIA_CHOOSER_MODAL_ONLOAD_HANDLERS = {
'chooser': function(modal, jsonData) {
var searchUrl = $('form.media-search', modal.body).attr('action');
const searchUrl = $('form.media-search', modal.body).attr('action');
const searchInput = $('#id_q', modal.body);
const resultsContainer = $('#search-results', modal.body);
const collectionChooser = $('#collection_chooser_collection_id', modal.body);
/* save initial page browser HTML, so that we can restore it if the search box gets cleared */
const initialPageResultsHtml = resultsContainer.html();

/* currentTag stores the tag currently being filtered on, so that we can
preserve this when paginating */
var currentTag;
let currentTag;

let request;

function ajaxifyLinks (context) {
$('a.media-choice', context).on('click', function(e) {
Expand All @@ -13,61 +20,67 @@ MEDIA_CHOOSER_MODAL_ONLOAD_HANDLERS = {
});

$('.pagination a', context).on('click', function(e) {
var page = this.getAttribute("data-page");
setPage(page);
let params = {
p: this.getAttribute("data-page"),
collection_id: collectionChooser.val()
};
const query = searchInput.val();
if (query.length) {
params['q'] = query;
}
if (currentTag) {
params['tag'] = currentTag;
}

request = fetchResults(params);
e.preventDefault();
});

$('a[data-ordering]', context).on('click', function(e) {
sortResults(this.dataset["ordering"]);
request = fetchResults({
q: searchInput.val(),
collection_id: collectionChooser.val(),
ordering: this.dataset["ordering"]
});
e.preventDefault();
});
}

function fetchResults(requestData) {
$.ajax({
return $.ajax({
url: searchUrl,
data: requestData,
success: function(data, status) {
$('#search-results').html(data);
ajaxifyLinks($('#search-results'));
initWMTabs();
}
success(data) {
request = null;
resultsContainer.html(data);
ajaxifyLinks(resultsContainer);
},
error() {
request = null;
},
});
}

function search() {
/* Searching causes currentTag to be cleared - otherwise there's
no way to de-select a tag */
currentTag = null;
fetchResults({
q: $('#id_q').val(),
collection_id: $('#collection_chooser_collection_id').val()
});
return false;
}

function setPage(page) {
params = {p: page};
if ($('#id_q').val().length){
params['q'] = $('#id_q').val();
const query = searchInput.val();
const collection_id = collectionChooser.val()
if (query !== '' || collection_id !== '') {
/* Searching causes currentTag to be cleared - otherwise there's
no way to de-select a tag */
currentTag = null;
request = fetchResults({
q: query,
collection_id: collection_id
});
}
if (currentTag) {
params['tag'] = currentTag;
else {
/* search box is empty - restore original page browser HTML */
resultsContainer.html(initialPageResultsHtml);
ajaxifyLinks();
}
params['collection_id'] = $('#collection_chooser_collection_id').val();
fetchResults(params);
return false;
}

function sortResults(order) {
fetchResults({
q: $('#id_q').val(),
collection_id: $('#collection_chooser_collection_id').val(),
ordering: order
});
}

ajaxifyLinks(modal.body);
initWMTabs();

Expand Down Expand Up @@ -116,43 +129,45 @@ MEDIA_CHOOSER_MODAL_ONLOAD_HANDLERS = {

$('form.media-search', modal.body).on('submit', search);

$('#id_q').on('input', function() {
searchInput.on('input', function() {
if (request) {
request.abort();
}
clearTimeout($.data(this, 'timer'));
var wait = setTimeout(search, 200);
$(this).data('timer', wait);
});
$('#collection_chooser_collection_id').on('change', search);
collectionChooser.on('change', search);
$('a.suggested-tag').on('click', function() {
currentTag = $(this).text();
$('#id_q').val('');
fetchResults({
searchInput.val('');
request = fetchResults({
'tag': currentTag,
collection_id: $('#collection_chooser_collection_id').val()
collection_id: collectionChooser.val()
});
return false;
});

function populateTitle(context) {
// Note: There are two inputs with `#id_title` on the page.
// The page title and media title. Select the input inside the modal body.
var fileWidget = $('#id_file', context);
// Note: There are two inputs with `#id_title` on the page.
// The page title and media title. Select the input inside the modal body.
$('[name="media-chooser-upload-file"]', modal.body).each(function() {
const fileWidget = $(this);
fileWidget.on('change', function () {
var titleWidget = $('#id_title', context);
var title = titleWidget.val();
if (title === '') {
let titleWidget = $('#id_media-chooser-upload-title', fileWidget.closest('form'));
if (titleWidget.val() === '') {
// The file widget value example: `C:\fakepath\media.jpg`
var parts = fileWidget.val().split('\\');
var fileName = parts[parts.length - 1];
titleWidget.val(fileName);
const parts = fileWidget.val().split('\\');
const filename = parts[parts.length - 1];
titleWidget.val(filename.replace(/\.[^.]+$/, ''));
}
});
}

populateTitle(modal.body);
});

/* Add tag entry interface (with autocompletion) to the tag field of the media upload form */
$('#id_tags', modal.body).tagit({
autocomplete: {source: jsonData['tag_autocomplete_url']}
$('[name="media-chooser-upload-tags"]', modal.body).each(function() {
$(this).tagit({
autocomplete: {source: jsonData['tag_autocomplete_url']}
});
});
},
'media_chosen': function(modal, jsonData) {
Expand Down
32 changes: 22 additions & 10 deletions src/wagtailmedia/static/wagtailmedia/js/media-chooser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,38 @@ function createMediaChooser(id) {
const chooserElement = $('#' + id + '-chooser');
const mediaTitle = chooserElement.find('[data-chooser-title]');
const input = $('#' + id);
const editLink = chooserElement.find('.edit-link');
const chooserBaseUrl = chooserElement.data('chooserUrl');

$('.action-choose', chooserElement).on('click', function() {
let chooseAction = chooserElement.find('.action-choose');
if (!chooseAction.length) {
chooseAction = chooserElement.find('[data-chooser-action-choose]');
}
let clearAction = chooserElement.find('.action-clear');
if (!clearAction.length) {
clearAction = chooserElement.find('[data-chooser-action-clear]');
}
let editAction = chooserElement.find('.edit-link');
if (!editAction.length) {
editAction = chooserElement.find('[data-chooser-edit-link]');
}


chooseAction.on('click', function() {
ModalWorkflow({
url: chooserBaseUrl,
url: chooserElement.data('chooserUrl'),
onload: MEDIA_CHOOSER_MODAL_ONLOAD_HANDLERS,
responses: {
mediaChosen: function(mediaData) {
input.val(mediaData.id);
mediaTitle.text(mediaData.title);
chooserElement.removeClass('blank');
editLink.attr('href', mediaData.edit_link);
editLink.removeClass('w-hidden');
editAction.attr('href', mediaData.edit_url);
editAction.removeClass('w-hidden');
}
}
});
});

$('.action-clear', chooserElement).on('click', function() {
clearAction.on('click', function() {
input.val('');
chooserElement.addClass('blank');
});
Expand All @@ -42,8 +54,8 @@ function createMediaChooser(id) {
}
input.val(mediaData.id);
mediaTitle.text(mediaData.title);
editLink.attr('href', mediaData.edit_url);
editLink.removeClass('w-hidden');
editAction.attr('href', mediaData.edit_url);
editAction.removeClass('w-hidden');
chooserElement.removeClass('blank');
state = mediaData;
},
Expand All @@ -57,7 +69,7 @@ function createMediaChooser(id) {
return result;
},
focus: function() {
$('.action-choose', chooserElement).focus();
chooseAction.focus();
}
};

Expand Down
22 changes: 16 additions & 6 deletions src/wagtailmedia/templates/wagtailmedia/chooser/chooser.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@

<div class="tab-content">
<section id="tab-search" class="w-tabs__panel" role="tabpanel" aria-labelledby="tab-label-search">
<form class="media-search search-bar" action="{% url 'wagtailmedia:chooser' %}" method="GET" novalidate>
<form action="{% url 'wagtailmedia:chooser' %}" method="GET" role="search" class="media-search search-bar" novalidate data-chooser-modal-search>
<ul class="fields">
{% for field in searchform %}
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
<li>{% include "wagtailadmin/shared/field.html" with field=field only %}</li>
{% endfor %}
{% if collections %}
{% include "wagtailadmin/shared/collection_chooser.html" %}
<li>{% include "wagtailadmin/shared/collection_chooser.html" %}</li>
{% endif %}
{% if popular_tags %}
{% url 'wagtailmedia:index' as index_url %}
<li class="taglist">
<h3>{% trans 'Popular tags' %}</h3>
{% for tag in popular_tags %}
<a class="suggested-tag tag" href="{% url 'wagtailmedia:index' %}?tag={{ tag.name|urlencode }}">{{ tag.name }}</a>
<a class="suggested-tag tag" href="{{ index_url }}?tag={{ tag.name|urlencode }}">{{ tag.name }}</a>
{% endfor %}
</li>
{% endif %}
Expand All @@ -74,11 +75,20 @@ <h3>{% trans 'Popular tags' %}</h3>
{% if field.is_hidden %}
{{ field }}
{% else %}
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
<li>{% include "wagtailadmin/shared/field.html" with field=field only %}</li>
{% endif %}
{% endfor %}
<li>
<button type="submit" class="button button-longrunning" data-clicked-text="{% trans 'Uploading…' %}">{% icon name="spinner" %}<em>{% trans 'Upload' %}</em></button>
<button
type="submit"
class="button button-longrunning"
data-clicked-text="{% trans 'Uploading…' %}"
data-controller="w-progress"
data-action="w-progress#activate"
data-w-progress-active-value="{% trans 'Uploading…' %}"
>
{% icon name="spinner" %}<em>{% trans 'Upload' %}</em>
</button>
</li>
</ul>
</form>
Expand Down
24 changes: 22 additions & 2 deletions src/wagtailmedia/templates/wagtailmedia/media/add.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
$('#id_tags').tagit({
autocomplete: {source: "{{ autocomplete_url|addslashes }}"}
});

const fileWidget = document.getElementById("id_file");
const titleWidget = document.getElementById("id_title");
fileWidget.addEventListener('change', function () {
if (titleWidget.value === '') {
// The file widget value example: `C:\fakepath\media.jpg`
var parts = fileWidget.value.split('\\');
var filename = parts[parts.length - 1].replace(/\.[^.]+$/, '');
titleWidget.value = filename;
}
});
});
</script>
{% endblock %}
Expand Down Expand Up @@ -48,11 +59,20 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
<li>{% include "wagtailadmin/shared/field.html" with field=field %}</li>
{% endif %}
{% endfor %}
<li>
<button type="submit" class="button button-longrunning" data-clicked-text="{% trans 'Uploading…' %}">{% icon name="spinner" %}<em>{% trans 'Upload' %}</em></button>
<button
type="submit"
class="button button-longrunning"
data-clicked-text="{% trans 'Uploading…' %}"
data-controller="w-progress"
data-action="w-progress#activate"
data-w-progress-active-value="{% trans 'Uploading…' %}"
>
{% icon name="spinner" %}<em>{% trans 'Upload' %}</em>
</button>
</li>
</ul>
</form>
Expand Down
Loading