Skip to content

Commit 576e43e

Browse files
author
Alexander Nesterov
committed
added clone button
1 parent 983178c commit 576e43e

File tree

7 files changed

+143
-6
lines changed

7 files changed

+143
-6
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ use unclead\multipleinput\MultipleInput;
4545
'min' => 2, // should be at least 2 rows
4646
'allowEmptyList' => false,
4747
'enableGuessTitle' => true,
48-
'addButtonPosition' => MultipleInput::POS_HEADER // show add button in the header
48+
'addButtonPosition' => MultipleInput::POS_HEADER, // show add button in the header
49+
'cloneButton' => true, // show clone button
4950
])
5051
->label(false);
5152
?>

src/MultipleInput.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ class MultipleInput extends InputWidget
6464
*/
6565
public $addButtonOptions;
6666

67+
/**
68+
* @var array the HTML options for the `clone` button
69+
*/
70+
public $cloneButtonOptions;
71+
6772
/**
6873
* @var bool whether to allow the empty list
6974
*/
@@ -136,6 +141,11 @@ class MultipleInput extends InputWidget
136141
*/
137142
public $enableError = false;
138143

144+
/**
145+
* @var bool whether to render clone button. Default to `false`.
146+
*/
147+
public $cloneButton = false;
148+
139149
/**
140150
* Initialization.
141151
*
@@ -247,6 +257,7 @@ private function createRenderer()
247257
'form' => $this->form,
248258
'sortable' => $this->sortable,
249259
'enableError' => $this->enableError,
260+
'cloneButton' => $this->cloneButton,
250261
];
251262

252263
if ($this->removeButtonOptions !== null) {
@@ -257,6 +268,10 @@ private function createRenderer()
257268
$config['addButtonOptions'] = $this->addButtonOptions;
258269
}
259270

271+
if ($this->cloneButtonOptions !== null) {
272+
$config['cloneButtonOptions'] = $this->cloneButtonOptions;
273+
}
274+
260275
$config['class'] = $this->rendererClass ?: TableRenderer::className();
261276

262277
return Yii::createObject($config);

src/TabularInput.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ class TabularInput extends Widget
6060
*/
6161
public $addButtonOptions;
6262

63+
/**
64+
* @var array the HTML options for the `clone` button
65+
*/
66+
public $cloneButtonOptions;
67+
6368
/**
6469
* @var bool whether to allow the empty list
6570
*/
@@ -122,6 +127,11 @@ class TabularInput extends Widget
122127
*/
123128
public $enableError = false;
124129

130+
/**
131+
* @var bool whether to render clone button. Default to `false`.
132+
*/
133+
public $cloneButton = false;
134+
125135
/**
126136
* @var string a class of model which is used to render the widget.
127137
* You have to specify this property in case you set `min` property to 0 (when you want to allow an empty list)
@@ -206,6 +216,10 @@ private function createRenderer()
206216
$config['addButtonOptions'] = $this->addButtonOptions;
207217
}
208218

219+
if ($this->cloneButtonOptions !== null) {
220+
$config['cloneButtonOptions'] = $this->cloneButtonOptions;
221+
}
222+
209223
if (!$this->rendererClass) {
210224
$this->rendererClass = TableRenderer::className();
211225
}

src/assets/src/js/jquery.multipleInput.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@
129129
addInput($(this));
130130
});
131131

132+
$wrapper.on('click.multipleInput', '.js-input-clone', function (e) {
133+
e.stopPropagation();
134+
addInput($(this), getRowValues(e));
135+
});
136+
132137
var i = 0,
133138
event = $.Event(events.afterInit);
134139

@@ -430,6 +435,20 @@
430435
}).length;
431436
};
432437

438+
var getRowValues = function (event) {
439+
var tr = $(event.currentTarget).closest('tr');
440+
var values = {};
441+
tr.find('td').each(function (index, value) {
442+
$(value).find('input, select, textarea').each(function (k, v) {
443+
var ele = $(v),
444+
id = getInputId(ele),
445+
obj = $('#' + id);
446+
values[id] = obj.val();
447+
});
448+
});
449+
return values;
450+
};
451+
433452
String.prototype.replaceAll = function (search, replace) {
434453
return this.split(search).join(replace);
435454
};

src/renderers/BaseRenderer.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ abstract class BaseRenderer extends BaseObject implements RendererInterface
7474
*/
7575
public $addButtonOptions = [];
7676

77+
/**
78+
* @var array the HTML options for the `clone` button
79+
*/
80+
public $cloneButtonOptions = [];
81+
7782
/**
7883
* @var bool whether to allow the empty list
7984
*/
@@ -132,6 +137,11 @@ abstract class BaseRenderer extends BaseObject implements RendererInterface
132137
*/
133138
public $enableError = false;
134139

