Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/controllers/FieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ public function actionSaveField(): ?Response
$fieldUid = null;
}

$settings = $this->request->getBodyParam('types.' . $type);

$field = $fieldsService->createField([
'type' => $type,
'id' => $fieldId,
Expand Down
84 changes: 81 additions & 3 deletions src/fields/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use craft\gql\GqlEntityRegistry;
use craft\gql\types\generators\TableRowType;
use craft\gql\types\TableRow;
use craft\helpers\ArrayHelper;
use craft\helpers\Cp;
use craft\helpers\DateTimeHelper;
use craft\helpers\Db;
Expand Down Expand Up @@ -338,7 +339,8 @@ public function getSettingsHtml(): ?string
Json::encode($this->defaults ?? []) . ', ' .
Json::encode($columnSettings) . ', ' .
Json::encode($dropdownSettingsHtml) . ', ' .
Json::encode($dropdownSettingsCols) .
Json::encode($dropdownSettingsCols) . ', ' .
Json::encode($this->staticRows) . ', ' .
');');

$columnsField = $view->renderTemplate('_components/fieldtypes/Table/columntable.twig', [
Expand All @@ -358,6 +360,7 @@ public function getSettingsHtml(): ?string
'cols' => $columns,
'rows' => $this->defaults,
'initJs' => false,
'includeRowId' => true,
]);

return $view->renderTemplate('_components/fieldtypes/Table/settings.twig', [
Expand All @@ -367,6 +370,25 @@ public function getSettingsHtml(): ?string
]);
}

/**
* @inheritdoc
*/
public function beforeSave(bool $isNew): bool
{
if (!$this->staticRows || empty($this->defaults)) {
parent::beforeSave($isNew);
}

// if we don't have rowIds - assign them
foreach ($this->defaults as $key => $value) {
if (!isset($this->defaults[$key]['rowId'])) {
$this->defaults[$key]['rowId'] = $key;
}
}

return parent::beforeSave($isNew);
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -464,11 +486,60 @@ private function _normalizeValueInternal(mixed $value, ?ElementInterface $elemen
$value = array_values($value);

if ($this->staticRows) {
// get the order of the default rows
$order = ArrayHelper::getColumn($this->defaults, 'rowId');
$missingValueRowIds = null;

if (!empty($order)) {
// if there's no rowIds, add them
if (ArrayHelper::containsRecursive($value, 'rowId') === false) {
foreach ($value as $key => &$row) {
$row['rowId'] = $order[$key];
}
}

// the rowIds present in the $value array
$usedValueRowIds = ArrayHelper::getColumn($value, 'rowId');

// if the field has a set order
$missingValueRowIds = array_values(array_diff($order, $usedValueRowIds));
$leftoverValueRowIds = array_diff($usedValueRowIds, $order);

// if the rowId is missing from the defaults - remove it from the $value array
if (!empty($leftoverValueRowIds)) {
foreach ($leftoverValueRowIds as $key => $rowId) {
unset($value[$key]);
}
}
}

$valueRows = count($value);
$totalRows = count($defaults);

// if we have too few rows
if ($valueRows < $totalRows) {
$value = array_pad($value, $totalRows, []);
} elseif ($valueRows > $totalRows) {
if ($missingValueRowIds === null) {
$value = array_pad($value, $totalRows, []);
} else {
// if we have the missing value rowIds - add them in places where settings rowId doesn't exist in the $value array
while (count($value) < $totalRows) {
$value[] = ['rowId' => reset($missingValueRowIds)];
array_shift($missingValueRowIds);
}
}
}

if (!empty($order)) {
// sort as per the field's settings
usort($value, function($a, $b) use ($order) {
$posA = array_search($a['rowId'], $order);
$posB = array_search($b['rowId'], $order);
return $posA - $posB;
});
}

// now that we've sorted the rows, if we have too many rows - splice
if ($valueRows > $totalRows) {
array_splice($value, $totalRows);
}
}
Expand Down Expand Up @@ -566,6 +637,12 @@ public function serializeValueForDb(mixed $value, ElementInterface $element): mi
$serializedRow[$colId] = parent::serializeValue($value, $element);
}
}
// if the table has static rows, store the rowId too
if ($this->staticRows) {
if (isset($row['rowId'])) {
$serializedRow['rowId'] = $row['rowId'];
}
}
$serialized[] = $serializedRow;
}

