From 9e4bca001d0bac5a0010ae6fa41a4e94325f1e5d Mon Sep 17 00:00:00 2001 From: Evgeny Tupikov Date: Sat, 20 Apr 2024 15:08:42 +0400 Subject: [PATCH 1/2] fix rendering action buttons in case the dataset contains non-numeric indices --- src/renderers/BaseRenderer.php | 32 ++++++++++++++++ src/renderers/DivRenderer.php | 51 ++++++++++--------------- src/renderers/ListRenderer.php | 43 +++++++-------------- src/renderers/TableRenderer.php | 67 +++++++++++++++------------------ 4 files changed, 95 insertions(+), 98 deletions(-) diff --git a/src/renderers/BaseRenderer.php b/src/renderers/BaseRenderer.php index b78d0c0..5a701a1 100644 --- a/src/renderers/BaseRenderer.php +++ b/src/renderers/BaseRenderer.php @@ -514,6 +514,11 @@ protected function isAddButtonPositionRowBegin() return in_array(self::POS_ROW_BEGIN, $this->addButtonPosition); } + protected function isFixedNumberOfRows() + { + return $this->max === $this->min; + } + private function prepareIndexPlaceholder() { $this->indexPlaceholder = 'multiple_index_' . $this->id; @@ -579,4 +584,31 @@ public function isBootstrapTheme() return $this->theme === self::THEME_BS; } + protected function renderRows() + { + $rows = []; + + $rowIndex = 0; + if ($this->data) { + foreach ($this->data as $index => $item) { + if ($rowIndex <= $this->max) { + $rows[] = $this->renderRowContent($index, $item, $rowIndex); + } else { + break; + } + $rowIndex++; + } + for (; $rowIndex < $this->min; $rowIndex++) { + $rows[] = $this->renderRowContent($rowIndex, null, $rowIndex); + } + } elseif ($this->min > 0) { + for (; $rowIndex < $this->min; $rowIndex++) { + $rows[] = $this->renderRowContent($rowIndex, null, $rowIndex); + } + } + + return $rows; + } + + abstract protected function renderRowContent($index = null, $item = null, $rowIndex = null); } diff --git a/src/renderers/DivRenderer.php b/src/renderers/DivRenderer.php index c717fa0..80e3056 100644 --- a/src/renderers/DivRenderer.php +++ b/src/renderers/DivRenderer.php @@ -98,27 +98,7 @@ public function renderFooter() */ protected function renderBody() { - $rows = []; - - if ($this->data) { - $j = 0; - foreach ($this->data as $index => $item) { - if ($j++ <= $this->max) { - $rows[] = $this->renderRowContent($index, $item); - } else { - break; - } - } - for ($i = $j; $i < $this->min; $i++) { - $rows[] = $this->renderRowContent($i); - } - } elseif ($this->min > 0) { - for ($i = 0; $i < $this->min; $i++) { - $rows[] = $this->renderRowContent($i); - } - } - - return implode("\n", $rows); + return implode("\n", $this->renderRows()); } /** @@ -128,14 +108,16 @@ protected function renderBody() * @param ActiveRecordInterface|array $item * @return mixed */ - private function renderRowContent($index = null, $item = null) + protected function renderRowContent($index = null, $item = null, $rowIndex = null) { $elements = []; + $columnIndex = 0; foreach ($this->columns as $column) { /* @var $column BaseColumn */ $column->setModel($item); - $elements[] = $this->renderCellContent($column, $index, $columnIndex++); + $elements[] = $this->renderCellContent($column, $index, $columnIndex, $rowIndex); + $columnIndex++; } $content = Html::tag('div', implode("\n", $elements), $this->prepareRowOptions($index, $item)); @@ -174,10 +156,11 @@ protected function prepareRowOptions($index, $item) * @param BaseColumn $column * @param int|null $index * @param int|null $columnIndex + * @param int|null $rowIndex * @return string * @throws \Exception */ - public function renderCellContent($column, $index, $columnIndex = null) + public function renderCellContent($column, $index = null, $columnIndex = null, $rowIndex = null) { $id = $column->getElementId($index); $name = $column->getElementName($index); @@ -263,9 +246,10 @@ public function renderCellContent($column, $index, $columnIndex = null) // first line if ($columnIndex == 0) { - if ($this->max !== $this->min) { - $content .= $this->renderActionColumn($index); + if (!$this->isFixedNumberOfRows()) { + $content .= $this->renderActionColumn($index, $column->getModel(), $rowIndex); } + if ($this->cloneButton) { $content .= $this->renderCloneColumn(); } @@ -287,14 +271,15 @@ public function renderCellContent($column, $index, $columnIndex = null) * @param null|ActiveRecordInterface|array $item * @return string */ - private function renderActionColumn($index = null, $item = null) + private function renderActionColumn($index = null, $item = null, $rowIndex = null) { - $content = $this->getActionButton($index) . $this->getExtraButtons($index, $item); + $content = $this->getActionButton($index, $rowIndex) . $this->getExtraButtons($index, $item); $options = ['class' => 'list-cell__button']; $layoutConfig = array_merge([ 'buttonActionClass' => $this->isBootstrapTheme() ? 'col-sm-offset-0 col-sm-2' : '', ], $this->layoutConfig); + Html::addCssClass($options, $layoutConfig['buttonActionClass']); return Html::tag('div', $content, $options); @@ -317,18 +302,20 @@ private function renderCloneColumn() return Html::tag('div', $this->renderCloneButton(), $options); } - private function getActionButton($index) + private function getActionButton($index, $rowIndex) { if ($index === null || $this->min === 0) { return $this->renderRemoveButton(); } - $index++; - if ($index < $this->min) { + // rowIndex is zero-based, so we have to increment it to properly cpmpare it with min number of rows + $rowIndex++; + + if ($rowIndex < $this->min) { return ''; } - if ($index === $this->min) { + if ($rowIndex === $this->min) { return $this->isAddButtonPositionRow() ? $this->renderAddButton() : ''; } diff --git a/src/renderers/ListRenderer.php b/src/renderers/ListRenderer.php index a34ad63..7661a41 100644 --- a/src/renderers/ListRenderer.php +++ b/src/renderers/ListRenderer.php @@ -102,27 +102,7 @@ public function renderFooter() */ protected function renderBody() { - $rows = []; - - if ($this->data) { - $j = 0; - foreach ($this->data as $index => $item) { - if ($j++ <= $this->max) { - $rows[] = $this->renderRowContent($index, $item); - } else { - break; - } - } - for ($i = $j; $i < $this->min; $i++) { - $rows[] = $this->renderRowContent($i); - } - } elseif ($this->min > 0) { - for ($i = 0; $i < $this->min; $i++) { - $rows[] = $this->renderRowContent($i); - } - } - - return Html::tag('tbody', implode("\n", $rows)); + return Html::tag('tbody', implode("\n", $this->renderRows())); } /** @@ -133,7 +113,7 @@ protected function renderBody() * @return mixed * @throws InvalidConfigException */ - private function renderRowContent($index = null, $item = null) + protected function renderRowContent($index = null, $item = null, $rowIndex = null) { $elements = []; @@ -146,8 +126,8 @@ private function renderRowContent($index = null, $item = null) $content = []; $content[] = Html::tag('td', implode("\n", $elements)); - if ($this->max !== $this->min) { - $content[] = $this->renderActionColumn($index); + if (!$this->isFixedNumberOfRows()) { + $content[] = $this->renderActionColumn($index, $item, $rowIndex); } if ($this->cloneButton) { @@ -290,12 +270,13 @@ public function renderCellContent($column, $index, $columnIndex = null) * * @param null|int $index * @param null|ActiveRecordInterface|array $item + * @param null|int $rowIndex * @return string * @throws \Exception */ - private function renderActionColumn($index = null, $item = null) + private function renderActionColumn($index = null, $item = null, $rowIndex = null) { - $content = $this->getActionButton($index) . $this->getExtraButtons($index, $item); + $content = $this->getActionButton($index, $rowIndex) . $this->getExtraButtons($index, $item); return Html::tag('td', $content, [ 'class' => 'list-cell__button', @@ -315,18 +296,20 @@ private function renderCloneColumn() ]); } - private function getActionButton($index) + private function getActionButton($index, $rowIndex) { if ($index === null || $this->min === 0) { return $this->renderRemoveButton(); } - $index++; - if ($index < $this->min) { + // rowIndex is zero-based, so we have to increment it to properly cpmpare it with min number of rows + $rowIndex++; + + if ($rowIndex < $this->min) { return ''; } - if ($index === $this->min) { + if ($rowIndex === $this->min) { return $this->isAddButtonPositionRow() ? $this->renderAddButton() : ''; } diff --git a/src/renderers/TableRenderer.php b/src/renderers/TableRenderer.php index 3394b0b..55d5f3b 100644 --- a/src/renderers/TableRenderer.php +++ b/src/renderers/TableRenderer.php @@ -167,27 +167,7 @@ private function renderButtonHeaderCell($button = '') */ protected function renderBody() { - $rows = []; - - if ($this->data) { - $j = 0; - foreach ($this->data as $index => $item) { - if ($j++ <= $this->max) { - $rows[] = $this->renderRowContent($index, $item); - } else { - break; - } - } - for ($i = $j; $i < $this->min; $i++) { - $rows[] = $this->renderRowContent($i); - } - } elseif ($this->min > 0) { - for ($i = 0; $i < $this->min; $i++) { - $rows[] = $this->renderRowContent($i); - } - } - - return Html::tag('tbody', implode("\n", $rows)); + return Html::tag('tbody', implode("\n", $this->renderRows())); } /** @@ -198,13 +178,13 @@ protected function renderBody() * @return mixed * @throws InvalidConfigException */ - private function renderRowContent($index = null, $item = null) + protected function renderRowContent($index = null, $item = null, $rowIndex = null) { $cells = []; $hiddenInputs = []; - $isLastRow = $this->max === $this->min; - if (!$isLastRow && $this->isAddButtonPositionRowBegin()) { - $cells[] = $this->renderActionColumn($index, $item, true); + + if (!$this->isFixedNumberOfRows() && $this->isAddButtonPositionRowBegin()) { + $cells[] = $this->renderActionColumn($index, $item, $rowIndex, true); } $columnIndex = 0; @@ -217,12 +197,13 @@ private function renderRowContent($index = null, $item = null) $cells[] = $this->renderCellContent($column, $index, $columnIndex++); } } + if ($this->cloneButton) { $cells[] = $this->renderCloneColumn(); } - if (!$isLastRow) { - $cells[] = $this->renderActionColumn($index, $item); + if (!$this->isFixedNumberOfRows()) { + $cells[] = $this->renderActionColumn($index, $item, $rowIndex); } if ($hiddenInputs) { @@ -268,6 +249,8 @@ protected function prepareRowOptions($index, $item) * @param int|null $index * @param int|null $columnIndex * @return string + * + * @todo rethink visibility level (make it private) */ public function renderCellContent($column, $index, $columnIndex = null) { @@ -284,7 +267,6 @@ public function renderCellContent($column, $index, $columnIndex = null) $options = ArrayHelper::merge($options, ['class' => $this->iconMap['drag-handle']]); } - $input = $column->renderInput($name, $options, [ 'id' => $id, 'name' => $name, @@ -336,14 +318,19 @@ public function renderCellContent($column, $index, $columnIndex = null) /** * Renders the action column. * - * @param null|int $index + * @param null|int|string $index * @param null|ActiveRecordInterface|array $item - * @param bool $isFirstColumn + * @param int $rowIndex * @return string */ - private function renderActionColumn($index = null, $item = null, $isFirstColumn = false) + private function renderActionColumn( + $index = null, + $item = null, + $rowIndex = null, + $isFirstColumn = false + ) { - $content = $this->getActionButton($index, $isFirstColumn) . $this->getExtraButtons($index, $item); + $content = $this->getActionButton($index, $rowIndex, $isFirstColumn) . $this->getExtraButtons($index, $item); return Html::tag('td', $content, [ 'class' => 'list-cell__button', @@ -362,7 +349,12 @@ private function renderCloneColumn() ]); } - private function getActionButton($index, $isFirstColumn) + /** + * @param int|string|null $index + * @param int $rowIndex + * @return string + */ + private function getActionButton($index = null, $rowIndex = null, $isFirstColumn = false) { if ($index === null || $this->min === 0) { if ($isFirstColumn) { @@ -372,16 +364,19 @@ private function getActionButton($index, $isFirstColumn) return $this->isAddButtonPositionRowBegin() ? '' : $this->renderRemoveButton(); } - $index++; - if ($index < $this->min) { + // rowIndex is zero-based, so we have to increment it to properly cpmpare it with min number of rows + $rowIndex++; + + if ($rowIndex < $this->min) { return ''; } - if ($index === $this->min) { + if ($rowIndex === $this->min) { if ($isFirstColumn) { return $this->isAddButtonPositionRowBegin() ? $this->renderAddButton() : ''; } + return $this->isAddButtonPositionRow() ? $this->renderAddButton() : ''; } From fa5ac6a0d78c89369468aeb55eadb7347b9e67c3 Mon Sep 17 00:00:00 2001 From: Evgeny Tupikov Date: Sat, 20 Apr 2024 15:11:05 +0400 Subject: [PATCH 2/2] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb31e0b..9124a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Yii2 multiple input change log 2.30.0 (in development) ======================= +2.30.0 +======================= +- #369 fix rendering action buttons in case the dataset contains non-numeric indices (unclead) + 2.29.0 ======================= - fix addind active form fields doesn't work properly in case of 10 rows and more (unclead)