diff --git a/.env.example b/.env.example index 355194e..bb9353a 100644 --- a/.env.example +++ b/.env.example @@ -38,8 +38,6 @@ MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" -PRETTY_JSON=true - OAUTH_GITHUB_ID= OAUTH_GITHUB_SECRET= OAUTH_GITHUB_REDIRECT=https://datatable.directory/auth/github/callback diff --git a/app/Http/Controllers/TableController.php b/app/Http/Controllers/TableController.php index 60e21d8..0a621c3 100644 --- a/app/Http/Controllers/TableController.php +++ b/app/Http/Controllers/TableController.php @@ -72,19 +72,22 @@ class TableController extends Controller */ public function create() { - $exampleColumns = - "latin,string,Latin Name\n" . - "common,string,Common Name\n" . - "lifespan,int,Lifespan (years)"; - $exampleData = "Mercenaria mercenaria,hard clam,40\n" . "Magallana gigas,pacific oyster,30\n" . "Patella vulgata,common limpet,20"; - return view('table.create', - compact('exampleColumns', 'exampleData') - ); + $columns = Column::columnsFromJson([ + ['name' => 'latin', 'type' => 'string', 'title' => 'Latin Name'], + ['name' => 'common', 'type' => 'string', 'title' => 'Common Name'], + ['name' => 'lifespan', 'type' => 'int', 'title' => 'Lifespan (years)'] + ]); + + return view('table.create', [ + 'exampleColumns' => '', + 'columns' => $columns, + 'exampleData' => $exampleData, + ]); } public function settings(Request $request, User $user, string $table) @@ -141,7 +144,7 @@ class TableController extends Controller 'description' => ['nullable', VALI_TEXT], 'license' => ['nullable', VALI_TEXT], 'origin' => ['nullable', VALI_TEXT], - 'columns' => 'required|string', + 'columns' => 'required|json', 'data' => 'string|nullable', ]); @@ -156,28 +159,24 @@ class TableController extends Controller /** @var Column[] $columns */ $columns = []; $column_keys = []; // for checking duplicates - $colTable = array_map('str_getcsv', explode("\n", $input->columns)); + $colsArray = fromJSON($input->columns); // prevent griefing via long list of columns - if (count($colTable) > 100) return $this->backWithErrors(['columns' => "Too many columns"]); + if (count($colsArray) > 100) return $this->backWithErrors(['columns' => "Too many columns"]); - foreach ($colTable as $col) { - $col = array_map('trim', $col); - if (count($col) < 2 || strlen($col[0])==0) { + foreach ($colsArray as $col) { + if (!isset($col->name) || !isset($col->type) || empty($col->name) || empty($col->type)) { return $this->backWithErrors(['columns' => "All columns must have at least name and type."]); } try { - if (in_array($col[0], $column_keys)) { - return $this->backWithErrors(['columns' => "Duplicate column: $col[0]"]); + if (in_array($col->name, $column_keys)) { + return $this->backWithErrors(['columns' => "Duplicate column: $col->name"]); } - $column_keys[] = $col[0]; + $column_keys[] = $col->name; - $columns[] = new Column([ - 'name' => $col[0], - 'type' => $col[1], - 'title' => count($col) >= 3 ? $col[2] : $col[0], // title falls back to =name if not specified, - ]); + if (!isset($col->title)) $col->title = $col->name; + $columns[] = new Column($col); } catch (\Exception $e) { return $this->backWithErrors(['columns' => $e->getMessage()]); } diff --git a/app/helpers.php b/app/helpers.php index dacd548..178ffa1 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -67,3 +67,27 @@ function vali($arr) { } return $result; } + + + +/** + * like old(), but decodes stringified json + * + * @param string $name + * @param object|array $default + * @return object|array + */ +function old_json($name, $default) { + $old = old($name, null); + if (is_string($old)) return json_decode($old); + return $default; +} + +// Safe JSON funcs +function toJSON($object) { + return \GuzzleHttp\json_encode($object, JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE); +} + +function fromJSON($object, $assoc=false) { + return \GuzzleHttp\json_decode($object, $assoc); +} diff --git a/config/app.php b/config/app.php index 13c3b78..692b7d2 100644 --- a/config/app.php +++ b/config/app.php @@ -222,7 +222,6 @@ return [ ], // -------------- added keys -------------- - 'pretty_json' => env('PRETTY_JSON', false), 'debug_blacklist' => [ '_COOKIE' => array_keys($_COOKIE), diff --git a/porklib/Providers/BladeExtensionsProvider.php b/porklib/Providers/BladeExtensionsProvider.php index 8aff1e5..a0c34cf 100644 --- a/porklib/Providers/BladeExtensionsProvider.php +++ b/porklib/Providers/BladeExtensionsProvider.php @@ -44,11 +44,7 @@ class BladeExtensionsProvider extends ServiceProvider // json encode Blade::directive('json', function ($x) { - if (config('app.pretty_json')) { - return ""; - } else { - return ""; - } + return ""; }); // json encode, escaped diff --git a/public/fonts/fa-dtbl-1-preview.html b/public/fonts/fa-dtbl-1-preview.html index c171c3a..60afadf 100644 --- a/public/fonts/fa-dtbl-1-preview.html +++ b/public/fonts/fa-dtbl-1-preview.html @@ -166,6 +166,7 @@ .fa-code-fork:before, .fa-comment:before, .fa-download:before, +.fa-exclamation-triangle:before, .fa-eye:before, .fa-facebook-square:before, .fa-floppy-o:before, @@ -178,6 +179,7 @@ .fa-key-modern:before, .fa-link:before, .fa-pencil:before, +.fa-plus:before, .fa-question-circle:before, .fa-sign-in:before, .fa-sign-out:before, @@ -185,6 +187,7 @@ .fa-star-o:before, .fa-table:before, .fa-th-list:before, +.fa-trash-o:before, .fa-user:before, .fa-user-circle-o:before, .fa-user-plus:before, @@ -209,30 +212,33 @@ .fa-code-fork:before { content: "\f102"; } .fa-comment:before { content: "\f103"; } .fa-download:before { content: "\f104"; } -.fa-eye:before { content: "\f105"; } -.fa-facebook-square:before { content: "\f106"; } -.fa-floppy-o:before { content: "\f107"; } -.fa-github:before { content: "\f108"; } -.fa-globe:before { content: "\f109"; } -.fa-google:before { content: "\f10a"; } -.fa-history:before { content: "\f10b"; } -.fa-home:before { content: "\f10c"; } -.fa-inbox:before { content: "\f10d"; } -.fa-key-modern:before { content: "\f10e"; } -.fa-link:before { content: "\f10f"; } -.fa-pencil:before { content: "\f110"; } -.fa-question-circle:before { content: "\f111"; } -.fa-sign-in:before { content: "\f112"; } -.fa-sign-out:before { content: "\f113"; } -.fa-star:before { content: "\f114"; } -.fa-star-o:before { content: "\f115"; } -.fa-table:before { content: "\f116"; } -.fa-th-list:before { content: "\f117"; } -.fa-user:before { content: "\f118"; } -.fa-user-circle-o:before { content: "\f119"; } -.fa-user-plus:before { content: "\f11a"; } -.fa-users:before { content: "\f11b"; } -.fa-wrench:before { content: "\f11c"; } +.fa-exclamation-triangle:before { content: "\f105"; } +.fa-eye:before { content: "\f106"; } +.fa-facebook-square:before { content: "\f107"; } +.fa-floppy-o:before { content: "\f108"; } +.fa-github:before { content: "\f109"; } +.fa-globe:before { content: "\f10a"; } +.fa-google:before { content: "\f10b"; } +.fa-history:before { content: "\f10c"; } +.fa-home:before { content: "\f10d"; } +.fa-inbox:before { content: "\f10e"; } +.fa-key-modern:before { content: "\f10f"; } +.fa-link:before { content: "\f110"; } +.fa-pencil:before { content: "\f111"; } +.fa-plus:before { content: "\f112"; } +.fa-question-circle:before { content: "\f113"; } +.fa-sign-in:before { content: "\f114"; } +.fa-sign-out:before { content: "\f115"; } +.fa-star:before { content: "\f116"; } +.fa-star-o:before { content: "\f117"; } +.fa-table:before { content: "\f118"; } +.fa-th-list:before { content: "\f119"; } +.fa-trash-o:before { content: "\f11a"; } +.fa-user:before { content: "\f11b"; } +.fa-user-circle-o:before { content: "\f11c"; } +.fa-user-plus:before { content: "\f11d"; } +.fa-users:before { content: "\f11e"; } +.fa-wrench:before { content: "\f11f"; } @@ -248,7 +254,7 @@
-