Expand Down Expand Up @@ -779,6 +856,7 @@ private function _getInputHtml(mixed $value, ?ElementInterface $element, bool $s
'allowReorder' => true,
'addRowLabel' => Craft::t('site', $this->addRowLabel),
'describedBy' => $this->describedBy,
'includeRowId' => $this->staticRows,
]);
}
}
11 changes: 11 additions & 0 deletions src/templates/_includes/forms/editableTable.twig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
{%- set minRows = minRows ?? null %}
{%- set maxRows = maxRows ?? null %}
{%- set describedBy = describedBy ?? null %}
{%- set includeRowId = includeRowId ?? false %}

{%- set totalRows = rows|length %}
{%- set staticRows = static or (staticRows ?? false) or (minRows == 1 and maxRows == 1 and totalRows == 1) %}
Expand Down Expand Up @@ -71,6 +72,9 @@
{% if allowDelete %}<col>{% endif %}
{% if allowReorder %}<col>{% endif %}
{% endif %}
{% if includeRowId %}
<col> {# for hidden row ID #}
{% endif %}
{% if cols|filter(c => (c.headingHtml ?? c.heading ?? c.info ?? '') is not same as(''))|length %}
<thead>
<tr>
Expand All @@ -92,12 +96,16 @@
{% if (allowDelete or allowReorder) %}
<th colspan="{{ not allowDelete or not allowReorder ? 1 : 2 }}" scope="colgroup"><span class="visually-hidden">{{ 'Row actions'|t('app') }}</span></th>
{% endif %}
{% if includeRowId %}
<th class="hidden">Row ID</th>
{% endif %}
</tr>
</thead>
{% endif %}
<tbody>
{% for rowId, row in rows %}
{% set rowNumber = loop.index %}
{% set rowIndex = loop.index0 %}
<tr data-id="{{ rowId }}">
{% for colId, col in cols %}
{% set cell = row[colId] is defined ? row[colId] : (defaultValues[colId] ?? null) %}
Expand Down Expand Up @@ -236,6 +244,9 @@
}) }}
</td>
{%- endif -%}
{% if includeRowId %}
<td class="hidden"><input type="hidden" name="{{ name~'['~rowId~'][rowId]' }}" value="{{ row['rowId'] is defined ? row['rowId'] : uuid() }}" /></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/cp.js.map

Large diffs are not rendered by default.

27 changes: 24 additions & 3 deletions src/web/assets/cp/src/js/EditableTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,9 @@ Craft.EditableTable = Garnish.Base.extend(
baseName,
values,
this.settings.allowReorder,
this.settings.allowDelete
this.settings.allowDelete,
this.settings.staticRows,
this.settings.includeRowId
);
},

Expand Down Expand Up @@ -436,6 +438,9 @@ Craft.EditableTable = Garnish.Base.extend(
lazyInitRows: true,
onAddRow: $.noop,
onDeleteRow: $.noop,
staticRows: false,
includeRowId: false,
maxRowId: null,
},

createRow: function (
Expand All @@ -444,7 +449,9 @@ Craft.EditableTable = Garnish.Base.extend(
baseName,
values,
allowReorder,
allowDelete
allowDelete,
staticRows = false,
includeRowId = false
) {
var $tr = $('<tr/>', {
'data-id': rowId,
Expand Down Expand Up @@ -612,6 +619,20 @@ Craft.EditableTable = Garnish.Base.extend(
.appendTo($tr);
}

if (staticRows && includeRowId) {
$('<td/>', {
class: 'hidden',
})
.append(
$('<input/>', {
type: 'hidden',
name: baseName + '[' + rowId + '][rowId]',
value: Craft.uuid(),
})
)
.appendTo($tr);
}

return $tr;
},
}
Expand Down Expand Up @@ -774,7 +795,7 @@ Craft.EditableTable.Row = Garnish.Base.extend(
}
}

var $deleteBtn = this.$tr.children().last().find('.delete');
var $deleteBtn = this.$tr.children().find('.delete').last();
this.addListener($deleteBtn, 'click', 'deleteRow');

var $inputs = this.$tr.find('input,textarea,select,.lightswitch');
Expand Down
Loading
Loading