1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-18 20:41:16 +02:00

Add option to repeaters enabling you to specify whether repeater item controls (delete, insert, clone, etc.) should be always visible or visible only when the header is hovered. Updated the default to be visible when only hovered as this reduces clutter. This commit also fixes an issue with custom header background colors (in matrix) not supporting matrix item type names that started with a number (i.e. "1-column-text"). This commit also fixes processwire/processwire-issues#1472 where the usual left/right outlines weren't showing for opened repeater items.

This commit is contained in:
Ryan Cramer
2021-12-02 11:32:23 -05:00
parent 46215bdfc2
commit b364eda4ef
7 changed files with 95 additions and 36 deletions

View File

@@ -33,7 +33,7 @@ class FieldtypeRepeater extends Fieldtype implements ConfigurableModule {
return array(
'title' => __('Repeater', __FILE__), // Module Title
'summary' => __('Maintains a collection of fields that are repeated for any number of times.', __FILE__), // Module Summary
'version' => 110,
'version' => 111,
'autoload' => true,
'installs' => 'InputfieldRepeater'
);

File diff suppressed because one or more lines are too long

View File

@@ -934,9 +934,11 @@ function InputfieldRepeater($) {
$item.attr('data-depth', depth);
if(depth > 0) {
$item.css('margin-left', (depth * depthSize) + 'px');
$item.css('padding-left', (depth * depthSize) + 'px');
$item.addClass('InputfieldRepeaterItemHasDepth');
} else {
$item.css('margin-left', 0);
$item.css('padding-left', 0);
$item.removeClass('InputfieldRepeaterItemHasDepth');
}
return depth;
@@ -1044,12 +1046,17 @@ function InputfieldRepeater($) {
var $depth = $wrap.find('input');
var depth = $depth.val();
var $item = $depth.closest('.InputfieldRepeaterItem');
var currentLeft = $item.css('margin-left');
var currentLeft = $item.css('padding-left');
if(currentLeft == 'auto') currentLeft = 0;
currentLeft = parseInt(currentLeft);
var targetLeft = depth * depthSize;
if(targetLeft != currentLeft) {
$item.css('margin-left', targetLeft + 'px');
$item.css('padding-left', targetLeft + 'px');
}
if(targetLeft > 0) {
$item.addClass('InputfieldRepeaterItemHasDepth');
} else {
$item.removeClass('InputfieldRepeaterItemHasDepth');
}
});
$inputfieldRepeater.children('.InputfieldContent').css('position', 'relative');
@@ -1149,10 +1156,10 @@ function InputfieldRepeater($) {
var $header = ui.item.children('.InputfieldHeader');
if(depth > maxDepth) {
// beyond max depth allowed
$header.addClass('ui-state-error');
$header.addClass('ui-state-error InputfieldRepeaterItemOOB'); // OOB: Out Of Bounds
} else if($header.hasClass('ui-state-error')) {
// no problems
$header.removeClass('ui-state-error');
$header.removeClass('ui-state-error InputfieldRepeaterItemOOB');
}
};
} else {
@@ -1266,6 +1273,7 @@ function InputfieldRepeater($) {
}
if($inputfields.hasClass('InputfieldRepeaterInit')) return;
if($('body').hasClass('touch-device')) $inputfieldRepeater.addClass('InputfieldRepeaterLoudControls');
var renderValueMode = $inputfields.closest('.InputfieldRenderValueMode').length > 0;

File diff suppressed because one or more lines are too long

View File

@@ -12,8 +12,9 @@
* @property int $repeaterMinItems
* @property int $repeaterDepth
* @property bool|int $familyFriendly
* @property bool $accordionMode
* @property bool $singleMode
* @property bool|int $accordionMode
* @property bool|int $singleMode
* @property bool|int $loudControls Always show controls regardless of hover?
*
* @method string renderRepeaterLabel($label, $cnt, Page $page)
*
@@ -26,7 +27,7 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
return array(
'title' => __('Repeater', __FILE__), // Module Title
'summary' => __('Repeats fields from another template. Provides the input for FieldtypeRepeater.', __FILE__), // Module Summary
'version' => 110,
'version' => 111,
'requires' => 'FieldtypeRepeater',
);
}
@@ -104,6 +105,7 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
$this->set('familyFriendly', 0);
$this->set('accordionMode', false);
$this->set('singleMode', false);
$this->set('loudControls', false);
}
/**
@@ -479,10 +481,10 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
// background-color definition
if(strlen($matches[1]) === 3 || strlen($matches[1]) === 6) {
$wrapLabel = str_replace($matches[0], '', $wrapLabel);
$typeStyles[] =
$typeStyles[$itemTypeName] =
".Inputfield_$this->name .InputfieldContent " .
".InputfieldRepeaterItem[data-typeName=$itemTypeName] > .InputfieldHeader " .
"{ background-color: #$matches[1] }";
".InputfieldRepeaterItem[data-typeName=\"$itemTypeName\"] > .InputfieldHeader " .
"{ background-color: #$matches[1]; outline-color: #$matches[1] }";
}
}
@@ -773,6 +775,9 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
if($this->accordionMode) {
$this->addClass('InputfieldRepeaterAccordion', 'wrapClass');
}
if($this->loudControls || $this->wire()->session->get('touch')) {
$this->addClass('InputfieldRepeaterLoudControls', 'wrapClass');
}
if(!empty($_COOKIE[$this->copyPasteCookieName()])) {
$this->addClass('InputfieldRepeaterCanPaste', 'wrapClass');
}

View File

@@ -16,10 +16,9 @@
}
}
// prevents longer item headers from going outside Inputfield box horizontally
.InputfieldRepeaterItem {
max-width: 100%;
overflow-x: hidden;
.InputfieldRepeaterItemHasDepth {
// avoids white left background where indent is
background: transparent;
}
.InputfieldRepeaterItem > .InputfieldHeader {
@@ -41,6 +40,7 @@
}
.InputfieldRepeaterItemControls {
display: block;
opacity: 1.0;
padding-right: 0.5em;
padding-left: 0.5em;
margin-top: 0.5em;
@@ -48,10 +48,8 @@
top: 0;
right: 0;
z-index: 1;
display: block;
white-space: nowrap;
height: 100%;
.InputfieldRepeaterSettingsToggle,
.InputfieldRepeaterClone,
@@ -88,15 +86,54 @@
opacity: 0.3;
}
}
&:hover .InputfieldRepeaterItemControls {
opacity: 1.0;
transition: opacity 300ms;
}
&.InputfieldRepeaterItemOOB .InputfieldRepeaterItemControls {
// items out of bounds (OOB) hide controls
display: none;
}
.toggle-icon {
line-height: 1em;
margin-right: 0.5em;
}
}
}
.InputfieldRepeaterItem {
// prevents longer item headers from going outside Inputfield box horizontally
max-width: 100%;
box-sizing: border-box;
// repeater item that has DELETE pending
&.InputfieldRepeaterDeletePending {
> .InputfieldRepeaterHeaderInit > .InputfieldRepeaterItemControls {
// keep just the trash icon visible when item marked for deletion
display: block;
opacity: 1.0;
*:not(.InputfieldRepeaterTrash):not(.toggle-icon) {
display: none !important;
}
}
}
}
&:not(.InputfieldRepeaterLoudControls) > .InputfieldContent > .Inputfields > .InputfieldRepeaterItem {
// repeater item that does NOT have delete pending
&:not(.InputfieldRepeaterDeletePending) {
> .InputfieldRepeaterHeaderInit:not(:hover) > .InputfieldRepeaterItemControls {
opacity: 0;
transition: opacity 500ms;
}
}
}
& > .InputfieldContent > .Inputfields > .InputfieldRepeaterInsertItem {
opacity: 0.5;
}

View File

@@ -260,32 +260,41 @@ class FieldtypeRepeaterConfigHelper extends Wire {
// -------------------------------------------------
/** @var InputfieldCheckbox $f */
$f = $modules->get('InputfieldCheckbox');
/** @var InputfieldToggle $f */
$f = $modules->get('InputfieldToggle');
$f->attr('name', 'rememberOpen');
$f->label = $this->_('Remember which repeater items are open?');
$f->description = $this->_('When checked, opened repeater items remain open after saving or reloading from the page editor (unless the user closes them).');
$f->description = $this->_('When enabled, opened repeater items remain open after saving or reloading from the page editor (unless the user closes them).');
$f->icon = 'lightbulb-o';
if((int) $field->get('rememberOpen')) {
$f->attr('checked', 'checked');
}
$f->columnWidth = 50;
$f->val((int) $field->get('rememberOpen'));
$fs->add($f);
// -------------------------------------------------
/** @var InputfieldCheckbox $f */
$f = $modules->get('InputfieldCheckbox');
/** @var InputfieldToggle $f */
$f = $modules->get('InputfieldToggle');
$f->attr('name', 'accordionMode');
$f->label = $this->_('Use accordion mode?');
$f->description = $this->_('When checked, only one repeater item will be open at a time.');
$f->description = $this->_('When enabled, only one repeater item will be open at a time.');
$f->icon = 'map-o';
if((int) $field->get('accordionMode')) {
$f->attr('checked', 'checked');
}
$f->columnWidth = 50;
$f->val((int) $field->get('accordionMode'));
$fs->add($f);
// -------------------------------------------------
/** @var InputfieldToggle $f */
$f = $modules->get('InputfieldToggle');
$f->attr('name', 'loudControls');
$f->label = $this->_('When to show repeater item controls/actions');
$f->labelType = InputfieldToggle::labelTypeCustom;
$f->yesLabel = $this->_('Always');
$f->noLabel = $this->_('Hover');
$f->description = $this->_('The hover option can reduce clutter in the interface by showing the repeater item actions/controls (clone, insert, delete, etc.) only when the item header is hovered.');
$f->notes = $this->_('Note that controls are always shown for touch devices regardless of this setting.');
$f->icon = 'sliders';
$f->val((int) $field->get('loudControls'));
$fs->add($f);
// -------------------------------------------------
$maxItems = (int) $field->get('repeaterMaxItems');