From 4afdbdea5609cfcbb648bf53db23c3dd488425fe Mon Sep 17 00:00:00 2001 From: Maxxen Date: Mon, 25 May 2020 23:15:34 +0200 Subject: [PATCH] added maxNumChildBlocks property and callbacks to disable adding/removing child blocks to sequence. Also made streamfield add-buttons dissapear when capacity is reached (#6070) --- CHANGELOG.txt | 1 + CONTRIBUTORS.rst | 1 + docs/releases/2.10.rst | 1 + .../static_src/wagtailadmin/js/blocks/list.js | 1 + .../wagtailadmin/js/blocks/sequence.js | 15 ++++++++++++++ .../wagtailadmin/js/blocks/stream.js | 20 +++++++++++++++++++ wagtail/core/blocks/stream_block.py | 1 + 7 files changed, 40 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e80ac6a126..38cee0fe4c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -46,6 +46,7 @@ Changelog * Upgrade jQuery to version 3.5.1 to reduce penetration testing false positives (Matt Westcott) * Add ability to extend `EditHandler` without a children attribute (Seb Brown) * `Page.objects.specific` now gracefully handles pages with missing specific records (Andy Babic) + * StreamField 'add' buttons are now disabled when maximum count is reached (Max Gabrielsson) * Fix: Support IPv6 domain (Alex Gleason, Coen van der Kamp) * Fix: Ensure link to add a new user works when no users are visible in the users list (LB (Ben Johnston)) * Fix: `AbstractEmailForm` saved submission fields are now aligned with the email content fields, `form.cleaned_data` will be used instead of `form.fields` (Haydn Greatnews) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 0e8929b600..4f8f801661 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -469,6 +469,7 @@ Contributors * Nikolay Lukyanov (mozgsml) * Jean Zombie * Pascal Widdershoven +* Max Gabrielsson Translators =========== diff --git a/docs/releases/2.10.rst b/docs/releases/2.10.rst index 845e7d3fa2..fadda5c7c8 100644 --- a/docs/releases/2.10.rst +++ b/docs/releases/2.10.rst @@ -64,6 +64,7 @@ Other features * Upgrade jQuery to version 3.5.1 to reduce penetration testing false positives (Matt Westcott) * Add ability to extend ``EditHandler`` without a children attribute (Seb Brown) * ``Page.objects.specific`` now gracefully handles pages with missing specific records (Andy Babic) + * StreamField 'add' buttons are now disabled when maximum count is reached (Max Gabrielsson) Bug fixes diff --git a/wagtail/admin/static_src/wagtailadmin/js/blocks/list.js b/wagtail/admin/static_src/wagtailadmin/js/blocks/list.js index 763fd53ed2..9cbd13215a 100644 --- a/wagtail/admin/static_src/wagtailadmin/js/blocks/list.js +++ b/wagtail/admin/static_src/wagtailadmin/js/blocks/list.js @@ -9,6 +9,7 @@ return function(elementPrefix) { var sequence = Sequence({ prefix: elementPrefix, + maxNumChildBlocks: Infinity, onInitializeMember: function(sequenceMember) { /* initialize child block's JS behaviour */ if (opts.childInitializer) { diff --git a/wagtail/admin/static_src/wagtailadmin/js/blocks/sequence.js b/wagtail/admin/static_src/wagtailadmin/js/blocks/sequence.js index c3c37609b4..c1c3eddd70 100644 --- a/wagtail/admin/static_src/wagtailadmin/js/blocks/sequence.js +++ b/wagtail/admin/static_src/wagtailadmin/js/blocks/sequence.js @@ -115,6 +115,11 @@ CODE FOR SETTING UP SPECIFIC UI WIDGETS, SUCH AS DELETE BUTTONS OR MENUS, DOES N } newMember._markAdded(); + + if (members.length >= opts.maxNumChildBlocks && opts.onDisableAdd) { + /* maximum block capacity has been reached */ + opts.onDisableAdd(members) + } } function elementFromTemplate(template, newPrefix) { @@ -247,6 +252,11 @@ CODE FOR SETTING UP SPECIFIC UI WIDGETS, SUCH AS DELETE BUTTONS OR MENUS, DOES N /* deleting the last member; the new last member cannot move down now */ opts.onDisableMoveDown(members[members.length - 1]); } + + if (members.length + 1 >= opts.maxNumChildBlocks && members.length < opts.maxNumChildBlocks && opts.onEnableAdd) { + /* there is now capacity left for another block */ + opts.onEnableAdd(members) + } }; self.moveMemberUp = function(member) { @@ -342,6 +352,11 @@ CODE FOR SETTING UP SPECIFIC UI WIDGETS, SUCH AS DELETE BUTTONS OR MENUS, DOES N } } + if (members.length >= opts.maxNumChildBlocks && opts.onDisableAdd) { + /* block capacity is already reached on initialization */ + opts.onDisableAdd(members) + } + return self; }; })(jQuery); diff --git a/wagtail/admin/static_src/wagtailadmin/js/blocks/stream.js b/wagtail/admin/static_src/wagtailadmin/js/blocks/stream.js index fa434b5452..fce5a5989f 100644 --- a/wagtail/admin/static_src/wagtailadmin/js/blocks/stream.js +++ b/wagtail/admin/static_src/wagtailadmin/js/blocks/stream.js @@ -81,6 +81,7 @@ return function(elementPrefix) { var sequence = Sequence({ prefix: elementPrefix, + maxNumChildBlocks: opts.maxNumChildBlocks, onInitializeMember: function(sequenceMember) { /* initialize child block's JS behaviour */ var blockTypeName = $('#' + sequenceMember.prefix + '-type').val(); @@ -129,6 +130,25 @@ onDisableMoveDown: function(sequenceMember) { $('#' + sequenceMember.prefix + '-movedown').addClass('disabled'); + }, + + onDisableAdd: function(members) { + for (var i = 0; i < members.length; i++){ + $('#' + members[i].prefix + '-appendmenu-openclose') + .removeClass('c-sf-add-button--visible').delay(300).slideUp() + } + $('#' + elementPrefix + '-prependmenu-openclose') + .removeClass('c-sf-add-button--visible').delay(300).slideUp() + }, + + onEnableAdd: function(members) { + for (var i = 0; i < members.length; i++){ + + $('#' + members[i].prefix + '-appendmenu-openclose') + .addClass('c-sf-add-button--visible').delay(300).slideDown() + } + $('#' + elementPrefix + '-prependmenu-openclose') + .addClass('c-sf-add-button--visible').delay(300).slideDown() } }); diff --git a/wagtail/core/blocks/stream_block.py b/wagtail/core/blocks/stream_block.py index 3390405e86..1f9e8f2010 100644 --- a/wagtail/core/blocks/stream_block.py +++ b/wagtail/core/blocks/stream_block.py @@ -118,6 +118,7 @@ class BaseStreamBlock(Block): opts = { 'definitionPrefix': "'%s'" % self.definition_prefix, 'childBlocks': '[\n%s\n]' % ',\n'.join(child_blocks), + 'maxNumChildBlocks': 'Infinity' if self.meta.max_num is None else ('%s' % self.meta.max_num), } return "StreamBlock(%s)" % js_dict(opts)