From 61292d814500a8377fa31f9d8753c406e58f7fb9 Mon Sep 17 00:00:00 2001 From: Nick de Kruijk Date: Mon, 25 Nov 2019 16:40:57 +0100 Subject: [PATCH] Add support for 'rows' column type --- src/Controllers/BaseController.php | 34 +++++++++++++++++++++++++++++ src/Controllers/ModelController.php | 30 +++++++++++++++++++++++++ src/css/base.css | 11 ++++++++++ src/js/model.js | 25 +++++++++++++++++++++ src/views/model.blade.php | 5 +++++ 5 files changed, 105 insertions(+) diff --git a/src/Controllers/BaseController.php b/src/Controllers/BaseController.php index 257b913..cc6dab7 100644 --- a/src/Controllers/BaseController.php +++ b/src/Controllers/BaseController.php @@ -468,4 +468,38 @@ public function pivot($columnId, $column) } return $response; } + + // Return the line input for a many to many (pivot) relationship + public function rows($columnId, $column) + { + $data = $this->getModelData($column); + $response = ''; + $response .= ''; + foreach ($column['columns'] as $columnId2 => $opt) { + $response .= ''; + } + if ($this->can('delete')) { + $response .= ''; + } + $response .= ''; + $response .= ''; + foreach ($column['columns'] as $col => $opt) { + $response .= ''; + } + $response .= ''; + $response .= '
'; + if (empty($opt['type'])) { + $opt['type'] = 'string'; + } + + if ($opt['type'] == 'string' || $opt['type'] == 'password' || $opt['type'] == 'date' || $opt['type'] == 'datetime' || $opt['type'] == 'number') { + $response .= ''; + } elseif ($opt['type'] == 'foreign') { + $response .= $this->foreign($columnId . '_' . $columnId2.'[]', $opt, false); + } else { + $response .= $opt['type']; + } + $response .= '
' . $this->locale('title', $opt, $col) . '
'; + return $response; + } } diff --git a/src/Controllers/ModelController.php b/src/Controllers/ModelController.php index 170c37a..429f23d 100644 --- a/src/Controllers/ModelController.php +++ b/src/Controllers/ModelController.php @@ -23,12 +23,22 @@ private function save($model, Request $request) $sync = []; $morph = []; + $row = []; foreach($this->columns() as $columnId => $column) { if (isset($column['type']) && $column['type'] == 'pivot') { $sync[$column['model']] = $request[$columnId]; if (!empty($column['morph'])) { $morph[$column['model']] = $column['morph']; } + } elseif (isset($column['type']) && $column['type'] == 'rows') { + $row[$column['model']]['self'] = $column['self']; + foreach($column['columns'] as $columnId2 => $opt) { + $r = $request[$columnId . '_' . $columnId2]; + array_shift($r); + foreach($r as $key => $value) { + $row[$column['model']][$key][$columnId2] = $value; + } + } } elseif (isset($column['type']) && $column['type'] == 'array') { // If column is of type array json decode it $model[$columnId] = json_decode($request[$columnId], true); @@ -57,6 +67,21 @@ private function save($model, Request $request) $model->save(); + foreach($row as $foreign => $data) { + $fm = new $foreign; + $self = $data['self']; + unset($data['self']); + $fm::where($self, $model->id)->delete(); + foreach($data as $row) { + $fm = new $foreign; + $fm->$self = $model->id; + foreach($row as $column => $value) { + $fm->$column = $value; + } + $fm->save(); + } + } + foreach($sync as $foreign => $values) { if (isset($morph[$foreign])) { $model->morphToMany($foreign, $morph[$foreign])->sync($values); @@ -114,6 +139,11 @@ public function show($slug, $id) if ($column['type'] == 'array') { $row[$columnId] = json_encode(json_decode($row[$columnId]), JSON_PRETTY_PRINT); } + // If column type is rows return those rows + if ($column['type'] == 'rows') { + unset($row['"'.$columnId.'"']); + $row[$columnId] = $this->model()::findOrFail($id)->hasMany($column['model'])->get(array_keys($column['columns']))->toArray(); + } // If column type is pivot return matching ids if ($column['type'] == 'pivot') { unset($row['"'.$columnId.'"']); diff --git a/src/css/base.css b/src/css/base.css index 13d45a3..f163b55 100644 --- a/src/css/base.css +++ b/src/css/base.css @@ -187,6 +187,17 @@ nav li:hover > ul > li {max-height:40px} #editview UL.input_images > .button.add:not(:first-child) {width:45px;height:90px;opacity:0.3} #editview UL.input_images > .button.add:not(:first-child):hover {opacity:1} #editview UL.input_images.image > .button.add:not(:first-child) {display:none} +#editview .content TABLE.rows {border-spacing:0;border-collapse:collapse;max-width:100%} +#editview .content TABLE.rows TR.template {display:none} +#editview .content TABLE.rows TR:last-child TH {display:none} +#editview .content TABLE.rows TH, +#editview .content TABLE.rows TD {font-weight:inherit;text-align:left;padding:0 0 3px 3px} +#editview .content TABLE.rows TH:first-child, +#editview .content TABLE.rows TD:first-child {padding-left:0} +#editview .content TABLE.rows SELECT {width:100%} +#editview .content TABLE.rows .button {padding:3px 7px 4px} +#editview .content TABLE.rows INPUT {padding:1px 4px 2px} + #editview .content TABLE.array {border-spacing:0;border-collapse:collapse} #editview .content TABLE.array TD:first-child {color:rgba(0,0,0,0.5);padding-right:0.5em;font-size:0.95em} #editview .content TABLE.array TD:first-child:first-letter {text-transform:uppercase} diff --git a/src/js/model.js b/src/js/model.js index 039cf3c..1c7ec1a 100644 --- a/src/js/model.js +++ b/src/js/model.js @@ -170,6 +170,7 @@ function modelShow(slug, id) { $.ajax(slug + '/' + id, { cache: false, }).done(function (data, status, xhr) { + $('#editview .rows .data').remove(); for (i in data) { if (i.substr(0, 7) == '_pivot.') { $('#editview input[type=checkbox].pivot-' + i.substr(7)).prop('checked', false); @@ -187,6 +188,11 @@ function modelShow(slug, id) { }); } else if ($('#input_' + i).attr('type') == 'checkbox') { $('#input_' + i).prop('checked', data[i] == true); + } else if ($('#input_' + i).is('TABLE') && $('#input_' + i).hasClass('rows')) { + var rowData = data[i]; + for (n in rowData) { + modelAddLine(slug, $('#input_' + i), rowData[n], i) + } } else { $('#input_' + i).val(data[i]).change(); } @@ -512,6 +518,22 @@ function hideColumns(t) { } } +function modelAddLine(slug, element, data, column) { + var tr = $(element).find('TR.template').clone().removeClass('template').addClass('data'); + tr.appendTo($(element)).find('.pivot-delete').click(function () { + $(this).parent().parent().remove(); + }); + if (data) { + for (n in data) { + tr.find('INPUT[data-column='+column+'_'+n+']').val(data[n]); + tr.find('SELECT[data-column='+column+'_'+n+']').val(data[n]); + console.log(n,data[n]); + } + } + // Fix rendering bug that prevents TH from being shown after deleting + $(element).find('TH').hide().show(); +} + function modelInit(slug) { $('.datepicker').datepicker({ showButtonPanel: true, @@ -543,6 +565,9 @@ function modelInit(slug) { $('UL.input_images .button.add').click(function () { modelAddMedia(slug, this); }); + $('DIV.rows .button.add').click(function () { + modelAddLine(slug, $(this).prev()); + }); $('.header .search INPUT').keyup(function (e) { modelSearch(this.value); }); diff --git a/src/views/model.blade.php b/src/views/model.blade.php index 772443f..1f4dbba 100644 --- a/src/views/model.blade.php +++ b/src/views/model.blade.php @@ -82,6 +82,11 @@ {!! $lp->foreign($id, $column) !!} @elseif ($column['type'] == 'pivot')
{!! $lp->pivot($id, $column) !!}
+ @elseif ($column['type'] == 'rows') +
+ {!! $lp->rows($id, $column) !!} + +
@elseif ($column['type'] != 'boolean') {{$column['type']}} @endif