Skip to content

Commit

Permalink
Merge branch 'release/2.14.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
rhukster committed May 11, 2018
2 parents c4e85e8 + fe4092c commit d8a44b0
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 76 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
# v2.14.0
## 05/11/2018

1. [](#new)
* Make `pagemedia` field available outside of pages context
* Added option on fields to disable displaying of label (`display_label: false`)
* Moved Dropzone HTML into an overridable Twig template
* Added support for image upload delete in Dropzone `file` field
1. [](#improved)
* Added support for `optgroup` within select field
* Save forms only once (stops extra work being done)
* Allow file field to pass dropzone options
* Added datasets support to fields
* Added `field.classes` support to display field
1. [](#bugfix)
* Removed overridden class in `password` field
* Worked around forms being lost if form cache expired before page cache, see [#240](https://github.com/getgrav/grav-plugin-form/pull/240)
* Fixed default form in dynamically created page if header uses `forms` instead of old `form` field
* Escape placeholder text in default field

# v2.13.3
## 04/13/2018

Expand Down
87 changes: 32 additions & 55 deletions app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import $ from 'jquery';
import Dropzone from 'dropzone';
import { config, translations } from 'grav-form';

let request = {};

// translations
const Dictionary = {
dictCancelUpload: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD,
Expand All @@ -26,47 +24,7 @@ const DropzoneMediaConfig = {
addRemoveLinks: false,
dictDefaultMessage: Dictionary.dictDefaultMessage,
dictRemoveFileConfirmation: Dictionary.dictRemoveFileConfirmation,
previewTemplate: `
<div class="dz-preview dz-file-preview">
<div class="dz-image"><img data-dz-thumbnail /></div>
<div class="dz-details">
<div class="dz-size"><span data-dz-size></span></div>
<div class="dz-filename"><span data-dz-name></span></div>
</div>
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
<div class="dz-error-message"><span data-dz-errormessage></span></div>
<div class="dz-success-mark">
<svg width="54px" height="54px" viewBox="0 0 54 54" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.1 (9971) - http://www.bohemiancoding.com/sketch -->
<title>Check</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M23.5,31.8431458 L17.5852419,25.9283877 C16.0248253,24.3679711 13.4910294,24.366835 11.9289322,25.9289322 C10.3700136,27.4878508 10.3665912,30.0234455 11.9283877,31.5852419 L20.4147581,40.0716123 C20.5133999,40.1702541 20.6159315,40.2626649 20.7218615,40.3488435 C22.2835669,41.8725651 24.794234,41.8626202 26.3461564,40.3106978 L43.3106978,23.3461564 C44.8771021,21.7797521 44.8758057,19.2483887 43.3137085,17.6862915 C41.7547899,16.1273729 39.2176035,16.1255422 37.6538436,17.6893022 L23.5,31.8431458 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z" id="Oval-2" stroke-opacity="0.198794158" stroke="#747474" fill-opacity="0.816519475" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
</g>
</svg>
</div>
<div class="dz-error-mark">
<svg width="54px" height="54px" viewBox="0 0 54 54" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.1 (9971) - http://www.bohemiancoding.com/sketch -->
<title>error</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="Check-+-Oval-2" sketch:type="MSLayerGroup" stroke="#747474" stroke-opacity="0.198794158" fill="#FFFFFF" fill-opacity="0.816519475">
<path d="M32.6568542,29 L38.3106978,23.3461564 C39.8771021,21.7797521 39.8758057,19.2483887 38.3137085,17.6862915 C36.7547899,16.1273729 34.2176035,16.1255422 32.6538436,17.6893022 L27,23.3431458 L21.3461564,17.6893022 C19.7823965,16.1255422 17.2452101,16.1273729 15.6862915,17.6862915 C14.1241943,19.2483887 14.1228979,21.7797521 15.6893022,23.3461564 L21.3431458,29 L15.6893022,34.6538436 C14.1228979,36.2202479 14.1241943,38.7516113 15.6862915,40.3137085 C17.2452101,41.8726271 19.7823965,41.8744578 21.3461564,40.3106978 L27,34.6568542 L32.6538436,40.3106978 C34.2176035,41.8744578 36.7547899,41.8726271 38.3137085,40.3137085 C39.8758057,38.7516113 39.8771021,36.2202479 38.3106978,34.6538436 L32.6568542,29 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z" id="Oval-2" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>
</div>
</div>`.trim()
previewTemplate: ''
};

export default class FilesField {
Expand All @@ -75,6 +33,7 @@ export default class FilesField {
if (!this.container.length) { return; }

this.urls = {};
DropzoneMediaConfig.previewTemplate = $('#dropzone-template').html();
this.options = Object.assign({}, Dictionary, DropzoneMediaConfig, {
klass: this,
url: this.container.data('file-url-add') || config.current_url,
Expand Down Expand Up @@ -116,12 +75,17 @@ export default class FilesField {
});
}

getURI() {
return this.container.data('mediaUri') || '';
}

onDropzoneSending(file, xhr, formData) {
formData.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val());
formData.append('__form-file-uploader__', 1);
formData.append('name', this.options.dotNotation);
formData.append('form-nonce', config.form_nonce);
formData.append('task', 'filesupload');
formData.append('uri', this.getURI());
}

onDropzoneSuccess(file, response, xhr) {
Expand Down Expand Up @@ -172,23 +136,36 @@ export default class FilesField {

onDropzoneRemovedFile(file, ...extra) {
if (!file.accepted || file.rejected) { return; }
let url = file.removeUrl || this.urls.delete;
let url = file.removeUrl || this.urls.delete || `${location.href}.json`;
let path = (url || '').match(/path:(.*)\//);
let body = { filename: file.name };
let data = new FormData();

data.append('filename', file.name);
data.append('__form-name__', this.container.closest('form').find('[name="__form-name__"]').val());
data.append('name', this.options.dotNotation);
data.append('form-nonce', config.form_nonce);
data.append('uri', this.getURI());

if (file.sessionParams) {
body.task = 'filessessionremove';
body.session = file.sessionParams;
data.append('__form-file-remover__', '1');
data.append('session', file.sessionParams);
}

request(url, { method: 'post', body }, () => {
if (!path) { return; }

path = global.atob(path[1]);
let input = this.container.find('[name][type="hidden"]');
let data = JSON.parse(input.val() || '{}');
delete data[path];
input.val(JSON.stringify(data));
$.ajax({
url,
data,
method: 'POST',
contentType: false,
processData: false,
success: () => {
if (!path) { return; }

path = global.atob(path[1]);
let input = this.container.find('[name][type="hidden"]');
let data = JSON.parse(input.val() || '{}');
delete data[path];
input.val(JSON.stringify(data));
}
});
}

Expand Down
4 changes: 2 additions & 2 deletions assets/form.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion blueprints.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Form
version: 2.13.3
version: 2.14.0
description: Enables the forms handling
icon: check-square
author:
Expand Down
82 changes: 80 additions & 2 deletions classes/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,19 @@ public function __construct(Page $page, $name = null, $form = null)
$this->header_data = isset($header->data) ? $header->data : [];

if ($form) {
// If form is given, use it.
$this->items = $form;
} elseif ($name && isset($header->forms[$name])) {
// If form with that name was found, use that.
$this->items = $header->forms[$name];
} elseif (isset($header->form)) {
$this->items = $header->form; // for backwards compatibility
// For backwards compatibility.
$this->items = $header->form;
} elseif (!empty($header->forms)) {
// Pick up the first form.
$form = reset($header->forms);
$name = key($header->forms);
$this->items = $form;
}

// Add form specific rules.
Expand Down Expand Up @@ -531,14 +541,82 @@ public function uploadFiles()


// json_response
return [
$json_response = [
'status' => 'success',
'session' => \json_encode([
'sessionField' => base64_encode($uri),
'path' => $upload->file->path,
'field' => $settings->name
])
];

// Return JSON
header('Content-Type: application/json');
echo json_encode($json_response);
exit;
}

/**
* Removes a file from the flash object session, before it gets saved
*
* @return bool True if the action was performed.
*/
public function filesSessionRemove()
{
$grav = Grav::instance();
$post = $_POST;
$session = $grav['session'];
// Retrieve the current session of the uploaded files for the field
// and initialize it if it doesn't exist
$sessionField = base64_encode($grav['uri']->url(true));
$request = \json_decode($post['session']);

// Ensure the URI requested matches the current one, otherwise fail
if ($request->sessionField !== $sessionField) {
return false;
}

// Retrieve the flash object and remove the requested file from it
$flash = $session->getFlashObject('files-upload');
$endpoint = $flash[$request->sessionField][$request->field][$request->path];

if (isset($endpoint)) {
if (file_exists($endpoint['tmp_name'])) {
unlink($endpoint['tmp_name']);
}

unset($endpoint);
}

// Walk backward to cleanup any empty field that's left
// Field
if (isset($flash[$request->sessionField][$request->field][$request->path])) {
unset($flash[$request->sessionField][$request->field][$request->path]);
}

// Field
if (isset($flash[$request->sessionField][$request->field]) && empty($flash[$request->sessionField][$request->field])) {
unset($flash[$request->sessionField][$request->field]);
}

// Session Field
if (isset($flash[$request->sessionField]) && empty($flash[$request->sessionField])) {
unset($flash[$request->sessionField]);
}


// If there's anything left to restore in the flash object, do so
if (count($flash)) {
$session->setFlashObject('files-upload', $flash);
}

// json_response
$json_response = ['status' => 'success'];

// Return JSON
header('Content-Type: application/json');
echo json_encode($json_response);
exit;
}

/**
Expand Down
13 changes: 8 additions & 5 deletions form.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,18 +163,18 @@ public function onPageInitialized()
$submitted = false;
$this->json_response = [];

// Save cached forms.
if ($this->recache_forms) {
$this->saveCachedForms();
}

// Force rebuild form when form has not been built and form cache expired.
// This happens when form cache expires before the page cache
// and then does not trigger 'onPageProcessed' event.
if (!$this->forms) {
$this->onPageProcessed(new Event(['page' => $this->grav['page']]));
}

// Save cached forms
if ($this->recache_forms) {
$this->saveCachedForms();
}

// Enable form events if there's a POST
if ($this->shouldProcessForm()) {
$this->enable([
Expand All @@ -187,6 +187,8 @@ public function onPageInitialized()
if ($this->form) {
if (isset($_POST['__form-file-uploader__']) && $this->grav['uri']->extension() === 'json') {
$this->json_response = $this->form->uploadFiles();
} else if ($this->form && isset($_POST['__form-file-remover__']) && $this->grav['uri']->extension() === 'json') {
$this->json_response = $this->form->filesSessionRemove();
} else {
$this->form->post();
$submitted = true;
Expand Down Expand Up @@ -813,6 +815,7 @@ protected function saveCachedForms()
{
// Save the current state of the forms to cache
if ($this->recache_forms) {
$this->recache_forms = false;
$this->grav['cache']->save($this->getFormCacheId(), [$this->forms, $this->flat_forms]);
}
}
Expand Down
13 changes: 9 additions & 4 deletions templates/forms/default/field.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
{% block field %}
<div class="{{ form_field_outer_classes ?: 'form-field' }} {{ field.outerclasses }} {% if errors %} has-errors{% endif %} {% block outer_field_classes %}{% endblock %}">
{% block contents %}
{% if field.label is not same as(false) %}
{% if field.label is not same as(false) and field.display_label is not same as(false) %}
<div class="{{ form_field_outer_label_classes ?: 'form-label' }} {{ field.labelclasses }}">
<label class="{{ form_field_label_classes ?: 'inline' }}" {% if field.id is defined %}for="{{ field.id|e }}" {% endif %} >
{% block label %}
Expand All @@ -27,9 +27,9 @@
{% endif %}
{% else %}
{% if field.markdown %}
{{ field.label|markdown(false)|default(field.name|capitalize)|t }}
{{ field.label|markdown(false)|default(field.name|capitalize)|t|e('html_attr') }}
{% else %}
{{ field.label|default(field.name|capitalize)|t }}
{{ field.label|default(field.name|capitalize)|t|e('html_attr') }}
{% endif %}
{% endif %}

Expand Down Expand Up @@ -59,7 +59,7 @@
{% if field.id is defined %}id="{{ field.id|e }}" {% endif %}
{% if field.style is defined %}style="{{ field.style|e }}" {% endif %}
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
{% if field.placeholder %}placeholder="{{ field.placeholder|t }}"{% endif %}
{% if field.placeholder %}placeholder="{{ field.placeholder|t|e('html_attr') }}"{% endif %}
{% if autofocus %}autofocus="autofocus"{% endif %}
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
{% if field.readonly in ['on', 'true', 1] %}readonly="readonly"{% endif %}
Expand All @@ -73,6 +73,11 @@
{% if field.validate.pattern %}pattern="{{ field.validate.pattern|e }}"{% endif %}
{% if field.validate.message %}title="{{ field.validate.message|t|e }}"
{% elseif field.title is defined %}title="{{ field.title|t|e }}" {% endif %}
{% if field.datasets %}
{% for datakey, datavalue in field.datasets %}
data-{{ datakey }}="{{ datavalue|e('html_attr') }}"
{% endfor %}
{% endif %}
{% endblock %}
/>
{% block append %}{% endblock append %}
Expand Down
6 changes: 6 additions & 0 deletions templates/forms/default/form.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,9 @@
{% include 'forms/fields/uniqueid/uniqueid.html.twig' %}
{{ nonce_field('form', 'form-nonce')|raw }}
</form>

{% if config.forms.dropzone.enabled %}
<div id="dropzone-template" style="display:none;">
{% include 'forms/dropzone/template.html.twig' %}
</div>
{% endif %}
Loading

0 comments on commit d8a44b0

Please sign in to comment.