Merge pull request #2723 from octobercms/feature-RepeaterMaxItems

Add support for maxItems to the Repeater FormWidget. Thanks to @panakour for the initial work in #2710. Fixes #1710, #2649
This commit is contained in:
Luke Towers 2017-02-28 20:46:04 -06:00 committed by GitHub
commit fedf7b2b7d
2 changed files with 36 additions and 12 deletions

View File

@ -48,11 +48,16 @@ class Repeater extends FormWidgetBase
*/
protected $formWidgets = [];
/**
* @var bool Stops nested repeaters populating from previous sibling.
*/
/**
* @var bool Stops nested repeaters populating from previous sibling.
*/
protected static $onAddItemCalled = false;
/**
* @var int Maximum repeated items (0 == unlimited items)
*/
protected $maxItems = 0;
/**
* {@inheritDoc}
*/
@ -62,6 +67,7 @@ class Repeater extends FormWidgetBase
'form',
'prompt',
'sortable',
'maxItems',
]);
if (!self::$onAddItemCalled) {
@ -86,6 +92,7 @@ class Repeater extends FormWidgetBase
$this->vars['indexName'] = self::INDEX_PREFIX.$this->formField->getName(false).'[]';
$this->vars['prompt'] = $this->prompt;
$this->vars['formWidgets'] = $this->formWidgets;
$this->vars['maxItems'] = $this->maxItems;
}
/**

View File

@ -33,25 +33,28 @@
Repeater.DEFAULTS = {
sortableHandle: '.repeater-item-handle',
sortableContainer: 'ul.field-repeater-items',
titleFrom: null
titleFrom: null,
maxItems: null
}
Repeater.prototype.init = function() {
this.bindSorting()
this.$el.on('ajaxDone', '[data-repeater-remove]', this.proxy(this.onRemoveItemSuccess))
this.$el.on('ajaxDone', '[data-repeater-add]', this.proxy(this.onAddItemSuccess))
this.$el.on('ajaxDone', '> .field-repeater-items > .field-repeater-item > .repeater-item-remove > [data-repeater-remove]', this.proxy(this.onRemoveItemSuccess))
this.$el.on('ajaxDone', '> .field-repeater-add-item > [data-repeater-add]', this.proxy(this.onAddItemSuccess))
this.$el.on('click', '> ul > li > .repeater-item-collapse .repeater-item-collapse-one', this.proxy(this.toggleCollapse))
this.$el.one('dispose-control', this.proxy(this.dispose))
this.togglePrompt()
}
Repeater.prototype.dispose = function() {
this.$sortable.sortable('destroy')
this.$el.off('ajaxDone', '[data-repeater-remove]', this.proxy(this.onRemoveItemSuccess))
this.$el.off('ajaxDone', '[data-repeater-add]', this.proxy(this.onAddItemSuccess))
this.$el.off('click', '> ul > li > .repeater-item-collapse .repeater-item-collapse-one', this.proxy(this.toggleCollapse))
this.$el.off('ajaxDone', '> .field-repeater-items > .field-repeater-item > .repeater-item-remove > [data-repeater-remove]', this.proxy(this.onRemoveItemSuccess))
this.$el.off('ajaxDone', '> .field-repeater-add-item > [data-repeater-add]', this.proxy(this.onAddItemSuccess))
this.$el.off('click', '> .field-repeater-items > .field-repeater-item > .repeater-item-collapse .repeater-item-collapse-one', this.proxy(this.toggleCollapse))
this.$el.off('dispose-control', this.proxy(this.dispose))
this.$el.removeData('oc.repeater')
@ -79,10 +82,24 @@
Repeater.prototype.onRemoveItemSuccess = function(ev) {
$(ev.target).closest('.field-repeater-item').remove()
this.togglePrompt()
}
// This fires twice, not sure why
Repeater.prototype.onAddItemSuccess = function(ev) {
this.togglePrompt()
}
Repeater.prototype.togglePrompt = function () {
if (this.options.maxItems != 0) {
var repeatedItems = this.$el.find('> .field-repeater-items > .field-repeater-item').length,
$addItemBtn = this.$el.find('> .field-repeater-add-item')
if (repeatedItems >= this.options.maxItems) {
$addItemBtn.hide()
} else if (repeatedItems < this.options.maxItems) {
$addItemBtn.show()
}
}
}
Repeater.prototype.toggleCollapse = function(ev) {