From cd295a33b30a3e4ff69b892164c9626c1417205f Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 16 Dec 2015 10:18:06 +0100 Subject: [PATCH 1/4] Let forms work with file inputs --- themes/grav/js/forms/form.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/themes/grav/js/forms/form.js b/themes/grav/js/forms/form.js index fed7b67d..c8bdc478 100644 --- a/themes/grav/js/forms/form.js +++ b/themes/grav/js/forms/form.js @@ -289,13 +289,13 @@ values = {}; // Get form values that are not handled by JS framework - Form.findElements(this.form, 'input, textarea', '', false).each(function(input) { + Form.findElements(this.form, 'input:not([type="file"]), textarea', '', false).each(function(input) { var input = $(this), name = input.attr('name'), parent = input.parent('[data-grav-disabled]'), value = input.val(); - if (input.is(':disabled') || (parent && parent.data('grav-disabled') == 'true')) { return; } + if (input.is(':disabled') || (parent && parent.data('grav-disabled') == 'true') || e.attr('type') != 'file') { return; } if (name) { values[name] = value; From 370ca99620bd97595f46d3e70c00bc37eae4a615 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 16 Dec 2015 10:18:36 +0100 Subject: [PATCH 2/4] If a field of the form is file, add enctype attribute with multipart/form-data --- themes/grav/templates/partials/blueprints.html.twig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/themes/grav/templates/partials/blueprints.html.twig b/themes/grav/templates/partials/blueprints.html.twig index f003debf..3a38e363 100644 --- a/themes/grav/templates/partials/blueprints.html.twig +++ b/themes/grav/templates/partials/blueprints.html.twig @@ -1,6 +1,13 @@ {% set form_id = form_id ? form_id : 'blueprints' %} -
+{% set multipart = '' %} +{% for field in blueprints.fields %} + {% if field.type == 'file' %} + {% set multipart = ' enctype="multipart/form-data"' %} + {% endif %} +{% endfor %} + + {% for field in blueprints.fields %} {% if field.type %} {% set value = data.value(field.name) %} From 135df6720e66e025e41a494cd97ee68a94b500df Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 16 Dec 2015 10:20:34 +0100 Subject: [PATCH 3/4] Add files processing to the admin plugin, to be used by the file fileds --- classes/controller.php | 90 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/classes/controller.php b/classes/controller.php index 5e0b8c84..9c64d6c1 100644 --- a/classes/controller.php +++ b/classes/controller.php @@ -963,6 +963,95 @@ class AdminController return true; } + private function cleanFilesData($key, $file) + { + $config = $this->grav['config']; + $blueprint = isset($this->items['fields'][$key]['files']) ? $this->items['fields'][$key]['files'] : []; + + /** @var Page $page */ + $page = null; + $cleanFiles[$key] = []; + if (!isset($blueprint)) { + return false; + } + + $type = trim("{$this->view}/{$this->admin->route}", '/'); + $data = $this->admin->data($type, $this->post); + + $fields = $data->blueprints()->fields(); + $blueprint = isset($fields[$key]) ? $fields[$key] : []; + + + $cleanFiles = [$key => []]; + foreach ((array)$file['error'] as $index => $error) { + if ($error == UPLOAD_ERR_OK) { + $tmp_name = $file['tmp_name'][$index]; + $name = $file['name'][$index]; + $type = $file['type'][$index]; + $destination = Folder::getRelativePath(rtrim($blueprint['destination'], '/')); + + if (!$this->match_in_array($type, $blueprint['accept'])) { + throw new \RuntimeException('File "' . $name . '" is not an accepted MIME type.'); + } + + if (Utils::startsWith($destination, '@page:')) { + $parts = explode(':', $destination); + $route = $parts[1]; + $page = $this->grav['page']->find($route); + + if (!$page) { + throw new \RuntimeException('Unable to upload file to destination. Page route not found.'); + } + + $destination = $page->relativePagePath(); + } else if ($destination == '@self') { + $page = $this->admin->page(true); + $destination = $page->relativePagePath(); + } else { + Folder::mkdir($destination); + } + + if (move_uploaded_file($tmp_name, "$destination/$name")) { + $path = $page ? $this->grav['uri']->convertUrl($page, $page->route() . '/' . $name) : $destination . '/' . $name; + $cleanFiles[$key][$path] = [ + 'name' => $file['name'][$index], + 'type' => $file['type'][$index], + 'size' => $file['size'][$index], + 'file' => $destination . '/' . $name, + 'route' => $page ? $path : null + ]; + } else { + throw new \RuntimeException("Unable to upload file(s) to $destination/$name"); + } + } + } + + return $cleanFiles[$key]; + } + + private function match_in_array($needle, $haystack) + { + foreach ((array)$haystack as $item) { + if (true == preg_match("#^" . strtr(preg_quote($item, '#'), array('\*' => '.*', '\?' => '.')) . "$#i", $needle)) { + return true; + } + } + + return false; + } + + private function processFiles($obj) + { + foreach ((array)$_FILES as $key => $file) { + $cleanFiles = $this->cleanFilesData($key, $file); + if ($cleanFiles) { + $obj->set($key, reset($cleanFiles)['name']); + } + } + + return $obj; + } + /** * Handles form and saves the input data if its valid. * @@ -1020,6 +1109,7 @@ class AdminController } else { // Handle standard data types. $obj = $this->prepareData(); + $obj = $this->processFiles($obj); $obj->validate(); $obj->filter(); } From f03e357dbdb25a6517bf6770b1b769de7acc591b Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Wed, 16 Dec 2015 10:21:05 +0100 Subject: [PATCH 4/4] If admin pro defines a custom_logo_top_left image, show it instead of the default image --- themes/grav/templates/partials/nav.html.twig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/themes/grav/templates/partials/nav.html.twig b/themes/grav/templates/partials/nav.html.twig index e6eab6f5..f2e1b6d4 100644 --- a/themes/grav/templates/partials/nav.html.twig +++ b/themes/grav/templates/partials/nav.html.twig @@ -1,6 +1,10 @@