maj+ header
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# OS Generated
|
||||
.DS_Store*
|
||||
/.idea
|
||||
node_modules
|
||||
*.js.map
|
||||
@@ -1,3 +1,18 @@
|
||||
# v2.16.1
|
||||
## 08/20/2018
|
||||
|
||||
1. [](#new)
|
||||
* Fixed a regression issue with `file` & `array` field
|
||||
|
||||
# v2.16.0
|
||||
## 08/20/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added new `form.keep_alive` option to keep session alive [#275](https://github.com/getgrav/grav-plugin-form/issues/275)
|
||||
* Added `array` field for frontend use
|
||||
1. [](#improved)
|
||||
* Improving compatibility `autocomplete` spec [#274](https://github.com/getgrav/grav-plugin-form/pull/274)
|
||||
|
||||
# v2.15.1
|
||||
## 06/20/2018
|
||||
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
import $ from 'jquery';
|
||||
import Sortable from 'sortablejs';
|
||||
|
||||
let body = $('body');
|
||||
|
||||
class Template {
|
||||
constructor(container) {
|
||||
this.container = $(container);
|
||||
|
||||
if (this.getName() === undefined) {
|
||||
this.container = this.container.closest('[data-grav-array-name]');
|
||||
}
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.container.data('grav-array-name') || '';
|
||||
}
|
||||
|
||||
getKeyPlaceholder() {
|
||||
return this.container.data('grav-array-keyname') || 'Key';
|
||||
}
|
||||
|
||||
getValuePlaceholder() {
|
||||
return this.container.data('grav-array-valuename') || 'Value';
|
||||
}
|
||||
|
||||
isValueOnly() {
|
||||
return this.container.find('[data-grav-array-mode="value_only"]:first').length || false;
|
||||
}
|
||||
|
||||
isTextArea() {
|
||||
return this.container.data('grav-array-textarea') || false;
|
||||
}
|
||||
|
||||
shouldBeDisabled() {
|
||||
// check for toggleables, if field is toggleable and it's not enabled, render disabled
|
||||
let toggle = this.container.closest('.form-field').find('[data-grav-field="toggleable"] input[type="checkbox"]');
|
||||
return toggle.length && toggle.is(':not(:checked)');
|
||||
}
|
||||
|
||||
getNewRow() {
|
||||
let tpl = '';
|
||||
const value = this.isTextArea()
|
||||
? `<textarea ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" name="" placeholder="${this.getValuePlaceholder()}"></textarea>`
|
||||
: `<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" name="" value="" placeholder="${this.getValuePlaceholder()}" />`;
|
||||
|
||||
if (this.isValueOnly()) {
|
||||
tpl += `
|
||||
<div class="form-row array-field-value_only" data-grav-array-type="row">
|
||||
<span data-grav-array-action="sort" class="fa fa-bars"></span>
|
||||
${value}
|
||||
`;
|
||||
} else {
|
||||
tpl += `
|
||||
<div class="form-row" data-grav-array-type="row">
|
||||
<span data-grav-array-action="sort" class="fa fa-bars"></span>
|
||||
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="key" type="text" value="" placeholder="${this.getKeyPlaceholder()}" />
|
||||
${value}
|
||||
`;
|
||||
}
|
||||
|
||||
tpl += `
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>`;
|
||||
|
||||
return tpl;
|
||||
}
|
||||
}
|
||||
|
||||
export default class ArrayField {
|
||||
constructor() {
|
||||
body.on('input', '[data-grav-array-type="key"], [data-grav-array-type="value"]', (event) => this.actionInput(event));
|
||||
body.on('click touch', '[data-grav-array-action]:not([data-grav-array-action="sort"])', (event) => this.actionEvent(event));
|
||||
|
||||
this.arrays = $();
|
||||
|
||||
$('[data-grav-field="array"]').each((index, list) => this.addArray(list));
|
||||
$('body').on('mutation._grav', this._onAddedNodes.bind(this));
|
||||
}
|
||||
|
||||
addArray(list) {
|
||||
list = $(list);
|
||||
|
||||
list.find('[data-grav-array-type="container"]').each((index, container) => {
|
||||
container = $(container);
|
||||
if (container.data('array-sort') || container[0].hasAttribute('data-array-nosort')) { return; }
|
||||
|
||||
container.data('array-sort', new Sortable(container.get(0), {
|
||||
handle: '.fa-bars',
|
||||
animation: 150
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
actionInput(event) {
|
||||
let element = $(event.target);
|
||||
let type = element.data('grav-array-type');
|
||||
|
||||
this._setTemplate(element);
|
||||
|
||||
let template = element.data('array-template');
|
||||
let keyElement = type === 'key' ? element : element.siblings('[data-grav-array-type="key"]:first');
|
||||
let valueElement = type === 'value' ? element : element.siblings('[data-grav-array-type="value"]:first');
|
||||
|
||||
let escaped_name = !template.isValueOnly() ? keyElement.val() : this.getIndexFor(element);
|
||||
escaped_name = escaped_name.toString().replace(/\[/g, '%5B').replace(/]/g, '%5D');
|
||||
let name = `${template.getName()}[${escaped_name}]`;
|
||||
valueElement.attr('name', !valueElement.val() ? template.getName() : name);
|
||||
|
||||
this.refreshNames(template);
|
||||
}
|
||||
|
||||
actionEvent(event) {
|
||||
event && event.preventDefault();
|
||||
let element = $(event.target);
|
||||
let action = element.data('grav-array-action');
|
||||
let container = element.parents('[data-grav-array-type="container"]');
|
||||
|
||||
this._setTemplate(element);
|
||||
|
||||
this[`${action}Action`](element);
|
||||
|
||||
let siblings = container.find('> div');
|
||||
container[siblings.length > 1 ? 'removeClass' : 'addClass']('one-child');
|
||||
}
|
||||
|
||||
addAction(element) {
|
||||
let template = element.data('array-template');
|
||||
let row = element.closest('[data-grav-array-type="row"]');
|
||||
|
||||
row.after(template.getNewRow());
|
||||
}
|
||||
|
||||
remAction(element) {
|
||||
let template = element.data('array-template');
|
||||
let row = element.closest('[data-grav-array-type="row"]');
|
||||
let isLast = !row.siblings().length;
|
||||
|
||||
if (isLast) {
|
||||
let newRow = $(template.getNewRow());
|
||||
row.after(newRow);
|
||||
newRow.find('[data-grav-array-type="value"]:last').attr('name', template.getName());
|
||||
}
|
||||
|
||||
row.remove();
|
||||
this.refreshNames(template);
|
||||
}
|
||||
|
||||
refreshNames(template) {
|
||||
if (!template.isValueOnly()) { return; }
|
||||
|
||||
let row = template.container.find('> div > [data-grav-array-type="row"]');
|
||||
let inputs = row.find('[name]:not([name=""])');
|
||||
|
||||
inputs.each((index, input) => {
|
||||
input = $(input);
|
||||
let name = input.attr('name');
|
||||
name = name.replace(/\[\d+\]$/, `[${index}]`);
|
||||
input.attr('name', name);
|
||||
});
|
||||
|
||||
if (!inputs.length) {
|
||||
row.find('[data-grav-array-type="value"]').attr('name', template.getName());
|
||||
}
|
||||
}
|
||||
|
||||
getIndexFor(element) {
|
||||
let template = element.data('array-template');
|
||||
let row = element.closest('[data-grav-array-type="row"]');
|
||||
|
||||
return template.container.find(`${template.isValueOnly() ? '> div ' : ''} > [data-grav-array-type="row"]`).index(row);
|
||||
}
|
||||
|
||||
_setTemplate(element) {
|
||||
if (!element.data('array-template')) {
|
||||
element.data('array-template', new Template(element.closest('[data-grav-array-name]')));
|
||||
}
|
||||
}
|
||||
|
||||
_onAddedNodes(event, target/* , record, instance */) {
|
||||
let arrays = $(target).find('[data-grav-field="array"]');
|
||||
if (!arrays.length) { return; }
|
||||
|
||||
arrays.each((index, list) => {
|
||||
list = $(list);
|
||||
if (!~this.arrays.index(list)) {
|
||||
this.addArray(list);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new ArrayField();
|
||||
@@ -0,0 +1,297 @@
|
||||
import $ from 'jquery';
|
||||
import Dropzone from 'dropzone';
|
||||
import EXIF from 'exif-js';
|
||||
import { config, translations } from 'grav-form';
|
||||
|
||||
// translations
|
||||
const Dictionary = {
|
||||
dictCancelUpload: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD,
|
||||
dictCancelUploadConfirmation: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION,
|
||||
dictDefaultMessage: translations.PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE,
|
||||
dictFallbackMessage: translations.PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE,
|
||||
dictFallbackText: translations.PLUGIN_FORM.DROPZONE_FALLBACK_TEXT,
|
||||
dictFileTooBig: translations.PLUGIN_FORM.DROPZONE_FILE_TOO_BIG,
|
||||
dictInvalidFileType: translations.PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE,
|
||||
dictMaxFilesExceeded: translations.PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED,
|
||||
dictRemoveFile: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE,
|
||||
dictRemoveFileConfirmation: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION,
|
||||
dictResponseError: translations.PLUGIN_FORM.DROPZONE_RESPONSE_ERROR
|
||||
};
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
const DropzoneMediaConfig = {
|
||||
createImageThumbnails: { thumbnailWidth: 150 },
|
||||
addRemoveLinks: false,
|
||||
dictDefaultMessage: Dictionary.dictDefaultMessage,
|
||||
dictRemoveFileConfirmation: Dictionary.dictRemoveFileConfirmation,
|
||||
previewTemplate: ''
|
||||
};
|
||||
|
||||
window.EXIF = EXIF;
|
||||
|
||||
export default class FilesField {
|
||||
constructor({ container = '.dropzone.files-upload', options = {} } = {}) {
|
||||
this.container = $(container);
|
||||
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,
|
||||
acceptedFiles: this.container.data('media-types'),
|
||||
init: this.initDropzone
|
||||
}, this.container.data('dropzone-options'), options);
|
||||
|
||||
this.dropzone = new Dropzone(container, this.options);
|
||||
this.dropzone.on('complete', this.onDropzoneComplete.bind(this));
|
||||
this.dropzone.on('success', this.onDropzoneSuccess.bind(this));
|
||||
this.dropzone.on('removedfile', this.onDropzoneRemovedFile.bind(this));
|
||||
this.dropzone.on('sending', this.onDropzoneSending.bind(this));
|
||||
this.dropzone.on('error', this.onDropzoneError.bind(this));
|
||||
}
|
||||
|
||||
initDropzone() {
|
||||
let files = this.options.klass.container.find('[data-file]');
|
||||
let dropzone = this;
|
||||
if (!files.length) { return; }
|
||||
|
||||
files.each((index, file) => {
|
||||
file = $(file);
|
||||
let data = file.data('file');
|
||||
let mock = {
|
||||
name: data.name,
|
||||
size: data.size,
|
||||
type: data.type,
|
||||
status: Dropzone.ADDED,
|
||||
accepted: true,
|
||||
url: this.options.url,
|
||||
removeUrl: data.remove
|
||||
};
|
||||
|
||||
dropzone.files.push(mock);
|
||||
dropzone.options.addedfile.call(dropzone, mock);
|
||||
if (mock.type.match(/^image\//)) dropzone.options.thumbnail.call(dropzone, mock, data.path);
|
||||
|
||||
file.remove();
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
if (this.options.reloadPage) {
|
||||
global.location.reload();
|
||||
}
|
||||
|
||||
// store params for removing file from session before it gets saved
|
||||
if (response.session) {
|
||||
file.sessionParams = response.session;
|
||||
file.removeUrl = this.options.url;
|
||||
|
||||
// Touch field value to force a mutation detection
|
||||
const input = this.container.find('[name][type="hidden"]');
|
||||
const value = input.val();
|
||||
input.val(value + ' ');
|
||||
}
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data: response,
|
||||
mode: 'removeFile',
|
||||
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_UPLOAD} <strong>${file.name}</strong></p>
|
||||
<pre>${response.message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
onDropzoneComplete(file) {
|
||||
if (!file.accepted && !file.rejected) {
|
||||
let data = {
|
||||
status: 'error',
|
||||
message: `${translations.PLUGIN_FORM.FILE_UNSUPPORTED}: ${file.name.match(/\..+/).join('')}`
|
||||
};
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data,
|
||||
mode: 'removeFile',
|
||||
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_ADD} <strong>${file.name}</strong></p>
|
||||
<pre>${data.message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
if (this.options.reloadPage) {
|
||||
global.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
onDropzoneRemovedFile(file, ...extra) {
|
||||
if (!file.accepted || file.rejected) { return; }
|
||||
let url = file.removeUrl || this.urls.delete || `${location.href}.json`;
|
||||
let path = (url || '').match(/path:(.*)\//);
|
||||
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) {
|
||||
data.append('__form-file-remover__', '1');
|
||||
data.append('session', file.sessionParams);
|
||||
}
|
||||
|
||||
$.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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onDropzoneError(file, response, xhr) {
|
||||
let message = xhr && response.error ? response.error.message : response;
|
||||
$(file.previewElement).find('[data-dz-errormessage]').html(message);
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data: { status: 'error' },
|
||||
msg: `<pre>${message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
handleError(options) {
|
||||
return true;
|
||||
/* let { file, data, mode, msg } = options;
|
||||
if (data.status !== 'error' && data.status !== 'unauthorized') { return; }
|
||||
|
||||
switch (mode) {
|
||||
case 'addBack':
|
||||
if (file instanceof File) {
|
||||
this.dropzone.addFile.call(this.dropzone, file);
|
||||
} else {
|
||||
this.dropzone.files.push(file);
|
||||
this.dropzone.options.addedfile.call(this.dropzone, file);
|
||||
this.dropzone.options.thumbnail.call(this.dropzone, file, file.extras.url);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'removeFile':
|
||||
default:
|
||||
if (~this.dropzone.files.indexOf(file)) {
|
||||
file.rejected = true;
|
||||
this.dropzone.removeFile.call(this.dropzone, file, { silent: true });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
let modal = $('[data-remodal-id="generic"]');
|
||||
modal.find('.error-content').html(msg);
|
||||
$.remodal.lookup[modal.data('remodal')].open(); */
|
||||
}
|
||||
}
|
||||
|
||||
export function UriToMarkdown(uri) {
|
||||
uri = uri.replace(/@3x|@2x|@1x/, '');
|
||||
uri = uri.replace(/\(/g, '%28');
|
||||
uri = uri.replace(/\)/g, '%29');
|
||||
|
||||
return uri.match(/\.(jpe?g|png|gif|svg)$/i) ? `` : `[${decodeURI(uri)}](${uri})`;
|
||||
}
|
||||
|
||||
let instances = [];
|
||||
let cache = $();
|
||||
const onAddedNodes = (event, target/* , record, instance */) => {
|
||||
let files = $(target).find('.dropzone.files-upload');
|
||||
if (!files.length) { return; }
|
||||
|
||||
files.each((index, file) => {
|
||||
file = $(file);
|
||||
if (!~cache.index(file)) {
|
||||
addNode(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const addNode = (container) => {
|
||||
container = $(container);
|
||||
let input = container.find('input[type="file"]');
|
||||
let settings = container.data('grav-file-settings') || {};
|
||||
|
||||
if (settings.accept && ~settings.accept.indexOf('*')) {
|
||||
settings.accept = [''];
|
||||
}
|
||||
|
||||
let options = {
|
||||
url: container.data('file-url-add') || (container.closest('form').attr('action') || config.current_url) + '.json',
|
||||
paramName: settings.paramName || 'file',
|
||||
dotNotation: settings.name || 'file',
|
||||
acceptedFiles: settings.accept ? settings.accept.join(',') : input.attr('accept') || container.data('media-types'),
|
||||
maxFilesize: settings.filesize || 256,
|
||||
maxFiles: settings.limit || null,
|
||||
resizeWidth: settings.resizeWidth || null,
|
||||
resizeHeight: settings.resizeHeight || null,
|
||||
resizeQuality: settings.resizeQuality || null,
|
||||
accept: function(file, done) {
|
||||
const resolution = settings.resolution;
|
||||
if (!resolution) return done();
|
||||
|
||||
setTimeout(() => {
|
||||
let error = '';
|
||||
if (resolution.min) {
|
||||
Object.keys(resolution.min).forEach((attr) => {
|
||||
if (file[attr] < resolution.min[attr]) {
|
||||
error += translations.PLUGIN_FORM.RESOLUTION_MIN.replace(/{{attr}}/g, attr).replace(/{{min}}/g, resolution.min[attr]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!(settings.resizeWidth || settings.resizeHeight)) {
|
||||
if (resolution.max) {
|
||||
Object.keys(resolution.max).forEach((attr) => {
|
||||
if (file[attr] > resolution.max[attr]) {
|
||||
error += translations.PLUGIN_FORM.RESOLUTION_MAX.replace(/{{attr}}/g, attr).replace(/{{max}}/g, resolution.max[attr]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return done(error);
|
||||
}, 50);
|
||||
}
|
||||
};
|
||||
|
||||
cache = cache.add(container);
|
||||
container = container[0];
|
||||
instances.push(new FilesField({ container, options }));
|
||||
};
|
||||
|
||||
export let Instances = (() => {
|
||||
$('.dropzone.files-upload').each((i, container) => addNode(container));
|
||||
$('body').on('mutation._grav', onAddedNodes);
|
||||
|
||||
return instances;
|
||||
})();
|
||||
@@ -0,0 +1,4 @@
|
||||
import FileInstances from './file';
|
||||
import ArrayInstances from './array';
|
||||
|
||||
export default { FileInstances, ArrayInstances };
|
||||
@@ -1,298 +1,4 @@
|
||||
import $ from 'jquery';
|
||||
import Dropzone from 'dropzone';
|
||||
import EXIF from 'exif-js';
|
||||
import { config, translations } from 'grav-form';
|
||||
|
||||
// translations
|
||||
const Dictionary = {
|
||||
dictCancelUpload: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD,
|
||||
dictCancelUploadConfirmation: translations.PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION,
|
||||
dictDefaultMessage: translations.PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE,
|
||||
dictFallbackMessage: translations.PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE,
|
||||
dictFallbackText: translations.PLUGIN_FORM.DROPZONE_FALLBACK_TEXT,
|
||||
dictFileTooBig: translations.PLUGIN_FORM.DROPZONE_FILE_TOO_BIG,
|
||||
dictInvalidFileType: translations.PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE,
|
||||
dictMaxFilesExceeded: translations.PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED,
|
||||
dictRemoveFile: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE,
|
||||
dictRemoveFileConfirmation: translations.PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION,
|
||||
dictResponseError: translations.PLUGIN_FORM.DROPZONE_RESPONSE_ERROR
|
||||
};
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
const DropzoneMediaConfig = {
|
||||
createImageThumbnails: { thumbnailWidth: 150 },
|
||||
addRemoveLinks: false,
|
||||
dictDefaultMessage: Dictionary.dictDefaultMessage,
|
||||
dictRemoveFileConfirmation: Dictionary.dictRemoveFileConfirmation,
|
||||
previewTemplate: ''
|
||||
};
|
||||
|
||||
window.EXIF = EXIF;
|
||||
|
||||
export default class FilesField {
|
||||
constructor({ container = '.dropzone.files-upload', options = {} } = {}) {
|
||||
this.container = $(container);
|
||||
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,
|
||||
acceptedFiles: this.container.data('media-types'),
|
||||
init: this.initDropzone
|
||||
}, this.container.data('dropzone-options'), options);
|
||||
|
||||
this.dropzone = new Dropzone(container, this.options);
|
||||
this.dropzone.on('complete', this.onDropzoneComplete.bind(this));
|
||||
this.dropzone.on('success', this.onDropzoneSuccess.bind(this));
|
||||
this.dropzone.on('removedfile', this.onDropzoneRemovedFile.bind(this));
|
||||
this.dropzone.on('sending', this.onDropzoneSending.bind(this));
|
||||
this.dropzone.on('error', this.onDropzoneError.bind(this));
|
||||
}
|
||||
|
||||
initDropzone() {
|
||||
let files = this.options.klass.container.find('[data-file]');
|
||||
let dropzone = this;
|
||||
if (!files.length) { return; }
|
||||
|
||||
files.each((index, file) => {
|
||||
file = $(file);
|
||||
let data = file.data('file');
|
||||
let mock = {
|
||||
name: data.name,
|
||||
size: data.size,
|
||||
type: data.type,
|
||||
status: Dropzone.ADDED,
|
||||
accepted: true,
|
||||
url: this.options.url,
|
||||
removeUrl: data.remove
|
||||
};
|
||||
|
||||
dropzone.files.push(mock);
|
||||
dropzone.options.addedfile.call(dropzone, mock);
|
||||
if (mock.type.match(/^image\//)) dropzone.options.thumbnail.call(dropzone, mock, data.path);
|
||||
|
||||
file.remove();
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
if (this.options.reloadPage) {
|
||||
global.location.reload();
|
||||
}
|
||||
|
||||
// store params for removing file from session before it gets saved
|
||||
if (response.session) {
|
||||
file.sessionParams = response.session;
|
||||
file.removeUrl = this.options.url;
|
||||
|
||||
// Touch field value to force a mutation detection
|
||||
const input = this.container.find('[name][type="hidden"]');
|
||||
const value = input.val();
|
||||
input.val(value + ' ');
|
||||
}
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data: response,
|
||||
mode: 'removeFile',
|
||||
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_UPLOAD} <strong>${file.name}</strong></p>
|
||||
<pre>${response.message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
onDropzoneComplete(file) {
|
||||
if (!file.accepted && !file.rejected) {
|
||||
let data = {
|
||||
status: 'error',
|
||||
message: `${translations.PLUGIN_FORM.FILE_UNSUPPORTED}: ${file.name.match(/\..+/).join('')}`
|
||||
};
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data,
|
||||
mode: 'removeFile',
|
||||
msg: `<p>${translations.PLUGIN_FORM.FILE_ERROR_ADD} <strong>${file.name}</strong></p>
|
||||
<pre>${data.message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
if (this.options.reloadPage) {
|
||||
global.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
onDropzoneRemovedFile(file, ...extra) {
|
||||
if (!file.accepted || file.rejected) { return; }
|
||||
let url = file.removeUrl || this.urls.delete || `${location.href}.json`;
|
||||
let path = (url || '').match(/path:(.*)\//);
|
||||
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) {
|
||||
data.append('__form-file-remover__', '1');
|
||||
data.append('session', file.sessionParams);
|
||||
}
|
||||
|
||||
$.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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onDropzoneError(file, response, xhr) {
|
||||
let message = xhr && response.error ? response.error.message : response;
|
||||
$(file.previewElement).find('[data-dz-errormessage]').html(message);
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data: { status: 'error' },
|
||||
msg: `<pre>${message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
handleError(options) {
|
||||
return true;
|
||||
/* let { file, data, mode, msg } = options;
|
||||
if (data.status !== 'error' && data.status !== 'unauthorized') { return; }
|
||||
|
||||
switch (mode) {
|
||||
case 'addBack':
|
||||
if (file instanceof File) {
|
||||
this.dropzone.addFile.call(this.dropzone, file);
|
||||
} else {
|
||||
this.dropzone.files.push(file);
|
||||
this.dropzone.options.addedfile.call(this.dropzone, file);
|
||||
this.dropzone.options.thumbnail.call(this.dropzone, file, file.extras.url);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'removeFile':
|
||||
default:
|
||||
if (~this.dropzone.files.indexOf(file)) {
|
||||
file.rejected = true;
|
||||
this.dropzone.removeFile.call(this.dropzone, file, { silent: true });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
let modal = $('[data-remodal-id="generic"]');
|
||||
modal.find('.error-content').html(msg);
|
||||
$.remodal.lookup[modal.data('remodal')].open(); */
|
||||
}
|
||||
}
|
||||
|
||||
export function UriToMarkdown(uri) {
|
||||
uri = uri.replace(/@3x|@2x|@1x/, '');
|
||||
uri = uri.replace(/\(/g, '%28');
|
||||
uri = uri.replace(/\)/g, '%29');
|
||||
|
||||
return uri.match(/\.(jpe?g|png|gif|svg)$/i) ? `` : `[${decodeURI(uri)}](${uri})`;
|
||||
}
|
||||
|
||||
let instances = [];
|
||||
let cache = $();
|
||||
const onAddedNodes = (event, target/* , record, instance */) => {
|
||||
let files = $(target).find('.dropzone.files-upload');
|
||||
if (!files.length) { return; }
|
||||
|
||||
files.each((index, file) => {
|
||||
file = $(file);
|
||||
if (!~cache.index(file)) {
|
||||
addNode(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const addNode = (container) => {
|
||||
container = $(container);
|
||||
let input = container.find('input[type="file"]');
|
||||
let settings = container.data('grav-file-settings') || {};
|
||||
|
||||
if (settings.accept && ~settings.accept.indexOf('*')) {
|
||||
settings.accept = [''];
|
||||
}
|
||||
|
||||
let options = {
|
||||
url: container.data('file-url-add') || (container.closest('form').attr('action') || config.current_url) + '.json',
|
||||
paramName: settings.paramName || 'file',
|
||||
dotNotation: settings.name || 'file',
|
||||
acceptedFiles: settings.accept ? settings.accept.join(',') : input.attr('accept') || container.data('media-types'),
|
||||
maxFilesize: settings.filesize || 256,
|
||||
maxFiles: settings.limit || null,
|
||||
resizeWidth: settings.resizeWidth || null,
|
||||
resizeHeight: settings.resizeHeight || null,
|
||||
resizeQuality: settings.resizeQuality || null,
|
||||
accept: function(file, done) {
|
||||
const resolution = settings.resolution;
|
||||
if (!resolution) return done();
|
||||
|
||||
setTimeout(() => {
|
||||
let error = '';
|
||||
if (resolution.min) {
|
||||
Object.keys(resolution.min).forEach((attr) => {
|
||||
if (file[attr] < resolution.min[attr]) {
|
||||
error += translations.PLUGIN_FORM.RESOLUTION_MIN.replace(/{{attr}}/g, attr).replace(/{{min}}/g, resolution.min[attr]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!(settings.resizeWidth || settings.resizeHeight)) {
|
||||
if (resolution.max) {
|
||||
Object.keys(resolution.max).forEach((attr) => {
|
||||
if (file[attr] > resolution.max[attr]) {
|
||||
error += translations.PLUGIN_FORM.RESOLUTION_MAX.replace(/{{attr}}/g, attr).replace(/{{max}}/g, resolution.max[attr]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return done(error);
|
||||
}, 50);
|
||||
}
|
||||
};
|
||||
|
||||
cache = cache.add(container);
|
||||
container = container[0];
|
||||
instances.push(new FilesField({ container, options }));
|
||||
};
|
||||
|
||||
export let Instances = (() => {
|
||||
$('.dropzone.files-upload').each((i, container) => addNode(container));
|
||||
$('body').on('mutation._grav', onAddedNodes);
|
||||
|
||||
return instances;
|
||||
})();
|
||||
import Instances from './fields';
|
||||
import './utils/keep-alive';
|
||||
|
||||
export { Instances };
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import $ from 'jquery';
|
||||
import { config } from 'grav-form';
|
||||
|
||||
const keepAlive = $('[data-grav-keepalive]');
|
||||
|
||||
if (keepAlive.length) {
|
||||
const timeout = config.session_timeout / 1.5 * 1000;
|
||||
setInterval(() => {
|
||||
$.ajax({
|
||||
url: `${config.base_url_relative}/task${config.param_sep}keep-alive`
|
||||
});
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
Vendored
+1
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Executable → Regular
@@ -1,5 +1,5 @@
|
||||
name: Form
|
||||
version: 2.15.1
|
||||
version: 2.16.1
|
||||
description: Enables the forms handling
|
||||
icon: check-square
|
||||
author:
|
||||
|
||||
@@ -402,7 +402,10 @@ class Form extends Iterator implements \Serializable
|
||||
(array) $settings,
|
||||
['name' => $post['name']]
|
||||
);
|
||||
|
||||
// Allow plugins to adapt settings for a given post name
|
||||
// Useful if schema retrieval is not an option, e.g. dynamically created forms
|
||||
$grav->fireEvent('onFormUploadSettings', new Event(['settings' => &$settings, 'post' => $post]));
|
||||
|
||||
$upload = $this->normalizeFiles($_FILES['data'], $settings->name);
|
||||
|
||||
// Handle errors and breaks without proceeding further
|
||||
@@ -699,6 +702,10 @@ class Form extends Iterator implements \Serializable
|
||||
$queue = $session->getFlashObject('files-upload');
|
||||
$queue = $queue[base64_encode($url)];
|
||||
if (is_array($queue)) {
|
||||
// Allow plugins to implement additional / alternative logic
|
||||
// Add post to event data
|
||||
$grav->fireEvent('onFormStoreUploads', new Event(['queue' => &$queue, 'form' => $this, 'post' => $post]));
|
||||
|
||||
foreach ($queue as $key => $files) {
|
||||
foreach ($files as $destination => $file) {
|
||||
if (!rename($file['tmp_name'], $destination)) {
|
||||
|
||||
@@ -94,6 +94,12 @@ class FormPlugin extends Plugin
|
||||
'onTwigSiteVariables' => ['onTwigVariables', 0],
|
||||
'onFormValidationProcessed' => ['onFormValidationProcessed', 0],
|
||||
]);
|
||||
|
||||
// Mini Keep-Alive Logic
|
||||
$task = $this->grav['uri']->param('task');
|
||||
if ($task && $task === 'keep-alive') {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function onGetPageTemplates(Event $event)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"project":"grav-plugin-form",
|
||||
"platforms":{
|
||||
"grav":{
|
||||
"nodes":{
|
||||
"plugin":[
|
||||
{
|
||||
"source":"/",
|
||||
"destination":"/user/plugins/form"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,32 +5,39 @@
|
||||
"repository": "https://github.com/getgrav/grav-plugin-form",
|
||||
"main": "app/main.js",
|
||||
"scripts": {
|
||||
"watch": "webpack --watch --progress --colors --config webpack.conf.js",
|
||||
"dev": "webpack --progress --colors --config webpack.conf.js",
|
||||
"prod": "NODE_ENV=production webpack -p --config webpack.conf.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"watch": "NODE_ENV=development webpack --watch --progress --colors --mode development --config webpack.conf.js",
|
||||
"dev": "NODE_ENV=development webpack --progress --colors --config webpack.conf.js",
|
||||
"prod": "NODE_ENV=production webpack --mode production --config webpack.conf.js"
|
||||
},
|
||||
"author": "RocketTheme, LLC",
|
||||
"author": "Team Grav",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dropzone": "^5.3.0",
|
||||
"exif-js": "^2.3.0"
|
||||
"exif-js": "^2.3.0",
|
||||
"sortablejs": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.14.0",
|
||||
"babel-loader": "^6.2.5",
|
||||
"babel-polyfill": "^6.13.0",
|
||||
"babel-preset-es2015": "^6.14.0",
|
||||
"eslint": "^3.4.0",
|
||||
"eslint-loader": "^1.5.0",
|
||||
"exports-loader": "^0.6.3",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-sourcemaps": "^1.6.0",
|
||||
"gulp-util": "^3.0.7",
|
||||
"gulp-webpack": "^1.5.0",
|
||||
"immutable": "^3.8.1",
|
||||
"imports-loader": "^0.6.5",
|
||||
"json-loader": "^0.5.4",
|
||||
"webpack": "^1.13.2"
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^8.2.6",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-stage-3": "^6.24.1",
|
||||
"css-loader": "^1.0.0",
|
||||
"eslint": "^5.2.0",
|
||||
"eslint-loader": "^2.1.0",
|
||||
"exports-loader": "^0.7.0",
|
||||
"gulp": "latest",
|
||||
"gulp-autoprefixer": "latest",
|
||||
"gulp-clean-css": "^3.9.4",
|
||||
"gulp-csscomb": "^3.0.8",
|
||||
"gulp-rename": "^1.3.0",
|
||||
"gulp-sass": "^4.0.1",
|
||||
"gulp-sourcemaps": "^2.6.4",
|
||||
"imports-loader": "^0.8.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"style-loader": "^0.21.0",
|
||||
"webpack": "^4.16.2",
|
||||
"webpack-cli": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
{% 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 %}
|
||||
{% if field.autocomplete in ['on', 'off', 'new-password'] %}autocomplete="{{ field.autocomplete }}"{% endif %}
|
||||
{% if field.autocomplete is defined %}autocomplete="{{ field.autocomplete }}"{% endif %}
|
||||
{% if field.autocapitalize in ['off', 'characters', 'words', 'sentences'] %}autocapitalize="{{ field.autocapitalize }}"{% endif %}
|
||||
{% if field.inputmode in ['none', 'text', 'decimal', 'numeric', 'tel', 'search', 'emaiil', 'url'] %}inputmode="{{ field.inputmode }}"{% endif %}
|
||||
{% if field.inputmode in ['none', 'text', 'decimal', 'numeric', 'tel', 'search', 'email', 'url'] %}inputmode="{{ field.inputmode }}"{% endif %}
|
||||
{% if field.spellcheck in ['true', 'false'] %}spellcheck="{{ field.spellcheck }}"{% endif %}
|
||||
|
||||
{% if field.attributes is defined %}
|
||||
|
||||
@@ -22,6 +22,22 @@
|
||||
{% set action = base_url_relative ~ '/' ~ page.slug %}
|
||||
{% endif %}
|
||||
|
||||
{% if form.keep_alive %}
|
||||
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'loading': 'defer', 'group': 'bottom' }) %}
|
||||
{% do assets.addJs('plugin://form/assets/form.min.js', { 'loading': 'defer', 'group': 'bottom' }) %}
|
||||
{% endif %}
|
||||
|
||||
{% do assets.addInlineJs("
|
||||
window.GravForm = window.GravForm || {};
|
||||
window.GravForm.config = {
|
||||
current_url: '" ~ uri.route(true) ~"',
|
||||
base_url_relative: '" ~ base_url_relative ~ "',
|
||||
param_sep: '"~ config.system.param_sep ~ "',
|
||||
form_nonce: '" ~ form.getNonce ~ "',
|
||||
session_timeout: " ~ config.system.session.timeout ~ "
|
||||
};
|
||||
window.GravForm.translations = jQuery.extend({}, window.GravForm.translations || {}, { PLUGIN_FORM: {} });
|
||||
", { 'group': 'bottom' }) %}
|
||||
<form name="{{ form.name }}"
|
||||
action="{{ action | trim('/', 'right') }}"
|
||||
method="{{ method }}"{{ multipart }}
|
||||
@@ -30,14 +46,13 @@
|
||||
class="{{ form_outer_classes }} {{ form.classes }}"
|
||||
{% endblock %}
|
||||
{% if form.novalidate %}novalidate{% endif %}
|
||||
{% if form.keep_alive %}data-grav-keepalive="true"{% endif %}
|
||||
>
|
||||
|
||||
{% block inner_markup_fields_start %}{% endblock %}
|
||||
|
||||
{% set data = data ?? form.data %}
|
||||
{% for field in form.fields %}
|
||||
{% if field.type == 'file' %}
|
||||
{% do assets.addJs('plugin://form/assets/form.min.js') %}
|
||||
{% endif %}
|
||||
{% set value = form.value(field.name) %}
|
||||
{% include "forms/fields/#{field.type}/#{field.type}.html.twig" ignore missing %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
{% extends "forms/field.html.twig" %}
|
||||
|
||||
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'loading': 'defer', 'group': 'bottom' }) %}
|
||||
{% do assets.addJs('plugin://form/assets/form.min.js', { 'loading': 'defer', 'group': 'bottom' }) %}
|
||||
|
||||
{% block global_attributes %}
|
||||
data-grav-array-name="{{ (scope ~ field.name)|fieldName }}"
|
||||
data-grav-array-keyname="{{ field.placeholder_key|e|tu }}"
|
||||
data-grav-array-valuename="{{ field.placeholder_value|e|tu }}"
|
||||
data-grav-array-textarea="{{ field.value_type == 'textarea' }}"
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
{% macro renderer(key, text, field, scope) %}
|
||||
|
||||
{% if text is not iterable %}
|
||||
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}"
|
||||
data-grav-array-type="row">
|
||||
<span data-grav-array-action="sort" class="fa fa-bars"></span>
|
||||
{% if field.value_only != true %}
|
||||
{% if key == '0' and text == '' %}
|
||||
{% set key = '' %}
|
||||
{% endif %}
|
||||
|
||||
<input
|
||||
data-grav-array-type="key"
|
||||
type="text" value="{{ key }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_key|e|tu }}" />
|
||||
{% endif %}
|
||||
|
||||
{% if field.value_type == 'textarea' %}
|
||||
<textarea
|
||||
data-grav-array-type="value"
|
||||
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
|
||||
placeholder="{{ field.placeholder_value|e|tu }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}>{{ text }}</textarea>
|
||||
{% else %}
|
||||
<input
|
||||
data-grav-array-type="value"
|
||||
type="text"
|
||||
name="{{ ((scope ~ field.name)|fieldName) ~ '[' ~ key ~ ']' }}"
|
||||
placeholder="{{ field.placeholder_value|e|tu }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
value={% if text == 'true' %}true{% elseif text == 'false' %}false{% else %}"{{ text|join(', ')|e }}"{% endif %} />
|
||||
{% endif %}
|
||||
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block input %}
|
||||
{% import _self as array_field %}
|
||||
<div class="{{ field.size }}" data-grav-array-type="container"{% if field.value_only %} data-grav-array-mode="value_only"{% endif %}{{ value|length <= 1 ? ' class="one-child"' : '' }}>
|
||||
{% if value|length %}
|
||||
{% for key, text in value -%}
|
||||
{% if text is not iterable %}
|
||||
{{ array_field.renderer(key, text, field, scope) }}
|
||||
{% else %}
|
||||
{# Backward compatibility for nested arrays (metas) which are not supported anymore #}
|
||||
{% for subkey, subtext in text -%}
|
||||
{{ array_field.renderer(key ~ '[' ~ subkey ~ ']', subtext, field, scope) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{%- else -%}
|
||||
{# Empty value, mock the entry field#}
|
||||
<div class="form-row" data-grav-array-type="row">
|
||||
<span data-grav-array-action="sort" class="fa fa-bars"></span>
|
||||
{% if field.value_only != true %}
|
||||
<input
|
||||
data-grav-array-type="key"
|
||||
type="text"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_key|e|tu }}" />
|
||||
{% endif %}
|
||||
{% if field.value_type == 'textarea' %}
|
||||
<textarea
|
||||
data-grav-array-type="value"
|
||||
name="{{ (scope ~ field.name)|fieldName }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_value|e|tu }}"></textarea>
|
||||
{% else %}
|
||||
<input
|
||||
data-grav-array-type="value"
|
||||
type="text"
|
||||
name="{{ (scope ~ field.name)|fieldName }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_value|e|tu }}" />
|
||||
{% endif %}
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -81,32 +81,30 @@
|
||||
</div>
|
||||
|
||||
{% do assets.addJs('jquery', 101) %}
|
||||
{% do assets.addJs('plugin://form/assets/form.min.js', { 'group': 'bottom', 'loading': 'defer' }) %}
|
||||
{% do assets.addCss('plugin://form/assets/dropzone.min.css', { 'group': 'form' }) %}
|
||||
{% do assets.addJs('plugin://form/assets/form.vendor.js', { 'loading': 'defer', 'group': 'bottom' }) %}
|
||||
{% do assets.addJs('plugin://form/assets/form.min.js', { 'loading': 'defer', 'group': 'bottom' }) %}
|
||||
{% do assets.addCss('plugin://form/assets/dropzone.min.css', { 'group': 'form'}) %}
|
||||
{{ assets.css('form')|raw }}
|
||||
{% do assets.addInlineJs("
|
||||
window.GravForm = window.GravForm || {};
|
||||
window.GravForm.config = {
|
||||
current_url: '" ~ uri.route(true) ~"',
|
||||
base_url_relative: '" ~ base_url_relative ~ "',
|
||||
param_sep: '"~ config.system.param_sep ~ "',
|
||||
form_nonce: '" ~ form.getNonce ~ "',
|
||||
};
|
||||
window.GravForm.translations = {};
|
||||
window.GravForm.translations['PLUGIN_FORM'] = {
|
||||
'DROPZONE_CANCEL_UPLOAD': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD'|t|json_encode ~ ",
|
||||
'DROPZONE_CANCEL_UPLOAD_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION'|t|json_encode ~ ",
|
||||
'DROPZONE_DEFAULT_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE'|t|json_encode ~ ",
|
||||
'DROPZONE_FALLBACK_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE'|t|json_encode ~ ",
|
||||
'DROPZONE_FALLBACK_TEXT': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_TEXT'|t|json_encode ~ ",
|
||||
'DROPZONE_FILE_TOO_BIG': " ~ 'PLUGIN_FORM.DROPZONE_FILE_TOO_BIG'|t|json_encode ~ ",
|
||||
'DROPZONE_INVALID_FILE_TYPE': " ~ 'PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE'|t|json_encode ~ ",
|
||||
'DROPZONE_MAX_FILES_EXCEEDED': " ~ 'PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED'|t|json_encode ~ ",
|
||||
'DROPZONE_REMOVE_FILE': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE'|t|json_encode ~ ",
|
||||
'DROPZONE_REMOVE_FILE_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION'|t|json_encode ~ ",
|
||||
'DROPZONE_RESPONSE_ERROR': " ~ 'PLUGIN_FORM.DROPZONE_RESPONSE_ERROR'|t|json_encode ~ ",
|
||||
'RESOLUTION_MIN': " ~ 'PLUGIN_FORM.RESOLUTION_MIN'|t|json_encode ~ ",
|
||||
'RESOLUTION_MAX': " ~ 'PLUGIN_FORM.RESOLUTION_MAX'|t|json_encode ~ "
|
||||
};
|
||||
window.GravForm = jQuery.extend({}, window.GravForm, {
|
||||
translations: {
|
||||
PLUGIN_FORM: {
|
||||
'DROPZONE_CANCEL_UPLOAD': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD'|t|json_encode ~ ",
|
||||
'DROPZONE_CANCEL_UPLOAD_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_CANCEL_UPLOAD_CONFIRMATION'|t|json_encode ~ ",
|
||||
'DROPZONE_DEFAULT_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_DEFAULT_MESSAGE'|t|json_encode ~ ",
|
||||
'DROPZONE_FALLBACK_MESSAGE': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_MESSAGE'|t|json_encode ~ ",
|
||||
'DROPZONE_FALLBACK_TEXT': " ~ 'PLUGIN_FORM.DROPZONE_FALLBACK_TEXT'|t|json_encode ~ ",
|
||||
'DROPZONE_FILE_TOO_BIG': " ~ 'PLUGIN_FORM.DROPZONE_FILE_TOO_BIG'|t|json_encode ~ ",
|
||||
'DROPZONE_INVALID_FILE_TYPE': " ~ 'PLUGIN_FORM.DROPZONE_INVALID_FILE_TYPE'|t|json_encode ~ ",
|
||||
'DROPZONE_MAX_FILES_EXCEEDED': " ~ 'PLUGIN_FORM.DROPZONE_MAX_FILES_EXCEEDED'|t|json_encode ~ ",
|
||||
'DROPZONE_REMOVE_FILE': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE'|t|json_encode ~ ",
|
||||
'DROPZONE_REMOVE_FILE_CONFIRMATION': " ~ 'PLUGIN_FORM.DROPZONE_REMOVE_FILE_CONFIRMATION'|t|json_encode ~ ",
|
||||
'DROPZONE_RESPONSE_ERROR': " ~ 'PLUGIN_FORM.DROPZONE_RESPONSE_ERROR'|t|json_encode ~ ",
|
||||
'RESOLUTION_MIN': " ~ 'PLUGIN_FORM.RESOLUTION_MIN'|t|json_encode ~ ",
|
||||
'RESOLUTION_MAX': " ~ 'PLUGIN_FORM.RESOLUTION_MAX'|t|json_encode ~ "
|
||||
}
|
||||
}
|
||||
});
|
||||
", { 'group': 'bottom' }) %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,23 +1,65 @@
|
||||
var webpack = require('webpack'),
|
||||
path = require('path'),
|
||||
exec = require('child_process').execSync,
|
||||
pwd = exec('pwd').toString();
|
||||
path = require('path'),
|
||||
UglifyJsPlugin = require('uglifyjs-webpack-plugin'),
|
||||
isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './app/main.js'
|
||||
},
|
||||
externals: {
|
||||
jquery: 'jQuery',
|
||||
'grav-form': 'GravForm'
|
||||
},
|
||||
module: {
|
||||
preLoaders: [
|
||||
{ test: /\.json$/, loader: 'json' },
|
||||
{ test: /\.js$/, loader: 'eslint', exclude: /node_modules/ }
|
||||
entry: {
|
||||
site: './app/main.js'
|
||||
},
|
||||
devtool: isProd ? false : 'eval-source-map',
|
||||
target: 'web',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'assets'),
|
||||
filename: 'form.min.js',
|
||||
chunkFilename: 'form.vendor.js'
|
||||
},
|
||||
optimization: {
|
||||
minimize: isProd,
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
drop_console: true
|
||||
},
|
||||
dead_code: true
|
||||
}
|
||||
})
|
||||
],
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: 1,
|
||||
name: 'vendor',
|
||||
enforce: true,
|
||||
chunks: 'all'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
'fetch': 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch'
|
||||
})
|
||||
],
|
||||
loaders: [
|
||||
{ test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015'] } }
|
||||
]
|
||||
}
|
||||
externals: {
|
||||
jquery: 'jQuery',
|
||||
'grav-form': 'GravForm'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{ enforce: 'pre', test: /\.json$/, loader: 'json-loader' },
|
||||
{ enforce: 'pre', test: /\.js$/, loader: 'eslint-loader', exclude: /node_modules/ },
|
||||
{ test: /\.css$/, loader: 'style-loader!css-loader' },
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
query: {
|
||||
presets: ['es2015', 'stage-3']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user