fa-dtbl-1 contains 29 glyphs:

+

fa-dtbl-1 contains 32 glyphs:

Toggle Preview Characters
@@ -319,6 +325,20 @@
+
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ + + +
+
+
PpPpPpPpPpPpPpPpPpPp @@ -328,7 +348,7 @@
- +
@@ -341,7 +361,7 @@
- +
@@ -355,7 +375,7 @@
- +
@@ -368,7 +388,7 @@
- +
@@ -381,7 +401,7 @@
- +
@@ -394,7 +414,7 @@
- +
@@ -407,7 +427,7 @@
- +
@@ -420,7 +440,7 @@
- +
@@ -433,7 +453,7 @@
- +
@@ -446,7 +466,7 @@
- +
@@ -459,7 +479,7 @@
- +
@@ -472,7 +492,20 @@
- + +
+ + +
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ +
@@ -485,7 +518,7 @@
- +
@@ -498,7 +531,7 @@
- +
@@ -511,7 +544,7 @@
- +
@@ -524,7 +557,7 @@
- +
@@ -537,7 +570,7 @@
- +
@@ -550,7 +583,7 @@
- +
@@ -563,7 +596,20 @@
- + +
+ + +
+
+ PpPpPpPpPpPpPpPpPpPp +
+
+ 12141618212436486072 +
+
+ +
@@ -576,7 +622,7 @@
- +
@@ -589,7 +635,7 @@
- +
@@ -602,7 +648,7 @@
- +
@@ -615,7 +661,7 @@
- +
@@ -628,7 +674,7 @@
- +
diff --git a/public/fonts/fa-dtbl-1.css b/public/fonts/fa-dtbl-1.css index 134b96f..2a98041 100644 --- a/public/fonts/fa-dtbl-1.css +++ b/public/fonts/fa-dtbl-1.css @@ -43,27 +43,30 @@ .fa-code-fork::before { content: "\f102"; } .fa-comment::before { content: "\f103"; } .fa-download::before { content: "\f104"; } -.fa-eye::before { content: "\f105"; } -.fa-facebook-square::before { content: "\f106"; } -.fa-floppy-o::before, .fa-save::before { content: "\f107"; } -.fa-github::before { content: "\f108"; } -.fa-globe::before { content: "\f109"; } -.fa-google::before { content: "\f10a"; } -.fa-history::before { content: "\f10b"; } -.fa-home::before { content: "\f10c"; } -.fa-inbox::before { content: "\f10d"; } -.fa-key-modern::before { content: "\f10e"; } -.fa-link::before { content: "\f10f"; } -.fa-pencil::before { content: "\f110"; } -.fa-question-circle::before { content: "\f111"; } -.fa-sign-in::before { content: "\f112"; } -.fa-sign-out::before { content: "\f113"; } -.fa-star::before { content: "\f114"; } -.fa-star-o::before { content: "\f115"; } -.fa-table::before { content: "\f116"; } -.fa-th-list::before { content: "\f117"; } -.fa-user::before { content: "\f118"; } -.fa-user-circle-o::before { content: "\f119"; } -.fa-user-plus::before { content: "\f11a"; } -.fa-users::before { content: "\f11b"; } -.fa-wrench::before { content: "\f11c"; } +.fa-exclamation-triangle::before, .fa-warning::before { content: "\f105"; } +.fa-eye::before { content: "\f106"; } +.fa-facebook-square::before { content: "\f107"; } +.fa-floppy-o::before, .fa-save::before { content: "\f108"; } +.fa-github::before { content: "\f109"; } +.fa-globe::before { content: "\f10a"; } +.fa-google::before { content: "\f10b"; } +.fa-history::before { content: "\f10c"; } +.fa-home::before { content: "\f10d"; } +.fa-inbox::before { content: "\f10e"; } +.fa-key-modern::before { content: "\f10f"; } +.fa-link::before { content: "\f110"; } +.fa-pencil::before { content: "\f111"; } +.fa-plus::before { content: "\f112"; } +.fa-question-circle::before { content: "\f113"; } +.fa-sign-in::before { content: "\f114"; } +.fa-sign-out::before { content: "\f115"; } +.fa-star::before { content: "\f116"; } +.fa-star-o::before { content: "\f117"; } +.fa-table::before { content: "\f118"; } +.fa-th-list::before { content: "\f119"; } +.fa-trash-o::before { content: "\f11a"; } +.fa-user::before { content: "\f11b"; } +.fa-user-circle-o::before { content: "\f11c"; } +.fa-user-plus::before { content: "\f11d"; } +.fa-users::before { content: "\f11e"; } +.fa-wrench::before { content: "\f11f"; } diff --git a/public/fonts/fa-dtbl-1.eot b/public/fonts/fa-dtbl-1.eot index 3083190..71ba15c 100644 Binary files a/public/fonts/fa-dtbl-1.eot and b/public/fonts/fa-dtbl-1.eot differ diff --git a/public/fonts/fa-dtbl-1.svg b/public/fonts/fa-dtbl-1.svg index d2153ea..3115101 100644 --- a/public/fonts/fa-dtbl-1.svg +++ b/public/fonts/fa-dtbl-1.svg @@ -1,11 +1,11 @@ -Created by FontForge 20170805 at Sun Jul 29 20:18:03 2018 +Created by FontForge 20170805 at Sat Aug 4 10:56:23 2018 By ondra The Fork Awesome font is licensed under the SIL OFL 1.1 (http://scripts.sil.org/OFL). Fork Awesome is a fork based of off Font Awesome 4.7.0 by Dave Gandy. More info on licenses at https://forkawesome.github.io @@ -22,7 +22,7 @@ The Fork Awesome font is licensed under the SIL OFL 1.1 (http://scripts.sil.org/ bbox="-0.14014 -256.168 2048 1536.01" underline-thickness="89.6" underline-position="-179.2" - unicode-range="U+0020-F11C" + unicode-range="U+0020-F11F" /> - + - - - - - - - - - - - - + - - - - - - - + - - - - diff --git a/public/fonts/fa-dtbl-1.ttf b/public/fonts/fa-dtbl-1.ttf index 24830b5..9225050 100644 Binary files a/public/fonts/fa-dtbl-1.ttf and b/public/fonts/fa-dtbl-1.ttf differ diff --git a/public/fonts/fa-dtbl-1.woff2 b/public/fonts/fa-dtbl-1.woff2 index 49d56af..8555166 100644 Binary files a/public/fonts/fa-dtbl-1.woff2 and b/public/fonts/fa-dtbl-1.woff2 differ diff --git a/resources/assets/js/app.js b/resources/assets/js/app.js index cde0ca4..866d344 100644 --- a/resources/assets/js/app.js +++ b/resources/assets/js/app.js @@ -9,6 +9,9 @@ require('./bootstrap') let url_slug = require('./url-slug') $(function () { + // Remove all noscript from forms etc + $('noscript').remove(); + $('[data-toggle="tooltip"]').tooltip({ container: 'body' }) @@ -62,17 +65,11 @@ $(document).on('input keypress paste keyup', 'input[data-autoalias]', function ( } }) -// -// window.Vue = require('vue'); -// -// /** -// * Next, we will create a fresh Vue application instance and attach it to -// * the page. Then, you may begin adding components to this application -// * or customize the JavaScript scaffolding to fit your unique needs. -// */ -// -// Vue.component('example-component', require('./components/ExampleComponent.vue')); -// -// const app = new Vue({ -// el: '#app' -// }); +window.Vue = require('vue'); + +Vue.component('column-editor', require('./components/ColumnEditor.vue')); +Vue.component('v-icon', require('./components/Icon.vue')); + +const app = new Vue({ + el: '#app' +}); diff --git a/resources/assets/js/components/ColumnEditor.vue b/resources/assets/js/components/ColumnEditor.vue new file mode 100644 index 0000000..2f49319 --- /dev/null +++ b/resources/assets/js/components/ColumnEditor.vue @@ -0,0 +1,89 @@ +
+ + + + + + + + + + + + + + + + + + + + + +
NameTypeTitle
+ + + + + + + + + + + +
+
+ + + + + diff --git a/resources/assets/js/components/ExampleComponent.vue b/resources/assets/js/components/ExampleComponent.vue deleted file mode 100644 index 2805329..0000000 --- a/resources/assets/js/components/ExampleComponent.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/resources/assets/js/components/Icon.vue b/resources/assets/js/components/Icon.vue new file mode 100644 index 0000000..d69f391 --- /dev/null +++ b/resources/assets/js/components/Icon.vue @@ -0,0 +1,21 @@ + + + diff --git a/resources/assets/js/components/_base.scss b/resources/assets/js/components/_base.scss new file mode 100644 index 0000000..f926487 --- /dev/null +++ b/resources/assets/js/components/_base.scss @@ -0,0 +1 @@ +@import "../../sass/bootstrap-base"; diff --git a/resources/assets/sass/_bootstrap-base.scss b/resources/assets/sass/_bootstrap-base.scss new file mode 100644 index 0000000..56da852 --- /dev/null +++ b/resources/assets/sass/_bootstrap-base.scss @@ -0,0 +1,5 @@ +@import "~bootstrap/scss/functions"; +@import "~bootstrap/scss/variables"; +@import "~bootstrap/scss/mixins"; +@import "mixins"; +@import "bootstrap-customizations/variables"; diff --git a/resources/assets/sass/_bootstrap.scss b/resources/assets/sass/_bootstrap.scss index 53bb168..f970e95 100644 --- a/resources/assets/sass/_bootstrap.scss +++ b/resources/assets/sass/_bootstrap.scss @@ -1,8 +1,4 @@ -@import "~bootstrap/scss/functions"; -@import "~bootstrap/scss/variables"; -@import "~bootstrap/scss/mixins"; - -@import "bootstrap-customizations/variables"; +@import "bootstrap-base"; @import "bootstrap-customizations/_helpers-before"; @import "~bootstrap/scss/root"; diff --git a/resources/assets/sass/_mixins.scss b/resources/assets/sass/_mixins.scss new file mode 100644 index 0000000..117bba1 --- /dev/null +++ b/resources/assets/sass/_mixins.scss @@ -0,0 +1,55 @@ +@function dist($x) { + @return $spacer*.25*$x; +} + +@mixin py($n) { + padding-top: dist($n); + padding-bottom: dist($n); +} + +@mixin px($n) { + padding-left: dist($n); + padding-right: dist($n); +} + +@mixin my($n) { + margin-top: dist($n); + margin-bottom: dist($n); +} + +@mixin mx($n) { + margin-left: dist($n); + margin-right: dist($n); +} + +@mixin pl($n) { + padding-left: dist($n); +} + +@mixin pr($n) { + padding-right: dist($n); +} + +@mixin pt($n) { + padding-top: dist($n); +} + +@mixin pb($n) { + padding-bottom: dist($n); +} + +@mixin ml($n) { + margin-left: dist($n); +} + +@mixin mr($n) { + margin-right: dist($n); +} + +@mixin mt($n) { + margin-top: dist($n); +} + +@mixin mb($n) { + margin-bottom: dist($n); +} diff --git a/resources/assets/sass/bootstrap-customizations/_variables.scss b/resources/assets/sass/bootstrap-customizations/_variables.scss index e58d4e8..49fd85a 100644 --- a/resources/assets/sass/bootstrap-customizations/_variables.scss +++ b/resources/assets/sass/bootstrap-customizations/_variables.scss @@ -1,7 +1,10 @@ $sp0: 0; $sp1_2: $spacer*.25; -$sp1: $spacer*.5; + +$sp1_4: $spacer*.125; +$sp2_4: $sp1_2; $sp3_4: $spacer*.75; + $sp1: $spacer*.5; $sp2: $spacer*1; $sp3: $spacer*1.5; diff --git a/resources/views/form/input.blade.php b/resources/views/form/input.blade.php index 175a395..99ff9a5 100644 --- a/resources/views/form/input.blade.php +++ b/resources/views/form/input.blade.php @@ -29,8 +29,8 @@ @if ($errors->has($w->name)) - {{ $errors->first($w->name) }} - + {{ $errors->first($w->name) }} + @endif diff --git a/resources/views/table/create.blade.php b/resources/views/table/create.blade.php index b64fb4b..9eb9602 100644 --- a/resources/views/table/create.blade.php +++ b/resources/views/table/create.blade.php @@ -30,7 +30,7 @@ ->help('If you took the data from some external site, a book, etc., write it here. URLs in a full format will be clickable.') !!} - {!! Widget::textarea('columns', 'Columns')->value($exampleColumns)->height('8em') + {{--!! Widget::textarea('columns', 'Columns')->value($exampleColumns)->height('8em') ->help('
Column parameters in CSV format: @@ -39,7 +39,34 @@
  • column data type
    int, string, float, bool
  • column title
    used for display (optional) -
  • ') !!} + ') !!--}} + +
    + +
    + + + + + @if ($errors->has('columns')) + + {{ $errors->first('columns') }} + + @endif + + @if($errors->has('columns')) + + @icon(fa-warning, sr:Validation error:) + {{$errors->first('columns')}} + + @endif +
    +
    {!! Widget::textarea('data', 'Initial data')->value($exampleData)->height('12em') ->help('