Skip to content

Commit

Permalink
Some upgrades to Repeater and RepeaterMatrix: Added processwire/proce…
Browse files Browse the repository at this point in the history
…sswire-requests#474 which enables open/close for family groups of repeater items together, so that when using depths, and you open (or close) a repeater item, items that are visually children of it also open (or close). To enable, see the field "Details" tab setting in "Repeater depths/indents" > "Open/close items as a family?". Also added a configuration setting that enables you do disable the automatic scrolling to newly added items, as requested by @hiboudev
  • Loading branch information
ryancramerdesign committed Feb 14, 2024
1 parent a5f6cab commit caa8e7e
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 7 deletions.
64 changes: 60 additions & 4 deletions wire/modules/Fieldtype/FieldtypeRepeater/InputfieldRepeater.js
Expand Up @@ -3,12 +3,11 @@
*
* Maintains a collection of fields that are repeated for any number of times.
*
* ProcessWire 3.x, Copyright 2021 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
*/


function InputfieldRepeater($) {

/**
Expand Down Expand Up @@ -49,9 +48,17 @@ function InputfieldRepeater($) {
* Page version, if PagesVersions active
*
* @type {number}
*
*/
var pageVersion = 0;


/**
* Non-false when we are toggling family item visibility
*
* @type {boolean|number}
*
*/
var togglingItemVisibility = false;

/*** EVENTS ********************************************************************************************/

Expand Down Expand Up @@ -339,6 +346,51 @@ function InputfieldRepeater($) {
if(parseInt($loaded.val()) > 0) return; // item already loaded
$item.addClass('InputfieldRepeaterItemLoading');
};

/**
* Toggle visibility of children/siblings
*
* @param $item
* @param open
*
*/
function toggleItemFamilyVisibility($item, open) {
var $inputfield = $item.closest('.InputfieldRepeater');

if(!$inputfield.hasClass('InputfieldRepeaterFamilyToggle')) return;
if(!$inputfield.hasClass('InputfieldRepeaterDepth')) return;
if($inputfield.hasClass('InputfieldRepeaterAccordion')) false;

var depth = getItemDepth($item);
var $nextItem = $item.next('.InputfieldRepeaterItem');

if($nextItem.length) {
var nextDepth = getItemDepth($nextItem);
if(nextDepth > depth) {
// child item
togglingItemVisibility = nextDepth;
open ? Inputfields.open($nextItem) : Inputfields.close($nextItem);
} else if(nextDepth === depth && depth > 0 && togglingItemVisibility) {
// next sibling item
open ? Inputfields.open($nextItem) : Inputfields.close($nextItem);
} else {
// finished
togglingItemVisibility = false;
}
} else {
togglingItemVisibility = false;
}
}

/**
* Called when an item has finished opening
*
* @param $item
*
*/
function itemOpenComplete($item) {
toggleItemFamilyVisibility($item, true);
}

/**
* Event handler for when a repeater item is opened (primarily focused on ajax loaded items)
Expand All @@ -353,6 +405,7 @@ function InputfieldRepeater($) {

if(parseInt($loaded.val()) > 0) {
updateAccordion($item);
toggleItemFamilyVisibility($item, true);
return; // item already loaded
}

Expand Down Expand Up @@ -402,6 +455,7 @@ function InputfieldRepeater($) {

setTimeout(function() {
$inputfields.find('.Inputfield').trigger('reloaded', ['InputfieldRepeaterItemEdit']);
itemOpenComplete($item);
}, 50);

runScripts(data);
Expand All @@ -415,6 +469,7 @@ function InputfieldRepeater($) {
*/
var eventItemClosed = function() {
updateState($(this));
toggleItemFamilyVisibility($(this), false);
};

/**
Expand Down Expand Up @@ -543,7 +598,7 @@ function InputfieldRepeater($) {
if(depth) setItemDepth($addItem, depth);
if($addItem.hasClass('InputfieldStateCollapsed')) {
// ok
} else {
} else if(!$inputfieldRepeater.hasClass('InputfieldRepeaterNoScroll')) {
$('html, body').animate({
scrollTop: $addItem.offset().top
}, 500, 'swing');
Expand Down Expand Up @@ -1438,6 +1493,7 @@ function InputfieldRepeater($) {
* @param $item
*/
function scrollToItem($item) {
if($item.closest('.InputfieldRepeater').hasClass('InputfieldRepeaterNoScroll')) return;
$('html, body').animate({scrollTop: $item.offset().top - 10}, 250, 'swing');
}

Expand Down

Large diffs are not rendered by default.

Expand Up @@ -5,16 +5,18 @@
*
* Maintains a collection of fields that are repeated for any number of times.
*
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
* ProcessWire 3.x, Copyright 2024 by Ryan Cramer
* https://processwire.com
*
* @property int $repeaterMaxItems
* @property int $repeaterMinItems
* @property int $repeaterDepth
* @property bool|int $familyFriendly
* @property bool|int $familyToggle
* @property bool|int $accordionMode
* @property bool|int $singleMode
* @property bool|int $loudControls Always show controls regardless of hover?
* @property bool|int $noScroll Do not scroll to newly added items?
*
* @method string renderRepeaterLabel($label, $cnt, Page $page)
*
Expand Down Expand Up @@ -103,9 +105,11 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
$this->set('repeaterMinItems', 0);
$this->set('repeaterDepth', 0);
$this->set('familyFriendly', 0);
$this->set('familyToggle', 0);
$this->set('accordionMode', false);
$this->set('singleMode', false);
$this->set('loudControls', false);
$this->set('noScroll', false);
}

