diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 9f34d97569..ef8d8d4467 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -17,6 +17,7 @@ Changelog
* Cleaned up Django docs URLs in documentation (Pete Andrew)
* Add StreamFieldPanel to available panel types in documentation (Dan Swain)
* Add {{ block.super }} example to ModelAdmin customisation in documentation (Dan Swain)
+ * Add ability to filter image index by a tag (Benedikt Willi)
* Fix: Rename documents listing column 'uploaded' to 'created' (LB (Ben Johnston))
* Fix: Submenu items longer then the page height are no longer broken by the submenu footer (Igor van Spengen)
* Fix: Unbundle the l18n library as it was bundled to avoid installation errors which have been resolved (Matt Westcott)
diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst
index 87d6323ba3..8041a69324 100644
--- a/CONTRIBUTORS.rst
+++ b/CONTRIBUTORS.rst
@@ -425,6 +425,7 @@ Contributors
* Tim Gates
* Timothy Bautista
* Pete Andrew
+* Benedikt Willi
Translators
===========
diff --git a/client/scss/components/_button.scss b/client/scss/components/_button.scss
index 66a9f6978e..2b65475dad 100644
--- a/client/scss/components/_button.scss
+++ b/client/scss/components/_button.scss
@@ -106,7 +106,7 @@
}
&.bicolor {
- border: 0;
+ border: 1px solid transparent;
padding-left: 3.5em;
&:before {
@@ -123,6 +123,10 @@
border-top-left-radius: inherit;
border-bottom-left-radius: inherit;
}
+
+ &.button-secondary {
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ }
}
&.button-small.bicolor {
diff --git a/client/scss/components/_tag.scss b/client/scss/components/_tag.scss
index 8b561282cc..d054d9888c 100644
--- a/client/scss/components/_tag.scss
+++ b/client/scss/components/_tag.scss
@@ -29,9 +29,33 @@ a.tag:hover {
.taglist {
font-size: 0.9em;
line-height: 2.4em;
+}
- h3 {
- display: inline;
- margin-right: 1em;
+.tagfilter {
+ legend {
+ @include visuallyvisible;
+
+ @include media-breakpoint-up(sm) {
+ @include column(2);
+ padding-left: 0;
+ }
+
+ font-weight: 700;
+ color: #333;
+ font-size: 1.1em;
+ display: block;
+ padding: 0 0 0.8em;
+ }
+
+ a {
+ font-size: 0.9em;
+ }
+
+ .button.bicolor.icon-cross {
+ padding-left: 2em;
+
+ &:before {
+ background-color: transparent;
+ }
}
}
diff --git a/client/scss/tools/_mixins.general.scss b/client/scss/tools/_mixins.general.scss
index 1b826f489d..38cb7da8b1 100644
--- a/client/scss/tools/_mixins.general.scss
+++ b/client/scss/tools/_mixins.general.scss
@@ -81,10 +81,10 @@
@mixin visuallyvisible {
- clip: none;
+ clip: auto;
height: auto;
width: auto;
- margin: auto;
+ margin: initial;
overflow: visible;
position: initial;
}
diff --git a/docs/releases/2.8.rst b/docs/releases/2.8.rst
index 1966a52afa..00db4f51cb 100644
--- a/docs/releases/2.8.rst
+++ b/docs/releases/2.8.rst
@@ -26,6 +26,7 @@ Other features
* Cleaned up Django docs URLs in documentation (Pete Andrew)
* Add StreamFieldPanel to available panel types in documentation (Dan Swain)
* Add {{ block.super }} example to ModelAdmin customisation in documentation (Dan Swain)
+ * Add ability to filter image index by a tag (Benedikt Willi)
Bug fixes
diff --git a/wagtail/images/templates/wagtailimages/images/index.html b/wagtail/images/templates/wagtailimages/images/index.html
index be13692fff..b53e5983fe 100644
--- a/wagtail/images/templates/wagtailimages/images/index.html
+++ b/wagtail/images/templates/wagtailimages/images/index.html
@@ -1,4 +1,5 @@
{% extends "wagtailadmin/base.html" %}
+{% load wagtailadmin_tags %}
{% load wagtailimages_tags %}
{% load i18n %}
@@ -31,13 +32,33 @@
{% endif %}
- {% if collections %}
-
- {% endif %}
+ {% if current_tag %}
+
+ {% endif %}
+ {% endif %}
+ {% if popular_tags %}
+
+
+
+ {% endif %}
+
+
{% include "wagtailimages/images/results.html" %}
diff --git a/wagtail/images/tests/test_admin_views.py b/wagtail/images/tests/test_admin_views.py
index e7d088a230..56a93d114a 100644
--- a/wagtail/images/tests/test_admin_views.py
+++ b/wagtail/images/tests/test_admin_views.py
@@ -50,7 +50,7 @@ class TestImageIndexView(TestCase, WagtailTestUtils):
for i in range(1, 50):
self.image = Image.objects.create(
title="Test image %i" % i,
- file=get_test_image_file(),
+ file=get_test_image_file(size=(1, 1)),
collection=evil_plans_collection
)
@@ -87,6 +87,85 @@ class TestImageIndexView(TestCase, WagtailTestUtils):
['Root', 'Evil plans', 'Good plans'])
+ def test_tags(self):
+ image_two_tags = Image.objects.create(
+ title="Test image with two tags",
+ file=get_test_image_file(),
+ )
+ image_two_tags.tags.add("one", "two")
+
+ response = self.get()
+ self.assertEqual(response.status_code, 200)
+
+ current_tag = response.context['current_tag']
+ self.assertIsNone(current_tag)
+
+ tags = response.context['popular_tags']
+ self.assertTrue(
+ [tag.name for tag in tags] == ["one", "two"]
+ or [tag.name for tag in tags] == ["two", "one"]
+ )
+
+
+ def test_tag_filtering(self):
+ Image.objects.create(
+ title="Test image with no tags",
+ file=get_test_image_file(),
+ )
+
+ image_one_tag = Image.objects.create(
+ title="Test image with one tag",
+ file=get_test_image_file(),
+ )
+ image_one_tag.tags.add("one")
+
+ image_two_tags = Image.objects.create(
+ title="Test image with two tags",
+ file=get_test_image_file(),
+ )
+ image_two_tags.tags.add("one", "two")
+
+ # no filtering
+ response = self.get()
+ self.assertEqual(response.context['images'].paginator.count, 3)
+
+ # filter all images with tag 'one'
+ response = self.get({'tag': 'one'})
+ self.assertEqual(response.context['images'].paginator.count, 2)
+
+ # filter all images with tag 'two'
+ response = self.get({'tag': 'two'})
+ self.assertEqual(response.context['images'].paginator.count, 1)
+
+
+ def test_tag_filtering_preserves_other_params(self):
+ for i in range(1, 100):
+ image = Image.objects.create(
+ title="Test image %i" % i,
+ file=get_test_image_file(size=(1, 1)),
+ )
+ if (i % 2 != 0):
+ image.tags.add('even')
+ image.save()
+
+
+ response = self.get({'tag': 'even', 'p': 2})
+ self.assertEqual(response.status_code, 200)
+
+ response_body = response.content.decode('utf8')
+
+ # prev link should exist and include tag
+ self.assertTrue(
+ "?p=2&tag=even" in response_body
+ or "?tag=even&p=1" in response_body
+ )
+ # next link should exist and include tag
+ self.assertTrue(
+ "?p=3&tag=even" in response_body
+ or "?tag=even&p=3" in response_body
+ )
+
+
class TestImageAddView(TestCase, WagtailTestUtils):
def setUp(self):
self.login()
diff --git a/wagtail/images/views/images.py b/wagtail/images/views/images.py
index 3246ccb213..2c8bcb2cd2 100644
--- a/wagtail/images/views/images.py
+++ b/wagtail/images/views/images.py
@@ -59,6 +59,14 @@ def index(request):
except (ValueError, Collection.DoesNotExist):
pass
+ # Filter by tag
+ current_tag = request.GET.get('tag')
+ if current_tag:
+ try:
+ images = images.filter(tags__name=current_tag)
+ except (AttributeError):
+ current_tag = None
+
paginator = Paginator(images, per_page=INDEX_PAGE_SIZE)
images = paginator.get_page(request.GET.get('p'))
@@ -85,6 +93,7 @@ def index(request):
'search_form': form,
'popular_tags': popular_tags_for_model(Image),
+ 'current_tag': current_tag,
'collections': collections,
'current_collection': current_collection,
'user_can_add': permission_policy.user_has_permission(request.user, 'add'),