140+
/**
141+
* @var bool whether to render clone button. Default to `false`.
142+
*/
143+
public $cloneButton = false;
144+
135145
/**
136146
* @inheritdoc
137147
*/
@@ -224,6 +234,14 @@ private function prepareButtons()
224234
if (!array_key_exists('label', $this->addButtonOptions)) {
225235
$this->addButtonOptions['label'] = Html::tag('i', null, ['class' => 'glyphicon glyphicon-plus']);
226236
}
237+
238+
if (!array_key_exists('class', $this->cloneButtonOptions)) {
239+
$this->cloneButtonOptions['class'] = 'btn btn-info';
240+
}
241+
242+
if (!array_key_exists('label', $this->cloneButtonOptions)) {
243+
$this->cloneButtonOptions['label'] = Html::tag('i', null, ['class' => 'glyphicon glyphicon-duplicate']);
244+
}
227245
}
228246

229247

src/renderers/ListRenderer.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ private function renderRowContent($index = null, $item = null)
140140
$content[] = $this->renderActionColumn($index);
141141
}
142142

143+
$this->cloneButton && $content[] = $this->renderCloneColumn();
143144
$content = Html::tag('tr', implode("\n", $content), $this->prepareRowOptions($index, $item));
144145

145146
if ($index !== null) {
@@ -234,6 +235,19 @@ private function renderActionColumn($index = null)
234235
]);
235236
}
236237

238+
/**
239+
* Renders the clone column.
240+
*
241+
* @return string
242+
* @throws \Exception
243+
*/
244+
private function renderCloneColumn()
245+
{
246+
return Html::tag('td', $this->renderCloneButton(), [
247+
'class' => 'list-cell__button',
248+
]);
249+
}
250+
237251
private function getActionButton($index)
238252
{
239253
if ($index === null || $this->min === 0) {
@@ -276,6 +290,22 @@ private function renderRemoveButton()
276290
return Html::tag('div', $this->removeButtonOptions['label'], $options);
277291
}
278292

293+
/**
294+
* Renders clone button.
295+
*
296+
* @return string
297+
* @throws \Exception
298+
*/
299+
private function renderCloneButton()
300+
{
301+
$options = [
302+
'class' => 'btn multiple-input-list__btn js-input-clone',
303+
];
304+
Html::addCssClass($options, $this->cloneButtonOptions['class']);
305+
306+
return Html::tag('div', $this->cloneButtonOptions['label'], $options);
307+
}
308+
279309
/**
280310
* Returns template for using in js.
281311
*

src/renderers/TableRenderer.php

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ public function renderHeader()
6161
if ($this->max === null || ($this->max >= 1 && $this->max !== $this->min)) {
6262
$button = $this->isAddButtonPositionHeader() ? $this->renderAddButton() : '';
6363

64-
$cells[] = Html::tag('th', $button, [
65-
'class' => 'list-cell__button'
66-
]);
64+
$cells[] = $this->renderButtonHeaderCell($button);
65+
66+
$this->cloneButton && $cells[] = $this->renderButtonHeaderCell();
6767
}
6868

6969
return Html::tag('thead', Html::tag('tr', implode("\n", $cells)));
@@ -127,6 +127,18 @@ private function renderHeaderCell($column)
127127
return Html::tag('th', $column->title, $options);
128128
}
129129

130+
/**
131+
* Renders the button header cell.
132+
* @param string
133+
* @return string
134+
*/
135+
private function renderButtonHeaderCell($button = '')
136+
{
137+
return Html::tag('th', $button, [
138+
'class' => 'list-cell__button'
139+
]);
140+
}
141+
130142
/**
131143
* Renders the body.
132144
*
@@ -186,9 +198,9 @@ private function renderRowContent($index = null, $item = null)
186198
$cells[] = $this->renderCellContent($column, $index);
187199
}
188200
}
189-
201+
$this->cloneButton && $cells[] = $this->renderCloneColumn();
190202
if (!$isLastRow) {
191-
$cells[] = $this->renderActionColumn($index, false);
203+
$cells[] = $this->renderActionColumn($index);
192204
}
193205

194206
if ($hiddenInputs) {
@@ -286,6 +298,18 @@ private function renderActionColumn($index = null, $isFirstColumn = false)
286298
]);
287299
}
288300

301+
/**
302+
* Renders the clone column.
303+
*
304+
* @return string
305+
*/
306+
private function renderCloneColumn()
307+
{
308+
return Html::tag('td', $this->renderCloneButton(), [
309+
'class' => 'list-cell__button',
310+
]);
311+
}
312+
289313
private function getActionButton($index, $isFirstColumn)
290314
{
291315
if ($index === null || $this->min === 0) {
@@ -342,6 +366,22 @@ private function renderRemoveButton()
342366
return Html::tag('div', $this->removeButtonOptions['label'], $options);
343367
}
344368

369+
/**
370+
* Renders clone button.
371+
*
372+
* @return string
373+
* @throws \Exception
374+
*/
375+
private function renderCloneButton()
376+
{
377+
$options = [
378+
'class' => 'btn multiple-input-list__btn js-input-clone',
379+
];
380+
Html::addCssClass($options, $this->cloneButtonOptions['class']);
381+
382+
return Html::tag('div', $this->cloneButtonOptions['label'], $options);
383+
}
384+
345385
/**
346386
* Returns template for using in js.
347387
*

0 commit comments

Comments
 (0)