/**
Expand Down Expand Up @@ -803,6 +807,12 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
if($this->loudControls || $this->wire()->session->get('touch')) {
$this->addClass('InputfieldRepeaterLoudControls', 'wrapClass');
}
if($this->noScroll) {
$this->addClass('InputfieldRepeaterNoScroll', 'wrapClass');
}
if($this->familyToggle) {
$this->addClass('InputfieldRepeaterFamilyToggle', 'wrapClass');
}
if(!empty($_COOKIE[$this->copyPasteCookieName()])) {
$this->addClass('InputfieldRepeaterCanPaste', 'wrapClass');
}
Expand Down
30 changes: 29 additions & 1 deletion wire/modules/Fieldtype/FieldtypeRepeater/config.php
Expand Up @@ -181,6 +181,18 @@ public function getConfigInputfields(InputfieldWrapper $inputfields, Template $t
$f->val((int) $field->get('familyFriendly'));
$f->columnWidth = 50;
$fs->add($f);

/** @var InputfieldToggle $f */
$f = $modules->get('InputfieldToggle');
$f->attr('name', 'familyToggle');
$f->label = $this->_('Open/close items as a family?');
$f->description =
$this->_('When enabled, opening (or closing) a repeater item also opens (or closes) the next items that are visually children of it.') . ' ' .
$this->_('This is best combined with family-friendly item depth mode.');
$f->notes =
$this->_('Note that this setting is not compatible with accordion mode.');
$f->val((int) $field->get('familyToggle'));
$fs->add($f);

// -------------------------------------------------

Expand Down Expand Up @@ -285,6 +297,19 @@ public function getConfigInputfields(InputfieldWrapper $inputfields, Template $t
$f->val((int) $field->get('loudControls'));
$fs->add($f);

// -------------------------------------------------

/** @var InputfieldToggle $f */
$f = $modules->get('InputfieldToggle');
$f->attr('name', 'noScroll');
$f->label = $this->_('Scroll to new item when added?');
$f->labelType = InputfieldToggle::labelTypeCustom;
$f->yesLabel = $this->_('Disabled');
$f->noLabel = $this->_('Enabled');
$f->icon = 'arrow-down';
$f->val((int) $field->get('noScroll'));
$fs->add($f);

// -------------------------------------------------

$maxItems = (int) $field->get('repeaterMaxItems');
Expand Down Expand Up @@ -368,6 +393,9 @@ protected function getConfigInputfieldsStorage(InputfieldWrapper $inputfields) {
$this->_('Currently an experimental option for testing (lazyParents), but will later become default.');
if($this->field->get('lazyParents')) $f->attr('checked', 'checked');
$fs->add($f);

// @todo setting focus first visible input in repeater item on open
// @todo setting to disable the auto-scroll when adding an item

/** @var InputfieldCheckbox $f */
$f = $modules->get('InputfieldCheckbox');
Expand Down Expand Up @@ -505,4 +533,4 @@ public function getConfigAdvancedInputfields(InputfieldWrapper $inputfields) {
$inputfields->remove($inputfields->get('global'));
}

}
}

0 comments on commit caa8e7e

Please sign in to comment.