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

Loop: Wagtail 5.1 compatibility #216

Merged
merged 11 commits into from
Jul 19, 2023
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