From cbed54a2634f5daae08a76d62d42945185534664 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 12 Aug 2018 01:33:51 -0600 Subject: [PATCH] Implemented minItems repeater property on client & server Also implemented maxItems on server (previously only client). Fixes https://github.com/octobercms/october/issues/3668 --- modules/backend/formwidgets/Repeater.php | 34 +++++++++++++++++-- .../repeater/assets/js/repeater.js | 8 +++++ .../repeater/partials/_repeater.htm | 1 + modules/backend/lang/en/lang.php | 4 +++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/modules/backend/formwidgets/Repeater.php b/modules/backend/formwidgets/Repeater.php index 2981a770a..15786a842 100644 --- a/modules/backend/formwidgets/Repeater.php +++ b/modules/backend/formwidgets/Repeater.php @@ -1,8 +1,9 @@ vars['prompt'] = $this->prompt; $this->vars['formWidgets'] = $this->formWidgets; $this->vars['titleFrom'] = $this->titleFrom; + $this->vars['minItems'] = $this->minItems; $this->vars['maxItems'] = $this->maxItems; $this->vars['useGroups'] = $this->useGroups; @@ -184,6 +192,13 @@ class Repeater extends FormWidgetBase } } + if ($this->minItems && count($value) < $this->minItems) { + throw new ApplicationException(Lang::get('backend::lang.repeater.min_items_failed', ['name' => $this->fieldName, 'min' => $this->minItems, 'items' => count($value)])); + } + if ($this->maxItems && count($value) > $this->maxItems) { + throw new ApplicationException(Lang::get('backend::lang.repeater.max_items_failed', ['name' => $this->fieldName, 'max' => $this->maxItems, 'items' => count($value)])); + } + return array_values($value); } @@ -196,6 +211,21 @@ class Repeater extends FormWidgetBase $loadedIndexes = $loadedGroups = []; $loadValue = $this->getLoadValue(); + // Ensure that the minimum number of items are preinitialized + // ONLY DONE WHEN NOT IN GROUP MODE + if (!$this->useGroups && $this->minItems > 0) { + if (!is_array($loadValue)) { + $loadValue = []; + for ($i = 0; $i < $this->minItems; $i++) { + $loadValue[$i] = []; + } + } elseif (count($loadValue) < $this->minItems) { + for ($i = 0; $i < ($this->minItems - count($loadValue)); $i++) { + $loadValue[] = []; + } + } + } + if (is_array($loadValue)) { foreach ($loadValue as $index => $loadedValue) { $loadedIndexes[] = $index; diff --git a/modules/backend/formwidgets/repeater/assets/js/repeater.js b/modules/backend/formwidgets/repeater/assets/js/repeater.js index 8e17827e5..042bba684 100644 --- a/modules/backend/formwidgets/repeater/assets/js/repeater.js +++ b/modules/backend/formwidgets/repeater/assets/js/repeater.js @@ -34,6 +34,7 @@ sortableHandle: '.repeater-item-handle', sortableContainer: 'ul.field-repeater-items', titleFrom: null, + minItems: null, maxItems: null } @@ -122,6 +123,13 @@ } Repeater.prototype.togglePrompt = function () { + if (this.options.minItems && this.options.minItems > 0) { + var repeatedItems = this.$el.find('> .field-repeater-items > .field-repeater-item').length, + $removeItemBtn = this.$el.find('> .field-repeater-items > .field-repeater-item > .repeater-item-remove') + + $removeItemBtn.toggle(repeatedItems > this.options.minItems) + } + if (this.options.maxItems && this.options.maxItems > 0) { var repeatedItems = this.$el.find('> .field-repeater-items > .field-repeater-item').length, $addItemBtn = this.$el.find('> .field-repeater-add-item') diff --git a/modules/backend/formwidgets/repeater/partials/_repeater.htm b/modules/backend/formwidgets/repeater/partials/_repeater.htm index 5cdfb0f06..995c42cd8 100644 --- a/modules/backend/formwidgets/repeater/partials/_repeater.htm +++ b/modules/backend/formwidgets/repeater/partials/_repeater.htm @@ -1,6 +1,7 @@
+ data-sortable-container="#getId('items') ?>" data-sortable-handle=".getId('items') ?>-handle"> diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index 7d6866bf6..d867786a1 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -217,6 +217,10 @@ return [ 'remove_confirm' => 'Are you sure?', 'remove_file' => 'Remove file' ], + 'repeater' => [ + 'min_items_failed' => ':name requires a minimum of :min items, only :items were provided', + 'max_items_failed' => ':name only allows up to :max items, :items were provided', + ], 'form' => [ 'create_title' => 'New :name', 'update_title' => 'Edit :name',