diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 0ad6c1071d..85554a9a5a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -16,6 +16,7 @@ Changelog * Renamed `target_model` argument on `PageChooserBlock` to `page_type` (Loic Teixeira) * `edit_handler` and `panels` can now be defined on a `ModelAdmin` definition (Thomas Kremmel) * Add Learn Wagtail to third-party tutorials in documentation (Matt Westcott) + * Add a Django setting `TAG_LIMIT` to limit number of tags that can be added to any taggit model (Mani) * Fix: Set `SERVER_PORT` to 443 in `Page.dummy_request()` for HTTPS sites (Sergey Fedoseev) * Fix: Include port number in `Host` header of `Page.dummy_request()` (Sergey Fedoseev) * Fix: Validation error messages in `InlinePanel` no longer count towards `max_num` when disabling the 'add' button (Todd Dembrey, Thibaud Colas) diff --git a/docs/advanced_topics/settings.rst b/docs/advanced_topics/settings.rst index b4752ef18a..47751f6a16 100644 --- a/docs/advanced_topics/settings.rst +++ b/docs/advanced_topics/settings.rst @@ -384,6 +384,15 @@ Multi-word tags Tags can only consist of a single word, no spaces allowed. The default setting is ``True`` (spaces in tags are allowed). +Tag limit +--------- + +.. code-block:: python + + TAG_LIMIT = 5 + +Limit the number of tags that can be added to (django-taggit) Tag model. Default setting is ``None``, meaning no limit on tags. + Unicode Page Slugs ------------------ diff --git a/docs/releases/2.5.rst b/docs/releases/2.5.rst index b4cf7cf027..89b37fdee7 100644 --- a/docs/releases/2.5.rst +++ b/docs/releases/2.5.rst @@ -26,6 +26,7 @@ Other features * Renamed ``target_model`` argument on ``PageChooserBlock`` to ``page_type`` (Loic Teixeira) * ``edit_handler`` and ``panels`` can now be defined on a ``ModelAdmin`` definition (Thomas Kremmel) * Add Learn Wagtail to third-party tutorials in documentation (Matt Westcott) + * Add a Django setting ``TAG_LIMIT`` to limit number of tags that can be added to any taggit model (Mani) Bug fixes diff --git a/wagtail/admin/static_src/wagtailadmin/js/core.js b/wagtail/admin/static_src/wagtailadmin/js/core.js index 587195abc4..79eedd60c9 100644 --- a/wagtail/admin/static_src/wagtailadmin/js/core.js +++ b/wagtail/admin/static_src/wagtailadmin/js/core.js @@ -21,7 +21,7 @@ function escapeHtml(text) { }); } -function initTagField(id, autocompleteUrl, allowSpaces) { +function initTagField(id, autocompleteUrl, allowSpaces, tagLimit) { $('#' + id).tagit({ autocomplete: {source: autocompleteUrl}, preprocessTag: function(val) { @@ -34,7 +34,8 @@ function initTagField(id, autocompleteUrl, allowSpaces) { return val; }, - allowSpaces: allowSpaces + allowSpaces: allowSpaces, + tagLimit: tagLimit, }); } diff --git a/wagtail/admin/templates/wagtailadmin/widgets/tag_widget.html b/wagtail/admin/templates/wagtailadmin/widgets/tag_widget.html index 075b3a8e90..fb730fbff2 100644 --- a/wagtail/admin/templates/wagtailadmin/widgets/tag_widget.html +++ b/wagtail/admin/templates/wagtailadmin/widgets/tag_widget.html @@ -1 +1,9 @@ -{% include 'django/forms/widgets/text.html' %} \ No newline at end of file +{% include 'django/forms/widgets/text.html' %} + \ No newline at end of file diff --git a/wagtail/admin/tests/test_widgets.py b/wagtail/admin/tests/test_widgets.py index a26a687b64..251b33bfc3 100644 --- a/wagtail/admin/tests/test_widgets.py +++ b/wagtail/admin/tests/test_widgets.py @@ -157,3 +157,58 @@ class TestAdminDateTimeInput(TestCase): '"format": "d.m.Y. H:i"', html, ) + + +class TestAdminTagWidget(TestCase): + + def get_js_init_params(self, html): + """Returns a list of the params passed in to initTagField from the supplied HTML""" + # Eg. ["'test\\u002Did'", "'/admin/tag\\u002Dautocomplete/'", 'true', 'null'] + start = 'initTagField(' + end = ');' + items_after_init = html.split(start)[1] + if items_after_init: + params_raw = items_after_init.split(end)[0] + if params_raw: + return [part.strip() for part in params_raw.split(',')] + return [] + + + def test_render_js_init_basic(self): + """Chekcs that the 'initTagField' is correctly added to the inline script for tag widgets""" + widget = widgets.AdminTagWidget() + + html = widget.render('tags', None, attrs={'id': 'alpha'}) + params = self.get_js_init_params(html) + + self.assertEqual(len(params), 4) + self.assertEqual(params[0], "'alpha'") # id + self.assertEqual(params[1], "'/admin/tag\\u002Dautocomplete/'") # autocomplete url + self.assertEqual(params[2], 'true') # tag_spaces_allowed + self.assertEqual(params[3], 'null') # tag_limit + + + @override_settings(TAG_SPACES_ALLOWED=False) + def test_render_js_init_no_spaces_allowed(self): + """Chekcs that the 'initTagField' includes the correct value based on TAG_SPACES_ALLOWED in settings""" + widget = widgets.AdminTagWidget() + + html = widget.render('tags', None, attrs={'id': 'alpha'}) + params = self.get_js_init_params(html) + + self.assertEqual(len(params), 4) + self.assertEqual(params[2], 'false') # tag_spaces_allowed + self.assertEqual(params[3], 'null') # tag_limit + + + @override_settings(TAG_LIMIT=5) + def test_render_js_init_with_tag_limit(self): + """Chekcs that the 'initTagField' includes the correct value based on TAG_LIMIT in settings""" + widget = widgets.AdminTagWidget() + + html = widget.render('tags', None, attrs={'id': 'alpha'}) + params = self.get_js_init_params(html) + + self.assertEqual(len(params), 4) + self.assertEqual(params[2], 'true') # tag_spaces_allowed + self.assertEqual(params[3], '5') # tag_limit diff --git a/wagtail/admin/widgets.py b/wagtail/admin/widgets.py index 04e0b3c95f..8224169e84 100644 --- a/wagtail/admin/widgets.py +++ b/wagtail/admin/widgets.py @@ -101,6 +101,7 @@ class AdminTagWidget(TagWidget): context = super().get_context(name, value, attrs) context['widget']['autocomplete_url'] = reverse('wagtailadmin_tag_autocomplete') context['widget']['tag_spaces_allowed'] = getattr(settings, 'TAG_SPACES_ALLOWED', True) + context['widget']['tag_limit'] = getattr(settings, 'TAG_LIMIT', None) return context