diff --git a/administrator/components/com_users/config.xml b/administrator/components/com_users/config.xml
index 1985f666fad2..652a307306e2 100644
--- a/administrator/components/com_users/config.xml
+++ b/administrator/components/com_users/config.xml
@@ -124,7 +124,7 @@
label="COM_USERS_CONFIG_FIELD_DOMAINS_LABEL"
hiddenLabel="true"
multiple="true"
- layout="joomla.form.field.subform.repeatable-table"
+ layout="joomla.form.field.subform.repeatable-grid"
formsource="administrator/components/com_users/forms/config_domain.xml"
/>
</fieldset>
diff --git a/administrator/language/en-GB/plg_fields_subform.ini b/administrator/language/en-GB/plg_fields_subform.ini
index e920859e598e..72d787eeee66 100644
--- a/administrator/language/en-GB/plg_fields_subform.ini
+++ b/administrator/language/en-GB/plg_fields_subform.ini
@@ -7,6 +7,7 @@ PLG_FIELDS_SUBFORM="Fields - Subform"
PLG_FIELDS_SUBFORM_LABEL="Subform (%s)"
PLG_FIELDS_SUBFORM_PARAMS_CUSTOMFIELD_LABEL="Field"
PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_FORM_LABEL="Form"
+PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_GRID_LABEL="Form Grid"
PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_TABLE_LABEL="Table"
PLG_FIELDS_SUBFORM_PARAMS_MAX_ROWS_LABEL="Maximum Rows"
PLG_FIELDS_SUBFORM_PARAMS_OPTIONS_LABEL="Fields"
diff --git a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss b/build/media_source/templates/administrator/atum/scss/blocks/_form.scss
index 4f50b115fd0c..aa65e32b7c49 100644
--- a/build/media_source/templates/administrator/atum/scss/blocks/_form.scss
+++ b/build/media_source/templates/administrator/atum/scss/blocks/_form.scss
@@ -240,6 +240,41 @@ div.subform-repeatable-group {
}
}
+// Subform Grid layout
+.subform-repeatable-grid>.subform-repeatable-group {
+ padding-top: 16px;
+}
+.subform-grid-row {
+ display: flex;
+ flex-flow: row wrap;
+ column-gap: 1rem;
+
+ > .control-group {
+ flex: 1 1 220px;
+ flex-flow: column;
+
+ > .control-label {
+ width: 100%;
+ }
+
+ > .controls {
+ width: 100%;
+ min-width: unset;
+ }
+ }
+
+ // For groupByFieldset="true"
+ > fieldset {
+ flex: 1 1 220px;
+
+ > .control-group {
+ > .control-label {
+ width: 100%;
+ }
+ }
+ }
+}
+
// Highlight draggable section
.subform-repeatable-group[draggable="true"] {
// For non table layout
diff --git a/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss b/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss
index 41fa174ae191..6a8d1a1a9d05 100644
--- a/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss
+++ b/build/media_source/templates/site/cassiopeia/scss/blocks/_form.scss
@@ -212,6 +212,41 @@ div.subform-repeatable-group {
}
}
+// Subform Grid layout
+.subform-repeatable-grid>.subform-repeatable-group {
+ padding-top: 16px;
+}
+.subform-grid-row {
+ display: flex;
+ flex-flow: row wrap;
+ column-gap: 1rem;
+
+ > .control-group {
+ flex: 1 1 220px;
+ flex-flow: column;
+
+ > .control-label {
+ width: 100%;
+ }
+
+ > .controls {
+ width: 100%;
+ min-width: unset;
+ }
+ }
+
+ // For groupByFieldset="true"
+ > fieldset {
+ flex: 1 1 220px;
+
+ > .control-group {
+ > .control-label {
+ width: 100%;
+ }
+ }
+ }
+}
+
// Highlight draggable section
.subform-repeatable-group[draggable="true"] {
// For non table layout
diff --git a/layouts/joomla/form/field/subform/repeatable-grid.php b/layouts/joomla/form/field/subform/repeatable-grid.php
new file mode 100644
index 000000000000..73056dfad5d4
--- /dev/null
+++ b/layouts/joomla/form/field/subform/repeatable-grid.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @package Joomla.Site
+ * @subpackage Layout
+ *
+ * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Factory;
+use Joomla\CMS\Form\Form;
+use Joomla\CMS\Language\Text;
+
+extract($displayData);
+
+/**
+ * Layout variables
+ * -----------------
+ * @var Form $tmpl The Empty form for template
+ * @var array $forms Array of JForm instances for render the rows
+ * @var bool $multiple The multiple state for the form field
+ * @var int $min Count of minimum repeating in multiple mode
+ * @var int $max Count of maximum repeating in multiple mode
+ * @var string $name Name of the input field.
+ * @var string $fieldname The field name
+ * @var string $fieldId The field ID
+ * @var string $control The forms control
+ * @var string $label The field label
+ * @var string $description The field description
+ * @var string $class Classes for the container
+ * @var array $buttons Array of the buttons that will be rendered
+ * @var bool $groupByFieldset Whether group the subform fields by it`s fieldset
+ */
+if ($multiple) {
+ // Add script
+ Factory::getApplication()
+ ->getDocument()
+ ->getWebAssetManager()
+ ->useScript('webcomponent.field-subform');
+}
+
+$class = $class ? ' ' . $class : '';
+
+$sublayout = empty($groupByFieldset) ? 'section' : 'section-byfieldsets';
+?>
+
+<div class="subform-repeatable-wrapper subform-layout-grid">
+ <joomla-field-subform class="subform-repeatable<?php echo $class; ?> subform-repeatable-grid" name="<?php echo $name; ?>"
+ button-add=".group-add" button-remove=".group-remove" button-move="<?php echo empty($buttons['move']) ? '' : '.group-move' ?>"
+ repeatable-element=".subform-repeatable-group" minimum="<?php echo $min; ?>" maximum="<?php echo $max; ?>">
+ <?php if (!empty($buttons['add'])) : ?>
+ <div class="btn-toolbar">
+ <div class="btn-group">
+ <button type="button" class="group-add btn btn-sm button btn-success" aria-label="<?php echo Text::_('JGLOBAL_FIELD_ADD'); ?>">
+ <span class="icon-plus icon-white" aria-hidden="true"></span>
+ </button>
+ </div>
+ </div>
+ <?php endif; ?>
+ <?php
+ foreach ($forms as $k => $form) :
+ echo $this->sublayout($sublayout, ['form' => $form, 'basegroup' => $fieldname, 'group' => $fieldname . $k, 'buttons' => $buttons]);
+ endforeach;
+ ?>
+ <?php if ($multiple) : ?>
+ <template class="subform-repeatable-template-section hidden"><?php
+ echo trim($this->sublayout($sublayout, ['form' => $tmpl, 'basegroup' => $fieldname, 'group' => $fieldname . 'X', 'buttons' => $buttons]));
+ ?></template>
+ <?php endif; ?>
+ </joomla-field-subform>
+</div>
diff --git a/layouts/joomla/form/field/subform/repeatable-grid/section-byfieldsets.php b/layouts/joomla/form/field/subform/repeatable-grid/section-byfieldsets.php
new file mode 100644
index 000000000000..210b8c6a7bb3
--- /dev/null
+++ b/layouts/joomla/form/field/subform/repeatable-grid/section-byfieldsets.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @package Joomla.Site
+ * @subpackage Layout
+ *
+ * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Form\Form;
+use Joomla\CMS\Language\Text;
+
+extract($displayData);
+
+/**
+ * Layout variables
+ * -----------------
+ * @var Form $form The form instance for render the section
+ * @var string $basegroup The base group name
+ * @var string $group Current group name
+ * @var array $buttons Array of the buttons that will be rendered
+ */
+?>
+
+<div class="subform-repeatable-group" data-base-name="<?php echo $basegroup; ?>" data-group="<?php echo $group; ?>">
+ <?php if (!empty($buttons)) : ?>
+ <div class="btn-toolbar text-end">
+ <div class="btn-group">
+ <?php if (!empty($buttons['add'])) :
+ ?><button type="button" class="group-add btn btn-sm btn-success" aria-label="<?php echo Text::_('JGLOBAL_FIELD_ADD'); ?>"><span class="icon-plus icon-white" aria-hidden="true"></span> </button><?php
+ endif; ?>
+ <?php if (!empty($buttons['remove'])) :
+ ?><button type="button" class="group-remove btn btn-sm btn-danger" aria-label="<?php echo Text::_('JGLOBAL_FIELD_REMOVE'); ?>"><span class="icon-minus icon-white" aria-hidden="true"></span> </button><?php
+ endif; ?>
+ <?php if (!empty($buttons['move'])) :
+ ?><button type="button" class="group-move btn btn-sm btn-primary" aria-label="<?php echo Text::_('JGLOBAL_FIELD_MOVE'); ?>"><span class="icon-arrows-alt icon-white" aria-hidden="true"></span> </button><?php
+ endif; ?>
+ </div>
+ </div>
+ <?php endif; ?>
+ <div class="subform-grid-row">
+ <?php foreach ($form->getFieldsets() as $fieldset) : ?>
+ <fieldset class="<?php echo !empty($fieldset->class) ? $this->escape($fieldset->class) : ''; ?>">
+ <?php if (!empty($fieldset->label)) : ?>
+ <legend><?php echo Text::_($fieldset->label); ?></legend>
+ <?php endif; ?>
+ <?php foreach ($form->getFieldset($fieldset->name) as $field) : ?>
+ <?php echo $field->renderField(); ?>
+ <?php endforeach; ?>
+ </fieldset>
+ <?php endforeach; ?>
+ </div>
+</div>
diff --git a/layouts/joomla/form/field/subform/repeatable-grid/section.php b/layouts/joomla/form/field/subform/repeatable-grid/section.php
new file mode 100644
index 000000000000..fbd2c10b4019
--- /dev/null
+++ b/layouts/joomla/form/field/subform/repeatable-grid/section.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @package Joomla.Site
+ * @subpackage Layout
+ *
+ * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Form\Form;
+use Joomla\CMS\Language\Text;
+
+extract($displayData);
+
+/**
+ * Layout variables
+ * -----------------
+ * @var Form $form The form instance for render the section
+ * @var string $basegroup The base group name
+ * @var string $group Current group name
+ * @var array $buttons Array of the buttons that will be rendered
+ */
+?>
+
+<div class="subform-repeatable-group" data-base-name="<?php echo $basegroup; ?>" data-group="<?php echo $group; ?>">
+ <?php if (!empty($buttons)) : ?>
+ <div class="btn-toolbar text-end">
+ <div class="btn-group">
+ <?php if (!empty($buttons['add'])) :
+ ?><button type="button" class="group-add btn btn-sm btn-success" aria-label="<?php echo Text::_('JGLOBAL_FIELD_ADD'); ?>"><span class="icon-plus icon-white" aria-hidden="true"></span> </button><?php
+ endif; ?>
+ <?php if (!empty($buttons['remove'])) :
+ ?><button type="button" class="group-remove btn btn-sm btn-danger" aria-label="<?php echo Text::_('JGLOBAL_FIELD_REMOVE'); ?>"><span class="icon-minus icon-white" aria-hidden="true"></span> </button><?php
+ endif; ?>
+ <?php if (!empty($buttons['move'])) :
+ ?><button type="button" class="group-move btn btn-sm btn-primary" aria-label="<?php echo Text::_('JGLOBAL_FIELD_MOVE'); ?>"><span class="icon-arrows-alt icon-white" aria-hidden="true"></span> </button><?php
+ endif; ?>
+ </div>
+ </div>
+ <?php endif; ?>
+ <div class="subform-grid-row">
+ <?php foreach ($form->getGroup('') as $field) : ?>
+ <?php echo $field->renderField(); ?>
+ <?php endforeach; ?>
+ </div>
+</div>
diff --git a/layouts/joomla/form/field/subform/repeatable-table.php b/layouts/joomla/form/field/subform/repeatable-table.php
index 8490ea3f1ec8..6596a10a876c 100644
--- a/layouts/joomla/form/field/subform/repeatable-table.php
+++ b/layouts/joomla/form/field/subform/repeatable-table.php
@@ -82,12 +82,12 @@
?>
<div class="subform-repeatable-wrapper subform-table-layout subform-table-sublayout-<?php echo $sublayout; ?>">
- <joomla-field-subform class="subform-repeatable<?php echo $class; ?>" name="<?php echo $name; ?>"
+ <joomla-field-subform class="subform-repeatable<?php echo $class; ?> subform-repeatable-table" name="<?php echo $name; ?>"
button-add=".group-add" button-remove=".group-remove" button-move="<?php echo empty($buttons['move']) ? '' : '.group-move' ?>"
repeatable-element=".subform-repeatable-group"
rows-container="tbody.subform-repeatable-container" minimum="<?php echo $min; ?>" maximum="<?php echo $max; ?>">
<div class="table-responsive">
- <table class="table" id="subfieldList_<?php echo $fieldId; ?>">
+ <table class="table table-bordered" id="subfieldList_<?php echo $fieldId; ?>">
<caption class="visually-hidden">
<?php echo Text::_('JGLOBAL_REPEATABLE_FIELDS_TABLE_CAPTION'); ?>
</caption>
diff --git a/layouts/joomla/form/field/subform/repeatable/section-byfieldsets.php b/layouts/joomla/form/field/subform/repeatable/section-byfieldsets.php
index 4713233ba9b6..ab462169eba0 100644
--- a/layouts/joomla/form/field/subform/repeatable/section-byfieldsets.php
+++ b/layouts/joomla/form/field/subform/repeatable/section-byfieldsets.php
@@ -45,9 +45,7 @@
<?php endif; ?>
<div class="row">
<?php foreach ($form->getFieldsets() as $fieldset) : ?>
- <fieldset class="<?php if (!empty($fieldset->class)) {
- echo $fieldset->class;
- } ?>">
+ <fieldset class="<?php echo !empty($fieldset->class) ? $this->escape($fieldset->class) : ''; ?>"
<?php if (!empty($fieldset->label)) : ?>
<legend><?php echo Text::_($fieldset->label); ?></legend>
<?php endif; ?>
diff --git a/plugins/fields/list/params/list.xml b/plugins/fields/list/params/list.xml
index 4e21dcdef3aa..ae1f6b45c897 100644
--- a/plugins/fields/list/params/list.xml
+++ b/plugins/fields/list/params/list.xml
@@ -26,11 +26,11 @@
name="options"
type="subform"
label="PLG_FIELDS_LIST_PARAMS_OPTIONS_LABEL"
- layout="joomla.form.field.subform.repeatable-table"
+ layout="joomla.form.field.subform.repeatable-grid"
icon="list"
multiple="true"
>
- <form hidden="true" name="list_templates_modal" repeat="true">
+ <form>
<field
name="name"
type="text"
diff --git a/plugins/fields/subform/params/subform.xml b/plugins/fields/subform/params/subform.xml
index de8264800355..6b744c633fc3 100644
--- a/plugins/fields/subform/params/subform.xml
+++ b/plugins/fields/subform/params/subform.xml
@@ -31,7 +31,7 @@
type="subform"
label="PLG_FIELDS_SUBFORM_PARAMS_OPTIONS_LABEL"
icon="list"
- layout="joomla.form.field.subform.repeatable-table"
+ layout="joomla.form.field.subform.repeatable-grid"
min="1"
multiple="true"
>
@@ -73,8 +73,9 @@
showon="repeat:1"
>
<option value="">JDEFAULT</option>
- <option value="joomla.form.field.subform.repeatable-table">PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_TABLE_LABEL</option>
<option value="joomla.form.field.subform.repeatable">PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_FORM_LABEL</option>
+ <option value="joomla.form.field.subform.repeatable-grid">PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_GRID_LABEL</option>
+ <option value="joomla.form.field.subform.repeatable-table">PLG_FIELDS_SUBFORM_PARAMS_EDIT_LAYOUT_OPTION_REPEATABLE_TABLE_LABEL</option>
</field>
</fieldset>
</fieldset>
New language relevant PR in upstream repo: joomla/joomla-cms#42347 Here are the upstream changes:
Click to expand the diff!