diff --git a/app/Http/Controllers/TableController.php b/app/Http/Controllers/TableController.php index c7f5644..3a747ab 100644 --- a/app/Http/Controllers/TableController.php +++ b/app/Http/Controllers/TableController.php @@ -81,16 +81,17 @@ class TableController extends Controller */ public function create() { - $exampleData = - "Mercenaria mercenaria,hard clam,40\n" . - "Magallana gigas,pacific oyster,30\n" . - "Patella vulgata,common limpet,20"; + $exampleData = ""; +// "Mercenaria mercenaria,hard clam,40\n" . +// "Magallana gigas,pacific oyster,30\n" . +// "Patella vulgata,common limpet,20"; $columns = Column::columnsFromJson([ // fake 'id' to satisfy the check in Column constructor - ['id' => 1, 'name' => 'latin', 'type' => 'string', 'title' => 'Latin Name'], - ['id' => 2, 'name' => 'common', 'type' => 'string', 'title' => 'Common Name'], - ['id' => 3, 'name' => 'lifespan', 'type' => 'int', 'title' => 'Lifespan (years)'] + ['id' => 1, 'name' => 'column_1', 'type' => 'string', 'title' => 'First Column'], +// ['id' => 1, 'name' => 'latin', 'type' => 'string', 'title' => 'Latin Name'], +// ['id' => 2, 'name' => 'common', 'type' => 'string', 'title' => 'Common Name'], +// ['id' => 3, 'name' => 'lifespan', 'type' => 'int', 'title' => 'Lifespan (years)'] ]); return view('table.create', [ @@ -210,7 +211,33 @@ class TableController extends Controller } // --- DATA --- - $dataCsvLines = Utils::csvToArray($input->data); + $fname = 'csv-file'; + $dataCsvLines = []; + if ($request->hasFile($fname)) { + try { + $file = $request->file($fname); + if ($file->isValid() && $file->isReadable()) { + $handle = $file->openFile(); + $dataCsvLines = Utils::csvToArray($handle); + if (empty($dataCsvLines)) throw new \Exception("Failed to parse CSV file."); + $handle = null; + } else { + throw new \Exception("File not valid."); + } + } catch (\Exception $e) { + return $this->backWithErrors(['csv-file' => $e->getMessage()]); + } + } + else if ($input->data) { + try { + $text = trim($input->data); + if (!empty($text)) { + $dataCsvLines = Utils::csvToArray($text); + } + } catch (\Exception $e) { + return $this->backWithErrors(['data' => $e->getMessage()]); + } + } // Preparing data to insert into the Rows table $rowsToInsert = null; diff --git a/app/Models/Row.php b/app/Models/Row.php index caa0b82..58a75c4 100644 --- a/app/Models/Row.php +++ b/app/Models/Row.php @@ -83,6 +83,7 @@ class Row extends BaseModel */ public static function allocateRowIDs($count) { + if ($count == 0) return null; $last = \DB::selectOne("SELECT multi_nextval('global_row_id_seq', ?) AS last_id;", [$count])->last_id; return [$last - $count + 1, $last]; } diff --git a/resources/assets/js/components/ColumnEditor.vue b/resources/assets/js/components/ColumnEditor.vue index 57956c8..124201f 100644 --- a/resources/assets/js/components/ColumnEditor.vue +++ b/resources/assets/js/components/ColumnEditor.vue @@ -63,6 +63,9 @@ Complex animated column editor for the table edit page @@ -81,6 +84,9 @@ Complex animated column editor for the table edit page @@ -141,7 +147,7 @@ Complex animated column editor for the table edit page @media screen and (min-width: 625px) { table.new-table { - margin-left: -53px; + margin-left: -66px; } } @@ -471,6 +477,34 @@ export default { for (const [key, value] of Object.entries(col._loadvals)) { col[key] = value } + }, + + /** + * Move to next or prev editable cell vertically + * + * @param index + * @param field + * @param dir - +1 down, -1 up + */ + verticalTab (index, field, dir) { + if (dir == -1) { + // up + for(let i = index-1; i>= 0; i--) { + if (this.columns[i]._editing || this.newTable) { + this.$refs[`edit-${i}-${field}`][0].focus() + break; + } + } + } + else { + // down + for(let i = index+1; i < this.columns.length; i++) { + if (this.columns[i]._editing || this.newTable) { + this.$refs[`edit-${i}-${field}`][0].focus() + break; + } + } + } } } } diff --git a/resources/views/table/create.blade.php b/resources/views/table/create.blade.php index 7f4904b..0ed033c 100644 --- a/resources/views/table/create.blade.php +++ b/resources/views/table/create.blade.php @@ -4,6 +4,7 @@ @section('content')
@csrf @@ -57,11 +58,15 @@ - {!! Widget::textarea('data', 'Initial data')->value($exampleData)->height('12em') - ->help(' - Initial table data in CSV format, columns corresponding to the - specification you entered above. This is optional; you can fill the table - later, e.g. by uploading a CSV file.') !!} + {!! Widget::par(' + Initialize the table with pasted CSV lines or an uploaded CSV file, + using the column order you defined above. This is optional, you can always + fill or modify the table later. + ', 'text-muted') !!} + + {!! Widget::textarea('data', 'CSV as text')->value($exampleData)->height('12em') !!} + + {!! Widget::file('csv-file', 'CSV file')->accept("text/csv") !!}
diff --git a/resources/views/table/propose/add-rows-csv.blade.php b/resources/views/table/propose/add-rows-csv.blade.php index 2679b63..dfaa464 100644 --- a/resources/views/table/propose/add-rows-csv.blade.php +++ b/resources/views/table/propose/add-rows-csv.blade.php @@ -23,7 +23,7 @@ } @endphp - {!! Widget::par('Append rows from pasted CSV lines or uploaded CSV file') !!} + {!! Widget::par('Append rows from pasted CSV lines or an uploaded CSV file') !!} {{-- TODO interactive widget to select which cols are included, and in which order --}} {!! Widget::labeledPar('Columns', implode(', ', $cols), '', false) !!}