Skip to content

Commit a5a9fcc

Browse files
authored
Merge pull request #201 from alex-nesterov/clone-button
added optional clone button
2 parents 983178c + cd61b1f commit a5a9fcc

File tree

7 files changed

+150
-6
lines changed

7 files changed

+150
-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: 18 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($(this)));
135+
});
136+
132137
var i = 0,
133138
event = $.Event(events.afterInit);
134139

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

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

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: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ private function renderRowContent($index = null, $item = null)
140140
$content[] = $this->renderActionColumn($index);
141141
}
142142

143+
if ($this->cloneButton) {
144+
$content[] = $this->renderCloneColumn();
145+
}
146+
143147
$content = Html::tag('tr', implode("\n", $content), $this->prepareRowOptions($index, $item));
144148

145149
if ($index !== null) {
@@ -234,6 +238,19 @@ private function renderActionColumn($index = null)
234238
]);
235239
}
236240

241+
/**
242+
* Renders the clone column.
243+
*
244+
* @return string
245+
* @throws \Exception
246+
*/
247+
private function renderCloneColumn()
248+
{
249+
return Html::tag('td', $this->renderCloneButton(), [
250+
'class' => 'list-cell__button',
251+
]);
252+
}
253+
237254
private function getActionButton($index)
238255
{
239256
if ($index === null || $this->min === 0) {
@@ -276,6 +293,22 @@ private function renderRemoveButton()
276293
return Html::tag('div', $this->removeButtonOptions['label'], $options);
277294
}
278295

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

src/renderers/TableRenderer.php

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ 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+
if ($this->cloneButton) {
67+
$cells[] = $this->renderButtonHeaderCell();
68+
}
6769
}
6870

6971
return Html::tag('thead', Html::tag('tr', implode("\n", $cells)));
@@ -127,6 +129,18 @@ private function renderHeaderCell($column)
127129
return Html::tag('th', $column->title, $options);
128130
}
129131

132+
/**
133+
* Renders the button header cell.
134+
* @param string
135+
* @return string
136+
*/
137+
private function renderButtonHeaderCell($button = '')
138+
{
139+
return Html::tag('th', $button, [
140+
'class' => 'list-cell__button'
141+
]);
142+
}
143+
130144
/**
131145
* Renders the body.
132146
*
@@ -186,9 +200,12 @@ private function renderRowContent($index = null, $item = null)
186200
$cells[] = $this->renderCellContent($column, $index);
187201
}
188202
}
189-
203+
if ($this->cloneButton) {
204+
$cells[] = $this->renderCloneColumn();
205+
}
206+
190207
if (!$isLastRow) {
191-
$cells[] = $this->renderActionColumn($index, false);
208+
$cells[] = $this->renderActionColumn($index);
192209
}
193210

194211
if ($hiddenInputs) {
@@ -286,6 +303,18 @@ private function renderActionColumn($index = null, $isFirstColumn = false)
286303
]);
287304
}
288305

306+
/**
307+
* Renders the clone column.
308+
*
309+
* @return string
310+
*/
311+
private function renderCloneColumn()
312+
{
313+
return Html::tag('td', $this->renderCloneButton(), [
314+
'class' => 'list-cell__button',
315+
]);
316+
}
317+
289318
private function getActionButton($index, $isFirstColumn)
290319
{
291320
if ($index === null || $this->min === 0) {
@@ -342,6 +371,22 @@ private function renderRemoveButton()
342371
return Html::tag('div', $this->removeButtonOptions['label'], $options);
343372
}
344373

374+
/**
375+
* Renders clone button.
376+
*
377+
* @return string
378+
* @throws \Exception
379+
*/
380+
private function renderCloneButton()
381+
{
382+
$options = [
383+
'class' => 'btn multiple-input-list__btn js-input-clone',
384+
];
385+
Html::addCssClass($options, $this->cloneButtonOptions['class']);
386+
387+
return Html::tag('div', $this->cloneButtonOptions['label'], $options);
388+
}
389+
345390
/**
346391
* Returns template for using in js.
347392
*

0 commit comments

Comments
 (0)