From 2a615b75a7522ec516ce43cb4add96d6a10f3da8 Mon Sep 17 00:00:00 2001 From: Kevin MacMartin Date: Thu, 29 Jul 2021 16:40:55 -0400 Subject: [PATCH] Use a non-static function for getDashboardHeader so we can use getTable and not have to worry about sending the model, pull file and image saving and deletion into the dashboard model so it can be used by seeders and other things, allow filetype to be specified for images so more than just jpg is possible, if the image filetype isn't svg also save a webp version of a given image, add a dashboard model method to get the uploads path so we aren't hard-coding that to one degree or another in a whole bunch of places, allow a max width and/or height to be specified for image uploads to avoid giant images, don't send unnecessary parameters from the back-end to the front-end and through the api back to the back-end, add the ability to show error text to the dashboard alert model, show an error if a file of an incorrect type is uploaded, add webp suport detection logic to the vue-based front end as well as a method that selects the appropriate format of image (falling back on the provided format) --- app/Http/Controllers/DashboardController.php | 83 ++--- app/Models/Blog.php | 4 +- app/Models/DashboardModel.php | 338 ++++++++++++++++-- gulpfile.js | 2 +- readme.md | 6 +- resources/components/pages/blog.vue | 2 +- resources/js/app.js | 23 +- resources/js/dashboard.js | 18 +- resources/js/imports/supports-webp.js | 48 +++ resources/js/mixins/image-type.js | 13 + .../views/dashboard/pages/edit-item.blade.php | 19 +- resources/views/templates/public.blade.php | 5 +- 12 files changed, 464 insertions(+), 97 deletions(-) create mode 100644 resources/js/imports/supports-webp.js create mode 100644 resources/js/mixins/image-type.js diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 0ab8be7..bb231d1 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -28,14 +28,14 @@ class DashboardController extends Controller { return view('dashboard.pages.home'); } - // View Model Data + // Page to View Model Data public function getView($model) { $model_class = Dashboard::getModel($model, 'view'); if ($model_class != null) { return view('dashboard.pages.view', [ - 'heading' => $model_class::getDashboardHeading($model), + 'heading' => $model_class->getDashboardHeading(), 'column_headings' => $model_class::getDashboardColumnData('headings'), 'model' => $model, 'rows' => $model_class::getDashboardData(), @@ -46,7 +46,7 @@ class DashboardController extends Controller { } } - // Edit List of Model Rows + // Page to Edit List of Model Rows public function getEditList($model) { $model_class = Dashboard::getModel($model, 'edit'); @@ -55,7 +55,7 @@ class DashboardController extends Controller { $data = $model_class::getDashboardData(true); return view('dashboard.pages.edit-list', [ - 'heading' => $model_class::getDashboardHeading($model), + 'heading' => $model_class->getDashboardHeading(), 'model' => $model, 'rows' => $data['rows'], 'paramdisplay' => $data['paramdisplay'], @@ -75,7 +75,7 @@ class DashboardController extends Controller { } } - // Create and Edit Model Item + // Page to Create and Edit Model Item public function getEditItem($model, $id = 'new') { $model_class = Dashboard::getModel($model, 'edit'); @@ -103,7 +103,7 @@ class DashboardController extends Controller { } return view('dashboard.pages.edit-item', [ - 'heading' => $model_class::getDashboardHeading($model), + 'heading' => $model_class->getDashboardHeading(), 'model' => $model, 'id' => $id, 'item' => $item, @@ -296,15 +296,14 @@ class DashboardController extends Controller { if (is_null($item)) { return 'record-access-fail'; - } else if (!$item->userCheck()) { - return 'permission-fail'; } else if ($request->hasFile('file')) { - $directory = base_path() . '/public/uploads/' . $request['model'] . '/img/'; - File::makeDirectory($directory, 0755, true, true); - $image = Image::make($request->file('file')); - $image->save($directory . $request['id'] . '-' . $request['name'] . '.jpg'); - $item->touch(); - return 'success'; + $save_result = $item->saveImage($request['name'], $request->file('file')); + + if ($save_result == 'success') { + $item->touch(); + } + + return $save_result; } else { return 'file-upload-fail'; } @@ -319,8 +318,7 @@ class DashboardController extends Controller { $this->validate($request, [ 'id' => 'required', 'model' => 'required', - 'name' => 'required', - 'ext' => 'required' + 'name' => 'required' ]); $model_class = Dashboard::getModel($request['model'], 'edit'); @@ -330,14 +328,14 @@ class DashboardController extends Controller { if (is_null($item)) { return 'record-access-fail'; - } else if (!$item->userCheck()) { - return 'permission-fail'; } else if ($request->hasFile('file')) { - $directory = base_path() . '/public/uploads/' . $request['model'] . '/files/'; - File::makeDirectory($directory, 0755, true, true); - $request->file('file')->move($directory, $request['id'] . '-' . $request['name'] . '.' . $request['ext']); - $item->touch(); - return 'success'; + $save_result = $item->saveFile($request['name'], $request->file('file')); + + if ($save_result == 'success') { + $item->touch(); + } + + return $save_result; } else { return 'file-upload-fail'; } @@ -365,26 +363,18 @@ class DashboardController extends Controller { return 'permission-fail'; } - // delete the row - $item->delete(); - // delete associated files if they exist foreach ($model_class::$dashboard_columns as $column) { if ($column['type'] == 'image') { - $image = base_path() . '/public/uploads/' . $request['model'] . '/img/' . $request['id'] . '-' . $column['name'] . '.jpg'; - - if (file_exists($image) && !unlink($image)) { - return 'image-delete-fail'; - } + $item->deleteImage($column['name'], false); } else if ($column['type'] == 'file') { - $file = base_path() . '/public/uploads/' . $request['model'] . '/files/' . $request['id'] . '-' . $column['name'] . '.' . $column['ext']; - - if (file_exists($file) && !unlink($file)) { - return 'file-delete-fail'; - } + $item->deleteFile($column['name'], false); } } + // delete the row + $item->delete(); + // update the order of the remaining rows if $dashboard_reorder is true if ($model_class::$dashboard_reorder) { foreach ($model_class::getDashboardData() as $index => $item) { @@ -412,20 +402,13 @@ class DashboardController extends Controller { $model_class = Dashboard::getModel($request['model'], 'edit'); if ($model_class != null) { - $image = base_path() . '/public/uploads/' . $request['model'] . '/img/' . $request['id'] . '-' . $request['name'] . '.jpg'; $item = $model_class::find($request['id']); if (is_null($item)) { return 'record-access-fail'; - } else if (!$item->userCheck()) { - return 'permission-fail'; - } else if (!file_exists($image)) { - return 'image-not-exists-fail'; - } else if (!unlink($image)) { - return 'image-delete-fail'; } - return 'success'; + return $item->deleteImage($request['name'], true); } else { return 'model-access-fail'; } @@ -437,27 +420,19 @@ class DashboardController extends Controller { $this->validate($request, [ 'id' => 'required', 'model' => 'required', - 'name' => 'required', - 'ext' => 'required' + 'name' => 'required' ]); $model_class = Dashboard::getModel($request['model'], 'edit'); if ($model_class != null) { - $file = base_path() . '/public/uploads/' . $request['model'] . '/files/' . $request['id'] . '-' . $request['name'] . '.' . $request['ext']; $item = $model_class::find($request['id']); if (is_null($item)) { return 'record-access-fail'; - } else if (!$item->userCheck()) { - return 'permission-fail'; - } else if (!file_exists($file)) { - return 'file-not-exists-fail'; - } else if (!unlink($file)) { - return 'file-delete-fail'; } - return 'success'; + return $item->deleteFile($request['name'], true); } else { return 'model-access-fail'; } diff --git a/app/Models/Blog.php b/app/Models/Blog.php index d305210..39e5033 100644 --- a/app/Models/Blog.php +++ b/app/Models/Blog.php @@ -49,8 +49,8 @@ class Blog extends DashboardModel $blog_entry['tags'] = $tags; // Add the header image if one exists - $header_image_path = '/uploads/blog/img/' . $blog_entry->id . '-header-image.jpg'; - $blog_entry['headerimage'] = file_exists(base_path() . '/public' . $header_image_path) ? $header_image_path . '?version=' . $blog_entry->timestamp() : ''; + $header_image_path = $blog_entry->getUploadsPath('image') . $blog_entry->id . '-header-image.jpg'; + $blog_entry['headerimage'] = file_exists(public_path($header_image_path)) ? $header_image_path . '?version=' . $blog_entry->timestamp() : ''; // Add the processed blog entry to the array array_push($blog_entries, $blog_entry); diff --git a/app/Models/DashboardModel.php b/app/Models/DashboardModel.php index e64a249..70cac68 100644 --- a/app/Models/DashboardModel.php +++ b/app/Models/DashboardModel.php @@ -4,6 +4,8 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Auth; +use File; +use Image; use App\Traits\Timestamp; class DashboardModel extends Model @@ -120,13 +122,316 @@ class DashboardModel extends Model * * @return string */ - public static function getDashboardHeading($model) + public function getDashboardHeading() { - return static::$dashboard_heading == null ? ucfirst($model) : static::$dashboard_heading; + return static::$dashboard_heading == null ? ucfirst($this->getTable()) : static::$dashboard_heading; } /** - * Returns an array of column 'headings' or 'names' + * Return the upload path for a given type + * + * @return boolean + */ + public function getUploadsPath($type) + { + if ($type == 'image') { + return '/uploads/' . $this->getTable() . '/img/'; + } else if ($type == 'file') { + return '/uploads/' . $this->getTable() . '/files/'; + } + } + + /** + * Save an image + * + * @return boolean + */ + public function saveImage($name, $file) + { + // Fail if the user doesn't have permission + if (!$this->userCheck()) { + return 'permission-fail'; + } + + $max_width = 0; + $max_height = 0; + $main_ext = 'jpg'; + + // Retrieve the column + $column = static::getColumn($name); + + // Return an error if no column is found + if ($column == null) { + return 'no-such-column-fail'; + } + + // Update the extension if it's been configured + if (array_key_exists('ext', $column)) { + $main_ext = $column['ext']; + } + + // Create the directory if it doesn't exist + $directory = public_path($this->getUploadsPath('image')); + File::makeDirectory($directory, 0755, true, true); + + // Set the base file path (including the file name but not the extension) + $base_filename = $directory . $this->id . '-' . $name . '.'; + + if ($main_ext == 'svg') { + // Save the image provided it's an SVG + if (gettype($file) == 'string') { + if (!preg_match('/\.svg$/i', $file)) { + return 'incorrect-format-fail'; + } + + copy($file, $base_filename . $main_ext); + } else { + if ($file->extension() != 'svg') { + return 'incorrect-format-fail'; + } + + $file->move($directory, $base_filename . $main_ext); + } + } else { + // Update the maximum width if it's been configured + if (array_key_exists('max_width', $column)) { + $max_width = $column['max_width']; + } + // Update the maximum height if it's been configured + if (array_key_exists('max_height', $column)) { + $max_height = $column['max_height']; + } + + $image = Image::make($file); + + if ($max_width > 0 || $max_height > 0) { + $width = $image->width(); + $height = $image->height(); + $new_width = null; + $new_height = null; + + if ($max_width > 0 && $max_height > 0) { + if ($width > $max_width || $height > $max_height) { + $new_width = $max_width; + $new_height = ($new_width / $width) * $height; + + if ($new_height > $max_height) { + $new_width = ($max_height / $height) * $width; + } + } + } else if ($max_width > 0) { + if ($width > $max_width) { + $new_width = $max_width; + } + } else if ($height > $max_height) { + $new_height = $max_height; + } + + if (!is_null($new_width) || !is_null($new_height)) { + $image->resize($new_width, $new_height, function($constraint) { + $constraint->aspectRatio(); + }); + } + } + + $image->save($base_filename . $main_ext); + $image->save($base_filename . 'webp'); + } + + return 'success'; + } + + /* + * Delete an image + * + * @return string + */ + public function deleteImage($name, $not_exist_fail) + { + // Fail if the user doesn't have permission + if (!$this->userCheck()) { + return 'permission-fail'; + } + + // Set up our variables + $main_ext = 'jpg'; + $extensions = []; + + // Retrieve the column + $column = static::getColumn($name); + + // Return an error if no column is found + if ($column == null) { + return 'no-such-column-fail'; + } + + // Update the extension if it's been configured + if (array_key_exists('ext', $column)) { + $main_ext = $column['ext']; + } + + // Build the set of extensions to delete + array_push($extensions, $main_ext); + + // If the image extension isn't svg also delete the webp + if ($main_ext != 'svg') { + array_push($extensions, 'webp'); + } + + // Delete each image + foreach ($extensions as $ext) { + // Get the full path of the image + $image = public_path($this->getUploadsPath('image') . $this->id . '-' . $name . '.' . $ext); + + // Try to delete the image + if (file_exists($image)) { + if (!unlink($image)) { + return 'image-delete-fail'; + } + } else if ($not_exist_fail) { + return 'image-not-exists-fail'; + } + } + + // Success + return 'success'; + } + + /** + * Save a file + * + * @return boolean + */ + public function saveFile($name, $file) + { + // Fail if the user doesn't have permission + if (!$this->userCheck()) { + return 'permission-fail'; + } + + // Retrieve the column + $column = static::getColumn($name); + + // Return an error if no column is found + if ($column == null) { + return 'no-such-column-fail'; + } + + // Fail if an ext hasn't been declared + if (!array_key_exists('ext', $column)) { + return 'no-configured-extension-fail'; + } + + // Store the extension + $ext = $column['ext']; + + // Create the directory if it doesn't exist + $directory = public_path($this->getUploadsPath('file')); + File::makeDirectory($directory, 0755, true, true); + + // Save the file provided it's the correct extension + if (gettype($file) == 'string') { + if (!preg_match("/\.$ext/i", $file)) { + return 'incorrect-format-fail'; + } + + copy($file, $base_filename . $main_ext); + } else { + if ($file->extension() != $ext) { + return 'incorrect-format-fail'; + } + + $file->move($directory, $this->id . '-' . $name . '.' . $ext); + } + + // Success + return 'success'; + } + + /* + * Delete a file + * + * @return string + */ + public function deleteFile($name, $not_exist_fail) + { + // Fail if the user doesn't have permission + if (!$this->userCheck()) { + return 'permission-fail'; + } + + // Retrieve the column + $column = static::getColumn($name); + + // Return an error if no column is found + if ($column == null) { + return 'no-such-column-fail'; + } + + // Fail if an ext hasn't been declared + if (!array_key_exists('ext', $column)) { + return 'no-configured-extension-fail'; + } + + // Store the extension + $ext = $column['ext']; + + // Get the full path of the file + $file = public_path($this->getUploadsPath('file') . $this->id . '-' . $name . '.' . $ext); + + // Try to delete the file + if (file_exists($file)) { + if (!unlink($file)) { + return 'file-delete-fail'; + } + } else if ($not_exist_fail) { + return 'file-not-exists-fail'; + } + + // Success + return 'success'; + } + + /** + * Determine whether a user column exists and whether it matches the current user if it does + * + * @return boolean + */ + public function userCheck() + { + $user_check = true; + + foreach (static::$dashboard_columns as $column) { + if (array_key_exists('type', $column) && $column['type'] == 'user') { + if ($this->{$column['name']} != Auth::id()) { + $user_check = false; + } + + break; + } + } + + return $user_check; + } + + /** + * Get the file extension for an image + * + * @return string + */ + public static function getColumn($name) + { + foreach (static::$dashboard_columns as $column) { + if ($column['name'] == $name) { + return $column; + } + } + + return null; + } + + /** + * Return an array of column 'headings' or 'names' * * @return array */ @@ -152,7 +457,7 @@ class DashboardModel extends Model } /** - * Performs a search against the columns in $dashboard_display + * Perform a search against the columns in $dashboard_display * * @return array */ @@ -192,7 +497,7 @@ class DashboardModel extends Model } /** - * Returns data for the dashboard + * Return data for the dashboard * * @return array */ @@ -250,7 +555,7 @@ class DashboardModel extends Model } /** - * Retrieves the current query string containing valid query parameters + * Retrieve the current query string containing valid query parameters * * @return string */ @@ -275,25 +580,4 @@ class DashboardModel extends Model return $string; } - - /** - * Determines whether a user column exists and whether it matches the current user if it does - * - * @return boolean - */ - public function userCheck() { - $user_check = true; - - foreach (static::$dashboard_columns as $column) { - if (array_key_exists('type', $column) && $column['type'] == 'user') { - if ($this->{$column['name']} != Auth::id()) { - $user_check = false; - } - - break; - } - } - - return $user_check; - } } diff --git a/gulpfile.js b/gulpfile.js index 15dde46..858ffdc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -265,7 +265,7 @@ gulp.task("watch", () => { }); gulp.watch([ "app/**/*.php", "routes/**/*.php", "resources/views/**/*.blade.php" ], gulp.series(browserSyncReload)); - gulp.watch([ "resources/js/**/app.js", "resources/js/mixins/**/*.js", "resources/components/**/*.vue" ], gulp.series("js-public", browserSyncReload)); + gulp.watch([ "resources/js/**/app.js", "resources/js/mixins/**/*.js", "resources/js/imports/**/*.js", "resources/components/**/*.vue" ], gulp.series("js-public", browserSyncReload)); gulp.watch("resources/js/**/dashboard.js", gulp.series("js-dashboard", browserSyncReload)); gulp.watch("resources/sass/**/*.scss", gulp.parallel("sass-public", "sass-dashboard", "sass-error")); }); diff --git a/readme.md b/readme.md index 53e5fe2..0f6f66b 100644 --- a/readme.md +++ b/readme.md @@ -218,7 +218,9 @@ Models with their `$dashboard_type` set to `edit` also use: * `options` (required by `select`) Takes an array of options that are either strings or arrays containing the keys `title` (for what will display with the option) and `value` (for what will be recorded) * `name`: (required by `file` and `image`) Used along with the record id to determine the filename * `delete`: (optional for `file` and `image`) Enables a delete button for the upload when set to true -* `ext`: (required by `file`) Configures the file extension of the upload +* `ext`: (required by `file` and optional for `image`) Configures the file extension of the upload (`image` defaults to `jpg`) +* `max_width`: (optional for `image`) Configures the maximum width of an image upload (defaults to `0` which sets no maximum width) +* `max_height`: (optional for `image`) Configures the maximum height of an image upload (defaults to `0` which sets no maximum height) An example of the `$dashboard_columns` array in a model with its `$dashboard_type` set to `view`: @@ -238,7 +240,7 @@ An example of the `$dashboard_columns` array in a model with its `$dashboard_typ [ 'name' => 'created_at', 'title' => 'Date', 'type' => 'display' ], [ 'name' => 'title', 'required' => true, 'unique' => true, 'type' => 'string' ], [ 'name' => 'body', 'required' => true, 'type' => 'mkd' ], - [ 'name' => 'header-image', 'title' => 'Header Image', 'type' => 'image', 'delete' => true ], + [ 'name' => 'header-image', 'title' => 'Header Image', 'type' => 'image', 'delete' => true, 'ext' => 'jpg' ], [ 'name' => 'tags', 'type' => 'list', 'model' => 'BlogTags', 'columns' => [ 'name' ], 'foreign' => 'blog_id', 'sort' => 'order' ] ]; ``` diff --git a/resources/components/pages/blog.vue b/resources/components/pages/blog.vue index d1326e7..d681175 100644 --- a/resources/components/pages/blog.vue +++ b/resources/components/pages/blog.vue @@ -12,7 +12,7 @@
+ :style="{ backgroundImage: 'url(' + imageType(entry.headerimage) + ')' }">
diff --git a/resources/js/app.js b/resources/js/app.js index 7212dff..7c5db16 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -15,6 +15,15 @@ Vue.use(Vuex); // CSRF prevention header Vue.http.headers.common["X-CSRF-TOKEN"] = env.csrfToken; +// Import local javascript +import SupportsWebP from "imports/supports-webp.js"; + +// Import global mixins +import ImageType from "mixins/image-type.js"; + +// Register global mixins +Vue.mixin(ImageType); + // Import global components import NavSection from "sections/nav.vue"; import FooterSection from "sections/footer.vue"; @@ -61,7 +70,8 @@ const store = new Vuex.Store({ appLang: env.appLang, appDefaultLang: env.appDefaultLang, firstLoad: true, - lastPath: "" + lastPath: "", + supportsWebP: null }, getters: { @@ -83,6 +93,10 @@ const store = new Vuex.Store({ getLastPath: state => { return state.lastPath; + }, + + getSupportsWebP: state => { + return state.supportsWebP; } }, @@ -98,6 +112,10 @@ const store = new Vuex.Store({ setLastPath(state, value) { state.lastPath = value; + }, + + setSupportsWebP(state, value) { + state.supportsWebP = value; } }, @@ -106,6 +124,9 @@ const store = new Vuex.Store({ } }); +// Detect webp support +SupportsWebP.detect(store); + // Sync vue-router-sync with vuex store sync(store, router); diff --git a/resources/js/dashboard.js b/resources/js/dashboard.js index 7b00d3c..bf85ea9 100644 --- a/resources/js/dashboard.js +++ b/resources/js/dashboard.js @@ -4,6 +4,19 @@ const fadeTime = 250; // declare a reverse function for jquery jQuery.fn.reverse = [].reverse; +// extends an error message with additional text +function getErrorText(message, response) { + let errorText = message; + + switch (response) { + case "incorrect-format-fail": + errorText += ": Incorrect file format"; + break; + } + + return errorText; +} + // show or hide the loading modal function loadingModal(action) { const $loadingModal = $("#loading-modal"); @@ -429,7 +442,6 @@ function editItemInit() { file.append("name", $(fileUpload).attr("name")); file.append("id", row_id); file.append("model", model); - file.append("ext", $(fileUpload).data("ext")); $.ajax({ type: "POST", @@ -444,7 +456,7 @@ function editItemInit() { } else { loadingModal("hide"); - showAlert("Failed to upload file", function() { + showAlert(getErrorText("Failed to upload file", response), function() { submitting = false; }); } @@ -491,7 +503,7 @@ function editItemInit() { } else { loadingModal("hide"); - showAlert("Failed to upload image", function() { + showAlert(getErrorText("Failed to upload image", response), function() { submitting = false; }); } diff --git a/resources/js/imports/supports-webp.js b/resources/js/imports/supports-webp.js new file mode 100644 index 0000000..1b22858 --- /dev/null +++ b/resources/js/imports/supports-webp.js @@ -0,0 +1,48 @@ +export default { + detect: (store) => { + const webpTestImages = { + lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA", + lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==", + alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==" + }; + + const results = { + lossy: null, + lossless: null, + alpha: null + }; + + const getResultsValues = () => { + return Object.keys(results).map((feature) => { + return results[feature]; + }); + }; + + const callback = (feature, result) => { + results[feature] = result; + + if (getResultsValues().indexOf(null) === -1) { + store.commit("setSupportsWebP", getResultsValues().indexOf(false) === -1); + console.log(store.getters.getSupportsWebP); + } + }; + + const checkFeature = (feature) => { + const img = new Image(); + + img.onload = function() { + callback(feature, img.width > 0 && img.height > 0); + }; + + img.onerror = function() { + callback(feature, false); + }; + + img.src = "data:image/webp;base64," + webpTestImages[feature]; + }; + + Object.keys(webpTestImages).forEach((feature) => { + checkFeature(feature); + }); + } +}; diff --git a/resources/js/mixins/image-type.js b/resources/js/mixins/image-type.js new file mode 100644 index 0000000..9ab63a5 --- /dev/null +++ b/resources/js/mixins/image-type.js @@ -0,0 +1,13 @@ +export default { + methods: { + imageType(image) { + if (this.$store.getters.getSupportsWebP === true) { + return image.replace(/\.(png|jpg)/, ".webp"); + } else if (this.$store.getters.getSupportsWebP === false) { + return image; + } else { + return ""; + } + } + } +}; diff --git a/resources/views/dashboard/pages/edit-item.blade.php b/resources/views/dashboard/pages/edit-item.blade.php index 5a5ba12..79224ee 100644 --- a/resources/views/dashboard/pages/edit-item.blade.php +++ b/resources/views/dashboard/pages/edit-item.blade.php @@ -21,6 +21,7 @@
@set('value', $item !== null ? $item[$column['name']] : '') @set('type', $id == 'new' && array_key_exists('type-new', $column) ? $column['type-new'] : $column['type']) + @set('ext', array_key_exists('ext', $column) ? $column['ext'] : 'jpg') @if($type == 'hidden') @@ -28,7 +29,17 @@ @elseif($type != 'display' || $id != 'new')
- +
@@ -100,7 +111,7 @@
@elseif($type == 'image') - @set('current_image', "/uploads/$model/img/$id-" . $column['name'] . '.jpg') + @set('current_image', "/uploads/$model/img/$id-" . $column['name'] . '.' . $ext) @if(file_exists(base_path() . '/public' . $current_image)) @@ -116,14 +127,14 @@ @endif @elseif($type == 'file') @set('current_file', "/uploads/$model/files/$id-" . $column['name'] . '.' . $column['ext']) - + @if(file_exists(base_path() . '/public' . $current_file))
View {{ strtoupper($column['ext']) }} @if(array_key_exists('delete', $column) && $column['delete']) - + Delete {{ strtoupper($column['ext']) }} @endif diff --git a/resources/views/templates/public.blade.php b/resources/views/templates/public.blade.php index e7318f1..b984ece 100644 --- a/resources/views/templates/public.blade.php +++ b/resources/views/templates/public.blade.php @@ -6,11 +6,12 @@