Skip to content

Commit

Permalink
Merge pull request #2621 from craftcms/feature/min-max-row
Browse files Browse the repository at this point in the history
Feature/min max row
  • Loading branch information
brandonkelly authored Mar 28, 2018
2 parents 6ba51fd + 2ad05df commit 962e618
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 20 deletions.
38 changes: 37 additions & 1 deletion src/fields/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ public static function displayName(): string
// Properties
// =========================================================================

/**
* @var string|null Custom add row button label
*/
public $addRowLabel;

/**
* @var int|null Maximum number of Rows allowed
*/
public $maxRows;

/**
* @var int|null Minimum number of Rows allowed
*/
public $minRows;

/**
* @var array|null The columns that should be shown in the table
*/
Expand All @@ -66,6 +81,10 @@ public function init()
{
parent::init();

if ($this->addRowLabel === null) {
$this->addRowLabel = Craft::t('app', 'Add a row');
}

if ($this->defaults === '') {
$this->defaults = [];
}
Expand All @@ -82,6 +101,18 @@ public function init()
}
}

/**
* @inheritdoc
*/
public function rules()
{
$rules = parent::rules();
$rules[] = [['minRows'], 'compare', 'compareAttribute' => 'maxRows', 'operator' => '<=', 'type' => 'number'];
$rules[] = [['maxRows'], 'compare', 'compareAttribute' => 'minRows', 'operator' => '>=', 'type' => 'number'];
$rules[] = [['minRows', 'maxRows'], 'integer', 'min' => 0];
return $rules;
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -410,7 +441,12 @@ private function _getInputHtml($value, ElementInterface $element = null, bool $s
'name' => $this->handle,
'cols' => $this->columns,
'rows' => $value,
'static' => $static
'static' => $static,
'addRowLabel' => Craft::t('site', $this->addRowLabel),
'defaultValues' => [
'minRows' => $this->minRows ?: null,
'maxRows' => $this->maxRows ?: null,
],
]);
}
}
32 changes: 30 additions & 2 deletions src/templates/_components/fieldtypes/Table/settings.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
{% import '_includes/forms' as forms %}

<input type="hidden" name="defaults" value="">

{{ columnsField|raw }}
{{ defaultsField|raw }}

{{ forms.textField({
label: "Min Rows"|t('app'),
instructions: "The minimum number of rows the field is allowed to have."|t('app'),
id: 'minRows',
name: 'minRows',
value: field.minRows,
size: 3,
errors: field.getErrors('minRows')
}) }}

{{ forms.textField({
label: "Max Rows"|t('app'),
instructions: "The maximum number of rows the field is allowed to have."|t('app'),
id: 'maxRows',
name: 'maxRows',
value: field.maxRows,
size: 3,
errors: field.getErrors('maxRows')
}) }}

{{ forms.textField({
label: "Add Row Label"|t('app'),
instructions: "Insert the button label for adding a new row to the table."|t('app'),
id: 'addRowLabel',
name: 'addRowLabel',
value: field.addRowLabel,
size: 20,
errors: field.getErrors('addRowLabel')
}) }}

{% if craft.app.db.isMysql %}
<hr>
<a class="fieldtoggle" data-target="advanced">{{ "Advanced"|t('app') }}</a>
Expand Down
3 changes: 1 addition & 2 deletions src/templates/_includes/forms/editableTable.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
{%- set rows = rows ?? [] %}
{%- set initJs = not static and (initJs ?? true) -%}


<table id="{{ id }}" class="shadow-box editable"
{%- if block('attr') is defined %} {{ block('attr') }}{% endif %}>
{%- if block('attr') is defined %} {{ block('attr') }}{% endif %}>
<thead>
<tr>
{% for col in cols %}
Expand Down
69 changes: 62 additions & 7 deletions src/web/assets/cp/dist/js/Craft.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! - 2018-03-27 */
/*! - 2018-03-28 */
(function($){

/** global: Craft */
Expand Down Expand Up @@ -12565,6 +12565,10 @@ Craft.EditableTable = Garnish.Base.extend(
$tbody: null,
$addRowBtn: null,

rowCount: 0,
hasMaxRows: false,
hasMinRows: false,

radioCheckboxes: null,

init: function(id, baseName, columns, settings) {
Expand All @@ -12573,9 +12577,15 @@ Craft.EditableTable = Garnish.Base.extend(
this.columns = columns;
this.setSettings(settings, Craft.EditableTable.defaults);
this.radioCheckboxes = {};
this.minRows = settings['defaultValues']['minRows'];
this.maxRows = settings['defaultValues']['maxRows'];

this.hasMinRows = this.minRows !== null;
this.hasMaxRows = this.maxRows !== null;

this.$table = $('#' + id);
this.$tbody = this.$table.children('tbody');
this.rowCount = this.$tbody.find('tr').length;

this.sorter = new Craft.DataTableSorter(this.$table, {
helperClass: 'editabletablesorthelper',
Expand All @@ -12588,6 +12598,14 @@ Craft.EditableTable = Garnish.Base.extend(
// Give everything a chance to initialize
setTimeout($.proxy(this, 'initializeIfVisible'), 500);
}

if (this.hasMinRows && this.rowCount < this.minRows) {
for (var i = 0; i < this.minRows; i++) {
this.addRow()
}
}

this.updateAddRowButton();
},

isVisible: function() {
Expand All @@ -12611,7 +12629,6 @@ Craft.EditableTable = Garnish.Base.extend(
this.$addRowBtn = this.$table.next('.add');
this.addListener(this.$addRowBtn, 'activate', 'addRow');
},

initializeIfVisible: function() {
this.removeListener(Garnish.$win, 'resize');

Expand All @@ -12621,8 +12638,47 @@ Craft.EditableTable = Garnish.Base.extend(
this.addListener(Garnish.$win, 'resize', 'initializeIfVisible');
}
},
updateAddRowButton: function() {
if ((this.hasMaxRows && this.rowCount >= this.maxRows) ||
(this.hasMinRows && this.rowCount < this.minRows)) {
this.$addRowBtn.css('opacity', '0.2');
this.$addRowBtn.css('pointer-events', 'none');
} else {
this.$addRowBtn.css('opacity', '1');
this.$addRowBtn.css('pointer-events', 'auto');
}
},
canDeleteRow: function() {
return (this.rowCount > this.minRows);
},
deleteRow: function(row) {
if (this.hasMaxRows && this.hasMinRows) {
if (!this.canDeleteRow()) {
return;
}
}

this.sorter.removeItems(row.$tr);
row.$tr.remove();

if (this.hasMinRows && this.hasMinRows) {
this.rowCount--;
}

this.updateAddRowButton();
// onDeleteRow callback
this.settings.onDeleteRow(row.$tr);
},
canAddRow: function() {
return (this.rowCount < this.maxRows);
},
addRow: function() {
if (this.hasMinRows && this.hasMaxRows) {
if (!this.canAddRow()) {
return;
}
}

var rowId = this.settings.rowIdPrefix + (this.biggestId + 1),
$tr = this.createRow(rowId, this.columns, this.baseName, $.extend({}, this.settings.defaultValues));

Expand All @@ -12633,6 +12689,9 @@ Craft.EditableTable = Garnish.Base.extend(
// Focus the first input in the row
$tr.find('input,textarea,select').first().trigger('focus');

this.rowCount++;
this.updateAddRowButton();

// onAddRow callback
this.settings.onAddRow($tr);
},
Expand Down Expand Up @@ -12946,11 +13005,7 @@ Craft.EditableTable.Row = Garnish.Base.extend(
},

deleteRow: function() {
this.table.sorter.removeItems(this.$tr);
this.$tr.remove();

// onDeleteRow callback
this.table.settings.onDeleteRow(this.$tr);
this.table.deleteRow(this);
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/web/assets/cp/dist/js/Craft.min.js

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

67 changes: 61 additions & 6 deletions src/web/assets/cp/src/js/EditableTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Craft.EditableTable = Garnish.Base.extend(
$tbody: null,
$addRowBtn: null,

rowCount: 0,
hasMaxRows: false,
hasMinRows: false,

radioCheckboxes: null,

init: function(id, baseName, columns, settings) {
Expand All @@ -25,9 +29,15 @@ Craft.EditableTable = Garnish.Base.extend(
this.columns = columns;
this.setSettings(settings, Craft.EditableTable.defaults);
this.radioCheckboxes = {};
this.minRows = settings['defaultValues']['minRows'];
this.maxRows = settings['defaultValues']['maxRows'];

this.hasMinRows = this.minRows !== null;
this.hasMaxRows = this.maxRows !== null;

this.$table = $('#' + id);
this.$tbody = this.$table.children('tbody');
this.rowCount = this.$tbody.find('tr').length;

this.sorter = new Craft.DataTableSorter(this.$table, {
helperClass: 'editabletablesorthelper',
Expand All @@ -40,6 +50,14 @@ Craft.EditableTable = Garnish.Base.extend(
// Give everything a chance to initialize
setTimeout($.proxy(this, 'initializeIfVisible'), 500);
}

if (this.hasMinRows && this.rowCount < this.minRows) {
for (var i = 0; i < this.minRows; i++) {
this.addRow()
}
}

this.updateAddRowButton();
},

isVisible: function() {
Expand All @@ -63,7 +81,6 @@ Craft.EditableTable = Garnish.Base.extend(
this.$addRowBtn = this.$table.next('.add');
this.addListener(this.$addRowBtn, 'activate', 'addRow');
},

initializeIfVisible: function() {
this.removeListener(Garnish.$win, 'resize');

Expand All @@ -73,8 +90,47 @@ Craft.EditableTable = Garnish.Base.extend(
this.addListener(Garnish.$win, 'resize', 'initializeIfVisible');
}
},
updateAddRowButton: function() {
if ((this.hasMaxRows && this.rowCount >= this.maxRows) ||
(this.hasMinRows && this.rowCount < this.minRows)) {
this.$addRowBtn.css('opacity', '0.2');
this.$addRowBtn.css('pointer-events', 'none');
} else {
this.$addRowBtn.css('opacity', '1');
this.$addRowBtn.css('pointer-events', 'auto');
}
},
canDeleteRow: function() {
return (this.rowCount > this.minRows);
},
deleteRow: function(row) {
if (this.hasMaxRows && this.hasMinRows) {
if (!this.canDeleteRow()) {
return;
}
}

this.sorter.removeItems(row.$tr);
row.$tr.remove();

if (this.hasMinRows && this.hasMinRows) {
this.rowCount--;
}

this.updateAddRowButton();
// onDeleteRow callback
this.settings.onDeleteRow(row.$tr);
},
canAddRow: function() {
return (this.rowCount < this.maxRows);
},
addRow: function() {
if (this.hasMinRows && this.hasMaxRows) {
if (!this.canAddRow()) {
return;
}
}

var rowId = this.settings.rowIdPrefix + (this.biggestId + 1),
$tr = this.createRow(rowId, this.columns, this.baseName, $.extend({}, this.settings.defaultValues));

Expand All @@ -85,6 +141,9 @@ Craft.EditableTable = Garnish.Base.extend(
// Focus the first input in the row
$tr.find('input,textarea,select').first().trigger('focus');

this.rowCount++;
this.updateAddRowButton();

// onAddRow callback
this.settings.onAddRow($tr);
},
Expand Down Expand Up @@ -398,11 +457,7 @@ Craft.EditableTable.Row = Garnish.Base.extend(
},

deleteRow: function() {
this.table.sorter.removeItems(this.$tr);
this.$tr.remove();

// onDeleteRow callback
this.table.settings.onDeleteRow(this.$tr);
this.table.deleteRow(this);
}
},
{
Expand Down

0 comments on commit 962e618

Please sign in to comment.