Adds faux uploader method and initial upload styling
This commit is contained in:
parent
cb9349a6cf
commit
2d1c58f725
535
dist/formulate.esm.js
vendored
535
dist/formulate.esm.js
vendored
@ -1,6 +1,6 @@
|
||||
import isUrl from 'is-url';
|
||||
import isPlainObject from 'is-plain-object';
|
||||
import nanoid from 'nanoid';
|
||||
import isPlainObject from 'is-plain-object';
|
||||
|
||||
var library = {
|
||||
// === SINGLE LINE TEXT STYLE INPUTS
|
||||
@ -97,9 +97,129 @@ var library = {
|
||||
select: {
|
||||
classification: 'select',
|
||||
component: 'FormulateInputSelect'
|
||||
},
|
||||
|
||||
// === FILE TYPE
|
||||
|
||||
file: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
},
|
||||
image: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The file upload class holds and represents a file’s upload state durring
|
||||
* the upload flow.
|
||||
*/
|
||||
var FileUpload = function FileUpload (fileList, context, options) {
|
||||
this.fileList = fileList;
|
||||
this.files = [];
|
||||
this.options = options;
|
||||
this.setFileList(fileList);
|
||||
this.context = context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Produce an array of files and alert the callback.
|
||||
* @param {FileList}
|
||||
*/
|
||||
FileUpload.prototype.setFileList = function setFileList (fileList) {
|
||||
for (var i = 0; i < fileList.length; i++) {
|
||||
var file = fileList.item(i);
|
||||
this.files.push({
|
||||
progress: 0,
|
||||
name: file.name || 'file-upload',
|
||||
file: file,
|
||||
uuid: nanoid()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the file has an.
|
||||
*/
|
||||
FileUpload.prototype.hasUploader = function hasUploader () {
|
||||
return !!this.context.uploader
|
||||
};
|
||||
|
||||
FileUpload.prototype.uploaderIsAxios = function uploaderIsAxios () {
|
||||
if (
|
||||
this.hasUploader &&
|
||||
typeof this.hasUploader.request === 'function' &&
|
||||
typeof this.hasUploader.get === 'function' &&
|
||||
typeof this.hasUploader.delete === 'function' &&
|
||||
typeof this.hasUploader.post === 'function'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a new uploader function.
|
||||
*/
|
||||
FileUpload.prototype.getUploader = function getUploader () {
|
||||
var ref;
|
||||
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
if (this.uploaderIsAxios()) {
|
||||
var formData = new FormData();
|
||||
formData.append(this.context.name || 'file', args[0]);
|
||||
return this.uploader.post(this.context.uploadUrl, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: function (progressEvent) {
|
||||
args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total));
|
||||
}
|
||||
})
|
||||
.catch(function (err) { return args[2](err); })
|
||||
}
|
||||
return (ref = this.context).uploader.apply(ref, args)
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform the file upload.
|
||||
*/
|
||||
FileUpload.prototype.upload = function upload () {
|
||||
var this$1 = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!this$1.hasUploader) {
|
||||
return reject(new Error('No uploader has been defined'))
|
||||
}
|
||||
Promise.all(this$1.files.map(function (file) {
|
||||
return this$1.getUploader(
|
||||
file.file,
|
||||
function (progress) { file.progress = progress; },
|
||||
function (error) { return reject(new Error(error)); },
|
||||
this$1.options
|
||||
)
|
||||
}))
|
||||
.then(function (results) { return resolve(results); })
|
||||
.catch(function (err) { throw new Error(err) });
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
FileUpload.prototype.getFileList = function getFileList () {
|
||||
return this.fileList
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
FileUpload.prototype.getFiles = function getFiles () {
|
||||
return this.files
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to map over an object.
|
||||
* @param {Object} obj An object to map over
|
||||
@ -389,19 +509,20 @@ var rules = {
|
||||
/**
|
||||
* Check the maximum value of a particular.
|
||||
*/
|
||||
max: function (value, minimum) {
|
||||
max: function (value, minimum, force) {
|
||||
if ( minimum === void 0 ) minimum = 10;
|
||||
|
||||
return Promise.resolve((function () {
|
||||
minimum = Number(minimum);
|
||||
if (!isNaN(value)) {
|
||||
value = Number(value);
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
if (Array.isArray(value)) {
|
||||
minimum = !isNaN(minimum) ? Number(minimum) : minimum;
|
||||
return value.length <= minimum
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
value = !isNaN(value) ? Number(value) : value;
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string' || (force === 'length')) {
|
||||
value = !isNaN(value) ? value.toString() : value;
|
||||
return value.length <= minimum
|
||||
}
|
||||
return false
|
||||
@ -416,6 +537,12 @@ var rules = {
|
||||
while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ];
|
||||
|
||||
return Promise.resolve((function () {
|
||||
if (files instanceof FileUpload) {
|
||||
if (files.hasUploader()) {
|
||||
return false
|
||||
}
|
||||
files = files.getFiles();
|
||||
}
|
||||
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
|
||||
for (var i in files) {
|
||||
if (!types.includes(files[i].type)) {
|
||||
@ -639,10 +766,14 @@ var en = {
|
||||
var value = ref.value;
|
||||
var args = ref.args;
|
||||
|
||||
if (!isNaN(value)) {
|
||||
return (name + " must be less than " + (args[0]) + ".")
|
||||
if (Array.isArray(value)) {
|
||||
return ("You may only select " + (args[0]) + " " + name + ".")
|
||||
}
|
||||
return (name + " must be less than " + (args[0]) + " characters long.")
|
||||
var force = Array.isArray(args) && args[1] ? args[1] : false;
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return ((sentence(name)) + " must be less than " + (args[0]) + ".")
|
||||
}
|
||||
return ((sentence(name)) + " must be less than " + (args[0]) + " characters long.")
|
||||
},
|
||||
|
||||
/**
|
||||
@ -653,10 +784,14 @@ var en = {
|
||||
var value = ref.value;
|
||||
var args = ref.args;
|
||||
|
||||
if (!isNaN(value)) {
|
||||
return (name + " must be more than " + (args[0]) + ".")
|
||||
if (Array.isArray(value)) {
|
||||
return ("You must select at least " + (args[0]) + " " + name + ".")
|
||||
}
|
||||
return (name + " must be more than " + (args[0]) + " characters long.")
|
||||
var force = Array.isArray(args) && args[1] ? args[1] : false;
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return ((sentence(name)) + " must be more than " + (args[0]) + ".")
|
||||
}
|
||||
return ((sentence(name)) + " must be more than " + (args[0]) + " characters long.")
|
||||
},
|
||||
|
||||
/**
|
||||
@ -697,6 +832,35 @@ var en = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A fake uploader used by default.
|
||||
*
|
||||
* @param {File} file
|
||||
* @param {function} progress
|
||||
* @param {function} error
|
||||
* @param {object} options
|
||||
*/
|
||||
function fauxUploader (file, progress, error, options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var totalTime = options.fauxUploaderDuration || 2000;
|
||||
var start = performance.now();
|
||||
var advance = function () { return setTimeout(function () {
|
||||
var elapsed = performance.now() - start;
|
||||
var currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100));
|
||||
progress(currentProgress);
|
||||
if (currentProgress >= 100) {
|
||||
resolve({
|
||||
url: 'http://via.placeholder.com/350x150.png',
|
||||
name: file.name
|
||||
});
|
||||
} else {
|
||||
advance();
|
||||
}
|
||||
}, 20); };
|
||||
advance();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* For a single instance of an input, export all of the context needed to fully
|
||||
* render that element.
|
||||
@ -713,7 +877,11 @@ var context = {
|
||||
label: this.label,
|
||||
labelPosition: this.logicalLabelPosition,
|
||||
attributes: this.elementAttributes,
|
||||
blurHandler: blurHandler.bind(this)},
|
||||
blurHandler: blurHandler.bind(this),
|
||||
showImage: this.showImage,
|
||||
uploadUrl: this.uploadUrl,
|
||||
uploader: this.uploader || this.$formulate.getUploader(),
|
||||
immediateUpload: this.immediateUpload},
|
||||
this.typeContext))
|
||||
},
|
||||
nameOrFallback: nameOrFallback,
|
||||
@ -1001,6 +1169,22 @@ var script = {
|
||||
showErrors: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showImage: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
uploadUrl: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
uploader: {
|
||||
type: [Function, Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
immediateUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function data () {
|
||||
@ -1989,6 +2173,219 @@ __vue_render__$5._withStripped = true;
|
||||
//
|
||||
|
||||
var script$6 = {
|
||||
name: 'FormulateFiles',
|
||||
props: {
|
||||
files: {
|
||||
type: FileUpload,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileUploads: function fileUploads () {
|
||||
return this.files.files || []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$6 = script$6;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$6 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
return _vm.fileUploads.length
|
||||
? _c(
|
||||
"ul",
|
||||
{ staticClass: "formulate-files" },
|
||||
_vm._l(_vm.fileUploads, function(file) {
|
||||
return _c("li", { key: file.uuid, staticClass: "formulate-file" }, [
|
||||
_c("span", {
|
||||
staticClass: "formualte-file-name",
|
||||
domProps: { textContent: _vm._s(file.name) }
|
||||
}),
|
||||
_vm._v(" "),
|
||||
file.progress > 0 && file.progress < 100
|
||||
? _c("span", {
|
||||
domProps: { textContent: _vm._s(file.progress + "%") }
|
||||
})
|
||||
: _vm._e()
|
||||
])
|
||||
}),
|
||||
0
|
||||
)
|
||||
: _vm._e()
|
||||
};
|
||||
var __vue_staticRenderFns__$6 = [];
|
||||
__vue_render__$6._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$6 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$6 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$6 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$6 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
|
||||
/* style inject shadow dom */
|
||||
|
||||
|
||||
|
||||
var FormulateFiles = normalizeComponent(
|
||||
{ render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
|
||||
__vue_inject_styles__$6,
|
||||
__vue_script__$6,
|
||||
__vue_scope_id__$6,
|
||||
__vue_is_functional_template__$6,
|
||||
__vue_module_identifier__$6,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
var script$7 = {
|
||||
name: 'FormulateInputFile',
|
||||
components: {
|
||||
FormulateFiles: FormulateFiles
|
||||
},
|
||||
mixins: [FormulateInputMixin],
|
||||
data: function data () {
|
||||
return {
|
||||
isOver: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasFiles: function hasFiles () {
|
||||
return (this.context.model instanceof FileUpload && this.context.model.files.length)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFile: function handleFile () {
|
||||
var input = this.$refs.file;
|
||||
if (input.files.length) {
|
||||
this.context.model = this.$formulate.createUpload(input.files, this.context);
|
||||
}
|
||||
if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
|
||||
this.context.model.upload();
|
||||
}
|
||||
},
|
||||
handleDragOver: function handleDragOver (e) {
|
||||
e.preventDefault();
|
||||
this.isOver = true;
|
||||
},
|
||||
handleDragLeave: function handleDragLeave (e) {
|
||||
e.preventDefault();
|
||||
this.isOver = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$7 = script$7;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$7 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
return _c(
|
||||
"div",
|
||||
{
|
||||
class:
|
||||
"formulate-input-element formulate-input-element--" + _vm.context.type,
|
||||
attrs: { "data-type": _vm.context.type, "data-has-files": _vm.hasFiles }
|
||||
},
|
||||
[
|
||||
_c(
|
||||
"div",
|
||||
{
|
||||
staticClass: "formulate-input-upload-area",
|
||||
attrs: { "data-has-files": _vm.hasFiles }
|
||||
},
|
||||
[
|
||||
_c(
|
||||
"input",
|
||||
_vm._b(
|
||||
{
|
||||
ref: "file",
|
||||
attrs: { "data-is-drag-hover": _vm.isOver, type: "file" },
|
||||
on: {
|
||||
blur: _vm.context.blurHandler,
|
||||
change: _vm.handleFile,
|
||||
dragover: _vm.handleDragOver,
|
||||
dragleave: _vm.handleDragLeave
|
||||
}
|
||||
},
|
||||
"input",
|
||||
_vm.attributes,
|
||||
false
|
||||
)
|
||||
),
|
||||
_vm._v(" "),
|
||||
_c("div", {
|
||||
directives: [
|
||||
{
|
||||
name: "show",
|
||||
rawName: "v-show",
|
||||
value: !_vm.hasFiles,
|
||||
expression: "!hasFiles"
|
||||
}
|
||||
],
|
||||
staticClass: "formulate-input-upload-area-mask"
|
||||
}),
|
||||
_vm._v(" "),
|
||||
_vm.hasFiles
|
||||
? _c("FormulateFiles", { attrs: { files: _vm.context.model } })
|
||||
: _vm._e()
|
||||
],
|
||||
1
|
||||
)
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$7 = [];
|
||||
__vue_render__$7._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$7 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$7 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$7 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$7 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
|
||||
/* style inject shadow dom */
|
||||
|
||||
|
||||
|
||||
var FormulateInputFile = normalizeComponent(
|
||||
{ render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
|
||||
__vue_inject_styles__$7,
|
||||
__vue_script__$7,
|
||||
__vue_scope_id__$7,
|
||||
__vue_is_functional_template__$7,
|
||||
__vue_module_identifier__$7,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
var script$8 = {
|
||||
name: 'FormulateInputSelect',
|
||||
mixins: [FormulateInputMixin],
|
||||
computed: {
|
||||
@ -2005,10 +2402,10 @@ var script$6 = {
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$6 = script$6;
|
||||
var __vue_script__$8 = script$8;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$6 = function() {
|
||||
var __vue_render__$8 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2120,17 +2517,17 @@ var __vue_render__$6 = function() {
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$6 = [];
|
||||
__vue_render__$6._withStripped = true;
|
||||
var __vue_staticRenderFns__$8 = [];
|
||||
__vue_render__$8._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$6 = undefined;
|
||||
var __vue_inject_styles__$8 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$6 = undefined;
|
||||
var __vue_scope_id__$8 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$6 = undefined;
|
||||
var __vue_module_identifier__$8 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$6 = false;
|
||||
var __vue_is_functional_template__$8 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2140,12 +2537,12 @@ __vue_render__$6._withStripped = true;
|
||||
|
||||
|
||||
var FormulateInputSelect = normalizeComponent(
|
||||
{ render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
|
||||
__vue_inject_styles__$6,
|
||||
__vue_script__$6,
|
||||
__vue_scope_id__$6,
|
||||
__vue_is_functional_template__$6,
|
||||
__vue_module_identifier__$6,
|
||||
{ render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
|
||||
__vue_inject_styles__$8,
|
||||
__vue_script__$8,
|
||||
__vue_scope_id__$8,
|
||||
__vue_is_functional_template__$8,
|
||||
__vue_module_identifier__$8,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2154,16 +2551,16 @@ __vue_render__$6._withStripped = true;
|
||||
|
||||
//
|
||||
|
||||
var script$7 = {
|
||||
name: 'FormulateInputText',
|
||||
var script$9 = {
|
||||
name: 'FormulateInputSlider',
|
||||
mixins: [FormulateInputMixin]
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$7 = script$7;
|
||||
var __vue_script__$9 = script$9;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$7 = function() {
|
||||
var __vue_render__$9 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2284,17 +2681,17 @@ var __vue_render__$7 = function() {
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$7 = [];
|
||||
__vue_render__$7._withStripped = true;
|
||||
var __vue_staticRenderFns__$9 = [];
|
||||
__vue_render__$9._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$7 = undefined;
|
||||
var __vue_inject_styles__$9 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$7 = undefined;
|
||||
var __vue_scope_id__$9 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$7 = undefined;
|
||||
var __vue_module_identifier__$9 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$7 = false;
|
||||
var __vue_is_functional_template__$9 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2304,12 +2701,12 @@ __vue_render__$7._withStripped = true;
|
||||
|
||||
|
||||
var FormulateInputSlider = normalizeComponent(
|
||||
{ render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
|
||||
__vue_inject_styles__$7,
|
||||
__vue_script__$7,
|
||||
__vue_scope_id__$7,
|
||||
__vue_is_functional_template__$7,
|
||||
__vue_module_identifier__$7,
|
||||
{ render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
|
||||
__vue_inject_styles__$9,
|
||||
__vue_script__$9,
|
||||
__vue_scope_id__$9,
|
||||
__vue_is_functional_template__$9,
|
||||
__vue_module_identifier__$9,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2318,16 +2715,16 @@ __vue_render__$7._withStripped = true;
|
||||
|
||||
//
|
||||
|
||||
var script$8 = {
|
||||
var script$a = {
|
||||
name: 'FormulateInputTextArea',
|
||||
mixins: [FormulateInputMixin]
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$8 = script$8;
|
||||
var __vue_script__$a = script$a;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$8 = function() {
|
||||
var __vue_render__$a = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2369,17 +2766,17 @@ var __vue_render__$8 = function() {
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$8 = [];
|
||||
__vue_render__$8._withStripped = true;
|
||||
var __vue_staticRenderFns__$a = [];
|
||||
__vue_render__$a._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$8 = undefined;
|
||||
var __vue_inject_styles__$a = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$8 = undefined;
|
||||
var __vue_scope_id__$a = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$8 = undefined;
|
||||
var __vue_module_identifier__$a = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$8 = false;
|
||||
var __vue_is_functional_template__$a = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2389,12 +2786,12 @@ __vue_render__$8._withStripped = true;
|
||||
|
||||
|
||||
var FormulateInputTextArea = normalizeComponent(
|
||||
{ render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
|
||||
__vue_inject_styles__$8,
|
||||
__vue_script__$8,
|
||||
__vue_scope_id__$8,
|
||||
__vue_is_functional_template__$8,
|
||||
__vue_module_identifier__$8,
|
||||
{ render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
|
||||
__vue_inject_styles__$a,
|
||||
__vue_script__$a,
|
||||
__vue_scope_id__$a,
|
||||
__vue_is_functional_template__$a,
|
||||
__vue_module_identifier__$a,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2412,6 +2809,7 @@ var Formulate = function Formulate () {
|
||||
FormulateInputErrors: FormulateInputErrors,
|
||||
FormulateInputBox: FormulateInputBox,
|
||||
FormulateInputText: FormulateInputText,
|
||||
FormulateInputFile: FormulateInputFile,
|
||||
FormulateInputGroup: FormulateInputGroup,
|
||||
FormulateInputSelect: FormulateInputSelect,
|
||||
FormulateInputSlider: FormulateInputSlider,
|
||||
@ -2420,6 +2818,7 @@ var Formulate = function Formulate () {
|
||||
library: library,
|
||||
rules: rules,
|
||||
locale: 'en',
|
||||
uploader: fauxUploader,
|
||||
locales: {
|
||||
en: en
|
||||
}
|
||||
@ -2508,6 +2907,20 @@ Formulate.prototype.validationMessage = function validationMessage (rule, valida
|
||||
return 'This field does not have a valid value'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the file uploader.
|
||||
*/
|
||||
Formulate.prototype.getUploader = function getUploader () {
|
||||
return this.options.uploader || false
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new instance of an upload.
|
||||
*/
|
||||
Formulate.prototype.createUpload = function createUpload (fileList, context) {
|
||||
return new FileUpload(fileList, context, this.options)
|
||||
};
|
||||
|
||||
var Formulate$1 = new Formulate();
|
||||
|
||||
export default Formulate$1;
|
||||
|
539
dist/formulate.min.js
vendored
539
dist/formulate.min.js
vendored
@ -1,9 +1,9 @@
|
||||
var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
var Formulate = (function (exports, isUrl, nanoid, isPlainObject) {
|
||||
'use strict';
|
||||
|
||||
isUrl = isUrl && isUrl.hasOwnProperty('default') ? isUrl['default'] : isUrl;
|
||||
isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
|
||||
nanoid = nanoid && nanoid.hasOwnProperty('default') ? nanoid['default'] : nanoid;
|
||||
isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
|
||||
|
||||
var library = {
|
||||
// === SINGLE LINE TEXT STYLE INPUTS
|
||||
@ -100,9 +100,129 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
select: {
|
||||
classification: 'select',
|
||||
component: 'FormulateInputSelect'
|
||||
},
|
||||
|
||||
// === FILE TYPE
|
||||
|
||||
file: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
},
|
||||
image: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The file upload class holds and represents a file’s upload state durring
|
||||
* the upload flow.
|
||||
*/
|
||||
var FileUpload = function FileUpload (fileList, context, options) {
|
||||
this.fileList = fileList;
|
||||
this.files = [];
|
||||
this.options = options;
|
||||
this.setFileList(fileList);
|
||||
this.context = context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Produce an array of files and alert the callback.
|
||||
* @param {FileList}
|
||||
*/
|
||||
FileUpload.prototype.setFileList = function setFileList (fileList) {
|
||||
for (var i = 0; i < fileList.length; i++) {
|
||||
var file = fileList.item(i);
|
||||
this.files.push({
|
||||
progress: 0,
|
||||
name: file.name || 'file-upload',
|
||||
file: file,
|
||||
uuid: nanoid()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the file has an.
|
||||
*/
|
||||
FileUpload.prototype.hasUploader = function hasUploader () {
|
||||
return !!this.context.uploader
|
||||
};
|
||||
|
||||
FileUpload.prototype.uploaderIsAxios = function uploaderIsAxios () {
|
||||
if (
|
||||
this.hasUploader &&
|
||||
typeof this.hasUploader.request === 'function' &&
|
||||
typeof this.hasUploader.get === 'function' &&
|
||||
typeof this.hasUploader.delete === 'function' &&
|
||||
typeof this.hasUploader.post === 'function'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a new uploader function.
|
||||
*/
|
||||
FileUpload.prototype.getUploader = function getUploader () {
|
||||
var ref;
|
||||
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
if (this.uploaderIsAxios()) {
|
||||
var formData = new FormData();
|
||||
formData.append(this.context.name || 'file', args[0]);
|
||||
return this.uploader.post(this.context.uploadUrl, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: function (progressEvent) {
|
||||
args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total));
|
||||
}
|
||||
})
|
||||
.catch(function (err) { return args[2](err); })
|
||||
}
|
||||
return (ref = this.context).uploader.apply(ref, args)
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform the file upload.
|
||||
*/
|
||||
FileUpload.prototype.upload = function upload () {
|
||||
var this$1 = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!this$1.hasUploader) {
|
||||
return reject(new Error('No uploader has been defined'))
|
||||
}
|
||||
Promise.all(this$1.files.map(function (file) {
|
||||
return this$1.getUploader(
|
||||
file.file,
|
||||
function (progress) { file.progress = progress; },
|
||||
function (error) { return reject(new Error(error)); },
|
||||
this$1.options
|
||||
)
|
||||
}))
|
||||
.then(function (results) { return resolve(results); })
|
||||
.catch(function (err) { throw new Error(err) });
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
FileUpload.prototype.getFileList = function getFileList () {
|
||||
return this.fileList
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
FileUpload.prototype.getFiles = function getFiles () {
|
||||
return this.files
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to map over an object.
|
||||
* @param {Object} obj An object to map over
|
||||
@ -392,19 +512,20 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
/**
|
||||
* Check the maximum value of a particular.
|
||||
*/
|
||||
max: function (value, minimum) {
|
||||
max: function (value, minimum, force) {
|
||||
if ( minimum === void 0 ) minimum = 10;
|
||||
|
||||
return Promise.resolve((function () {
|
||||
minimum = Number(minimum);
|
||||
if (!isNaN(value)) {
|
||||
value = Number(value);
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
if (Array.isArray(value)) {
|
||||
minimum = !isNaN(minimum) ? Number(minimum) : minimum;
|
||||
return value.length <= minimum
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
value = !isNaN(value) ? Number(value) : value;
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string' || (force === 'length')) {
|
||||
value = !isNaN(value) ? value.toString() : value;
|
||||
return value.length <= minimum
|
||||
}
|
||||
return false
|
||||
@ -419,6 +540,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ];
|
||||
|
||||
return Promise.resolve((function () {
|
||||
if (files instanceof FileUpload) {
|
||||
if (files.hasUploader()) {
|
||||
return false
|
||||
}
|
||||
files = files.getFiles();
|
||||
}
|
||||
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
|
||||
for (var i in files) {
|
||||
if (!types.includes(files[i].type)) {
|
||||
@ -642,10 +769,14 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
var value = ref.value;
|
||||
var args = ref.args;
|
||||
|
||||
if (!isNaN(value)) {
|
||||
return (name + " must be less than " + (args[0]) + ".")
|
||||
if (Array.isArray(value)) {
|
||||
return ("You may only select " + (args[0]) + " " + name + ".")
|
||||
}
|
||||
return (name + " must be less than " + (args[0]) + " characters long.")
|
||||
var force = Array.isArray(args) && args[1] ? args[1] : false;
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return ((sentence(name)) + " must be less than " + (args[0]) + ".")
|
||||
}
|
||||
return ((sentence(name)) + " must be less than " + (args[0]) + " characters long.")
|
||||
},
|
||||
|
||||
/**
|
||||
@ -656,10 +787,14 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
var value = ref.value;
|
||||
var args = ref.args;
|
||||
|
||||
if (!isNaN(value)) {
|
||||
return (name + " must be more than " + (args[0]) + ".")
|
||||
if (Array.isArray(value)) {
|
||||
return ("You must select at least " + (args[0]) + " " + name + ".")
|
||||
}
|
||||
return (name + " must be more than " + (args[0]) + " characters long.")
|
||||
var force = Array.isArray(args) && args[1] ? args[1] : false;
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return ((sentence(name)) + " must be more than " + (args[0]) + ".")
|
||||
}
|
||||
return ((sentence(name)) + " must be more than " + (args[0]) + " characters long.")
|
||||
},
|
||||
|
||||
/**
|
||||
@ -700,6 +835,35 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A fake uploader used by default.
|
||||
*
|
||||
* @param {File} file
|
||||
* @param {function} progress
|
||||
* @param {function} error
|
||||
* @param {object} options
|
||||
*/
|
||||
function fauxUploader (file, progress, error, options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var totalTime = options.fauxUploaderDuration || 2000;
|
||||
var start = performance.now();
|
||||
var advance = function () { return setTimeout(function () {
|
||||
var elapsed = performance.now() - start;
|
||||
var currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100));
|
||||
progress(currentProgress);
|
||||
if (currentProgress >= 100) {
|
||||
resolve({
|
||||
url: 'http://via.placeholder.com/350x150.png',
|
||||
name: file.name
|
||||
});
|
||||
} else {
|
||||
advance();
|
||||
}
|
||||
}, 20); };
|
||||
advance();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* For a single instance of an input, export all of the context needed to fully
|
||||
* render that element.
|
||||
@ -716,7 +880,11 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
label: this.label,
|
||||
labelPosition: this.logicalLabelPosition,
|
||||
attributes: this.elementAttributes,
|
||||
blurHandler: blurHandler.bind(this)},
|
||||
blurHandler: blurHandler.bind(this),
|
||||
showImage: this.showImage,
|
||||
uploadUrl: this.uploadUrl,
|
||||
uploader: this.uploader || this.$formulate.getUploader(),
|
||||
immediateUpload: this.immediateUpload},
|
||||
this.typeContext))
|
||||
},
|
||||
nameOrFallback: nameOrFallback,
|
||||
@ -1004,6 +1172,22 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
showErrors: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showImage: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
uploadUrl: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
uploader: {
|
||||
type: [Function, Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
immediateUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function data () {
|
||||
@ -1992,6 +2176,219 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
//
|
||||
|
||||
var script$6 = {
|
||||
name: 'FormulateFiles',
|
||||
props: {
|
||||
files: {
|
||||
type: FileUpload,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileUploads: function fileUploads () {
|
||||
return this.files.files || []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$6 = script$6;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$6 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
return _vm.fileUploads.length
|
||||
? _c(
|
||||
"ul",
|
||||
{ staticClass: "formulate-files" },
|
||||
_vm._l(_vm.fileUploads, function(file) {
|
||||
return _c("li", { key: file.uuid, staticClass: "formulate-file" }, [
|
||||
_c("span", {
|
||||
staticClass: "formualte-file-name",
|
||||
domProps: { textContent: _vm._s(file.name) }
|
||||
}),
|
||||
_vm._v(" "),
|
||||
file.progress > 0 && file.progress < 100
|
||||
? _c("span", {
|
||||
domProps: { textContent: _vm._s(file.progress + "%") }
|
||||
})
|
||||
: _vm._e()
|
||||
])
|
||||
}),
|
||||
0
|
||||
)
|
||||
: _vm._e()
|
||||
};
|
||||
var __vue_staticRenderFns__$6 = [];
|
||||
__vue_render__$6._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$6 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$6 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$6 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$6 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
|
||||
/* style inject shadow dom */
|
||||
|
||||
|
||||
|
||||
var FormulateFiles = normalizeComponent(
|
||||
{ render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
|
||||
__vue_inject_styles__$6,
|
||||
__vue_script__$6,
|
||||
__vue_scope_id__$6,
|
||||
__vue_is_functional_template__$6,
|
||||
__vue_module_identifier__$6,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
var script$7 = {
|
||||
name: 'FormulateInputFile',
|
||||
components: {
|
||||
FormulateFiles: FormulateFiles
|
||||
},
|
||||
mixins: [FormulateInputMixin],
|
||||
data: function data () {
|
||||
return {
|
||||
isOver: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasFiles: function hasFiles () {
|
||||
return (this.context.model instanceof FileUpload && this.context.model.files.length)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFile: function handleFile () {
|
||||
var input = this.$refs.file;
|
||||
if (input.files.length) {
|
||||
this.context.model = this.$formulate.createUpload(input.files, this.context);
|
||||
}
|
||||
if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
|
||||
this.context.model.upload();
|
||||
}
|
||||
},
|
||||
handleDragOver: function handleDragOver (e) {
|
||||
e.preventDefault();
|
||||
this.isOver = true;
|
||||
},
|
||||
handleDragLeave: function handleDragLeave (e) {
|
||||
e.preventDefault();
|
||||
this.isOver = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$7 = script$7;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$7 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
return _c(
|
||||
"div",
|
||||
{
|
||||
class:
|
||||
"formulate-input-element formulate-input-element--" + _vm.context.type,
|
||||
attrs: { "data-type": _vm.context.type, "data-has-files": _vm.hasFiles }
|
||||
},
|
||||
[
|
||||
_c(
|
||||
"div",
|
||||
{
|
||||
staticClass: "formulate-input-upload-area",
|
||||
attrs: { "data-has-files": _vm.hasFiles }
|
||||
},
|
||||
[
|
||||
_c(
|
||||
"input",
|
||||
_vm._b(
|
||||
{
|
||||
ref: "file",
|
||||
attrs: { "data-is-drag-hover": _vm.isOver, type: "file" },
|
||||
on: {
|
||||
blur: _vm.context.blurHandler,
|
||||
change: _vm.handleFile,
|
||||
dragover: _vm.handleDragOver,
|
||||
dragleave: _vm.handleDragLeave
|
||||
}
|
||||
},
|
||||
"input",
|
||||
_vm.attributes,
|
||||
false
|
||||
)
|
||||
),
|
||||
_vm._v(" "),
|
||||
_c("div", {
|
||||
directives: [
|
||||
{
|
||||
name: "show",
|
||||
rawName: "v-show",
|
||||
value: !_vm.hasFiles,
|
||||
expression: "!hasFiles"
|
||||
}
|
||||
],
|
||||
staticClass: "formulate-input-upload-area-mask"
|
||||
}),
|
||||
_vm._v(" "),
|
||||
_vm.hasFiles
|
||||
? _c("FormulateFiles", { attrs: { files: _vm.context.model } })
|
||||
: _vm._e()
|
||||
],
|
||||
1
|
||||
)
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$7 = [];
|
||||
__vue_render__$7._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$7 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$7 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$7 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$7 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
|
||||
/* style inject shadow dom */
|
||||
|
||||
|
||||
|
||||
var FormulateInputFile = normalizeComponent(
|
||||
{ render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
|
||||
__vue_inject_styles__$7,
|
||||
__vue_script__$7,
|
||||
__vue_scope_id__$7,
|
||||
__vue_is_functional_template__$7,
|
||||
__vue_module_identifier__$7,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
var script$8 = {
|
||||
name: 'FormulateInputSelect',
|
||||
mixins: [FormulateInputMixin],
|
||||
computed: {
|
||||
@ -2008,10 +2405,10 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$6 = script$6;
|
||||
var __vue_script__$8 = script$8;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$6 = function() {
|
||||
var __vue_render__$8 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2123,17 +2520,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$6 = [];
|
||||
__vue_render__$6._withStripped = true;
|
||||
var __vue_staticRenderFns__$8 = [];
|
||||
__vue_render__$8._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$6 = undefined;
|
||||
var __vue_inject_styles__$8 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$6 = undefined;
|
||||
var __vue_scope_id__$8 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$6 = undefined;
|
||||
var __vue_module_identifier__$8 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$6 = false;
|
||||
var __vue_is_functional_template__$8 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2143,12 +2540,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
|
||||
|
||||
var FormulateInputSelect = normalizeComponent(
|
||||
{ render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
|
||||
__vue_inject_styles__$6,
|
||||
__vue_script__$6,
|
||||
__vue_scope_id__$6,
|
||||
__vue_is_functional_template__$6,
|
||||
__vue_module_identifier__$6,
|
||||
{ render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
|
||||
__vue_inject_styles__$8,
|
||||
__vue_script__$8,
|
||||
__vue_scope_id__$8,
|
||||
__vue_is_functional_template__$8,
|
||||
__vue_module_identifier__$8,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2157,16 +2554,16 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
|
||||
//
|
||||
|
||||
var script$7 = {
|
||||
name: 'FormulateInputText',
|
||||
var script$9 = {
|
||||
name: 'FormulateInputSlider',
|
||||
mixins: [FormulateInputMixin]
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$7 = script$7;
|
||||
var __vue_script__$9 = script$9;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$7 = function() {
|
||||
var __vue_render__$9 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2287,17 +2684,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$7 = [];
|
||||
__vue_render__$7._withStripped = true;
|
||||
var __vue_staticRenderFns__$9 = [];
|
||||
__vue_render__$9._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$7 = undefined;
|
||||
var __vue_inject_styles__$9 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$7 = undefined;
|
||||
var __vue_scope_id__$9 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$7 = undefined;
|
||||
var __vue_module_identifier__$9 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$7 = false;
|
||||
var __vue_is_functional_template__$9 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2307,12 +2704,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
|
||||
|
||||
var FormulateInputSlider = normalizeComponent(
|
||||
{ render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
|
||||
__vue_inject_styles__$7,
|
||||
__vue_script__$7,
|
||||
__vue_scope_id__$7,
|
||||
__vue_is_functional_template__$7,
|
||||
__vue_module_identifier__$7,
|
||||
{ render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
|
||||
__vue_inject_styles__$9,
|
||||
__vue_script__$9,
|
||||
__vue_scope_id__$9,
|
||||
__vue_is_functional_template__$9,
|
||||
__vue_module_identifier__$9,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2321,16 +2718,16 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
|
||||
//
|
||||
|
||||
var script$8 = {
|
||||
var script$a = {
|
||||
name: 'FormulateInputTextArea',
|
||||
mixins: [FormulateInputMixin]
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$8 = script$8;
|
||||
var __vue_script__$a = script$a;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$8 = function() {
|
||||
var __vue_render__$a = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2372,17 +2769,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$8 = [];
|
||||
__vue_render__$8._withStripped = true;
|
||||
var __vue_staticRenderFns__$a = [];
|
||||
__vue_render__$a._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$8 = undefined;
|
||||
var __vue_inject_styles__$a = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$8 = undefined;
|
||||
var __vue_scope_id__$a = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$8 = undefined;
|
||||
var __vue_module_identifier__$a = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$8 = false;
|
||||
var __vue_is_functional_template__$a = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2392,12 +2789,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
|
||||
|
||||
var FormulateInputTextArea = normalizeComponent(
|
||||
{ render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
|
||||
__vue_inject_styles__$8,
|
||||
__vue_script__$8,
|
||||
__vue_scope_id__$8,
|
||||
__vue_is_functional_template__$8,
|
||||
__vue_module_identifier__$8,
|
||||
{ render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
|
||||
__vue_inject_styles__$a,
|
||||
__vue_script__$a,
|
||||
__vue_scope_id__$a,
|
||||
__vue_is_functional_template__$a,
|
||||
__vue_module_identifier__$a,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2415,6 +2812,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
FormulateInputErrors: FormulateInputErrors,
|
||||
FormulateInputBox: FormulateInputBox,
|
||||
FormulateInputText: FormulateInputText,
|
||||
FormulateInputFile: FormulateInputFile,
|
||||
FormulateInputGroup: FormulateInputGroup,
|
||||
FormulateInputSelect: FormulateInputSelect,
|
||||
FormulateInputSlider: FormulateInputSlider,
|
||||
@ -2423,6 +2821,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
library: library,
|
||||
rules: rules,
|
||||
locale: 'en',
|
||||
uploader: fauxUploader,
|
||||
locales: {
|
||||
en: en
|
||||
}
|
||||
@ -2511,10 +2910,24 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
|
||||
return 'This field does not have a valid value'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the file uploader.
|
||||
*/
|
||||
Formulate.prototype.getUploader = function getUploader () {
|
||||
return this.options.uploader || false
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new instance of an upload.
|
||||
*/
|
||||
Formulate.prototype.createUpload = function createUpload (fileList, context) {
|
||||
return new FileUpload(fileList, context, this.options)
|
||||
};
|
||||
|
||||
var Formulate$1 = new Formulate();
|
||||
|
||||
exports.default = Formulate$1;
|
||||
|
||||
return exports;
|
||||
|
||||
}({}, isUrl, isPlainObject, nanoid));
|
||||
}({}, isUrl, nanoid, isPlainObject));
|
||||
|
543
dist/formulate.umd.js
vendored
543
dist/formulate.umd.js
vendored
@ -1,12 +1,12 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('is-url'), require('is-plain-object'), require('nanoid')) :
|
||||
typeof define === 'function' && define.amd ? define(['exports', 'is-url', 'is-plain-object', 'nanoid'], factory) :
|
||||
(global = global || self, factory(global.Formulate = {}, global.isUrl, global.isPlainObject, global.nanoid));
|
||||
}(this, (function (exports, isUrl, isPlainObject, nanoid) { 'use strict';
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('is-url'), require('nanoid'), require('is-plain-object')) :
|
||||
typeof define === 'function' && define.amd ? define(['exports', 'is-url', 'nanoid', 'is-plain-object'], factory) :
|
||||
(global = global || self, factory(global.Formulate = {}, global.isUrl, global.nanoid, global.isPlainObject));
|
||||
}(this, (function (exports, isUrl, nanoid, isPlainObject) { 'use strict';
|
||||
|
||||
isUrl = isUrl && isUrl.hasOwnProperty('default') ? isUrl['default'] : isUrl;
|
||||
isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
|
||||
nanoid = nanoid && nanoid.hasOwnProperty('default') ? nanoid['default'] : nanoid;
|
||||
isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
|
||||
|
||||
var library = {
|
||||
// === SINGLE LINE TEXT STYLE INPUTS
|
||||
@ -103,9 +103,129 @@
|
||||
select: {
|
||||
classification: 'select',
|
||||
component: 'FormulateInputSelect'
|
||||
},
|
||||
|
||||
// === FILE TYPE
|
||||
|
||||
file: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
},
|
||||
image: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The file upload class holds and represents a file’s upload state durring
|
||||
* the upload flow.
|
||||
*/
|
||||
var FileUpload = function FileUpload (fileList, context, options) {
|
||||
this.fileList = fileList;
|
||||
this.files = [];
|
||||
this.options = options;
|
||||
this.setFileList(fileList);
|
||||
this.context = context;
|
||||
};
|
||||
|
||||
/**
|
||||
* Produce an array of files and alert the callback.
|
||||
* @param {FileList}
|
||||
*/
|
||||
FileUpload.prototype.setFileList = function setFileList (fileList) {
|
||||
for (var i = 0; i < fileList.length; i++) {
|
||||
var file = fileList.item(i);
|
||||
this.files.push({
|
||||
progress: 0,
|
||||
name: file.name || 'file-upload',
|
||||
file: file,
|
||||
uuid: nanoid()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the file has an.
|
||||
*/
|
||||
FileUpload.prototype.hasUploader = function hasUploader () {
|
||||
return !!this.context.uploader
|
||||
};
|
||||
|
||||
FileUpload.prototype.uploaderIsAxios = function uploaderIsAxios () {
|
||||
if (
|
||||
this.hasUploader &&
|
||||
typeof this.hasUploader.request === 'function' &&
|
||||
typeof this.hasUploader.get === 'function' &&
|
||||
typeof this.hasUploader.delete === 'function' &&
|
||||
typeof this.hasUploader.post === 'function'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a new uploader function.
|
||||
*/
|
||||
FileUpload.prototype.getUploader = function getUploader () {
|
||||
var ref;
|
||||
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
if (this.uploaderIsAxios()) {
|
||||
var formData = new FormData();
|
||||
formData.append(this.context.name || 'file', args[0]);
|
||||
return this.uploader.post(this.context.uploadUrl, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: function (progressEvent) {
|
||||
args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total));
|
||||
}
|
||||
})
|
||||
.catch(function (err) { return args[2](err); })
|
||||
}
|
||||
return (ref = this.context).uploader.apply(ref, args)
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform the file upload.
|
||||
*/
|
||||
FileUpload.prototype.upload = function upload () {
|
||||
var this$1 = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!this$1.hasUploader) {
|
||||
return reject(new Error('No uploader has been defined'))
|
||||
}
|
||||
Promise.all(this$1.files.map(function (file) {
|
||||
return this$1.getUploader(
|
||||
file.file,
|
||||
function (progress) { file.progress = progress; },
|
||||
function (error) { return reject(new Error(error)); },
|
||||
this$1.options
|
||||
)
|
||||
}))
|
||||
.then(function (results) { return resolve(results); })
|
||||
.catch(function (err) { throw new Error(err) });
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
FileUpload.prototype.getFileList = function getFileList () {
|
||||
return this.fileList
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
FileUpload.prototype.getFiles = function getFiles () {
|
||||
return this.files
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to map over an object.
|
||||
* @param {Object} obj An object to map over
|
||||
@ -395,19 +515,20 @@
|
||||
/**
|
||||
* Check the maximum value of a particular.
|
||||
*/
|
||||
max: function (value, minimum) {
|
||||
max: function (value, minimum, force) {
|
||||
if ( minimum === void 0 ) minimum = 10;
|
||||
|
||||
return Promise.resolve((function () {
|
||||
minimum = Number(minimum);
|
||||
if (!isNaN(value)) {
|
||||
value = Number(value);
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
if (Array.isArray(value)) {
|
||||
minimum = !isNaN(minimum) ? Number(minimum) : minimum;
|
||||
return value.length <= minimum
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
value = !isNaN(value) ? Number(value) : value;
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string' || (force === 'length')) {
|
||||
value = !isNaN(value) ? value.toString() : value;
|
||||
return value.length <= minimum
|
||||
}
|
||||
return false
|
||||
@ -422,6 +543,12 @@
|
||||
while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ];
|
||||
|
||||
return Promise.resolve((function () {
|
||||
if (files instanceof FileUpload) {
|
||||
if (files.hasUploader()) {
|
||||
return false
|
||||
}
|
||||
files = files.getFiles();
|
||||
}
|
||||
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
|
||||
for (var i in files) {
|
||||
if (!types.includes(files[i].type)) {
|
||||
@ -645,10 +772,14 @@
|
||||
var value = ref.value;
|
||||
var args = ref.args;
|
||||
|
||||
if (!isNaN(value)) {
|
||||
return (name + " must be less than " + (args[0]) + ".")
|
||||
if (Array.isArray(value)) {
|
||||
return ("You may only select " + (args[0]) + " " + name + ".")
|
||||
}
|
||||
return (name + " must be less than " + (args[0]) + " characters long.")
|
||||
var force = Array.isArray(args) && args[1] ? args[1] : false;
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return ((sentence(name)) + " must be less than " + (args[0]) + ".")
|
||||
}
|
||||
return ((sentence(name)) + " must be less than " + (args[0]) + " characters long.")
|
||||
},
|
||||
|
||||
/**
|
||||
@ -659,10 +790,14 @@
|
||||
var value = ref.value;
|
||||
var args = ref.args;
|
||||
|
||||
if (!isNaN(value)) {
|
||||
return (name + " must be more than " + (args[0]) + ".")
|
||||
if (Array.isArray(value)) {
|
||||
return ("You must select at least " + (args[0]) + " " + name + ".")
|
||||
}
|
||||
return (name + " must be more than " + (args[0]) + " characters long.")
|
||||
var force = Array.isArray(args) && args[1] ? args[1] : false;
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return ((sentence(name)) + " must be more than " + (args[0]) + ".")
|
||||
}
|
||||
return ((sentence(name)) + " must be more than " + (args[0]) + " characters long.")
|
||||
},
|
||||
|
||||
/**
|
||||
@ -703,6 +838,35 @@
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A fake uploader used by default.
|
||||
*
|
||||
* @param {File} file
|
||||
* @param {function} progress
|
||||
* @param {function} error
|
||||
* @param {object} options
|
||||
*/
|
||||
function fauxUploader (file, progress, error, options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var totalTime = options.fauxUploaderDuration || 2000;
|
||||
var start = performance.now();
|
||||
var advance = function () { return setTimeout(function () {
|
||||
var elapsed = performance.now() - start;
|
||||
var currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100));
|
||||
progress(currentProgress);
|
||||
if (currentProgress >= 100) {
|
||||
resolve({
|
||||
url: 'http://via.placeholder.com/350x150.png',
|
||||
name: file.name
|
||||
});
|
||||
} else {
|
||||
advance();
|
||||
}
|
||||
}, 20); };
|
||||
advance();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* For a single instance of an input, export all of the context needed to fully
|
||||
* render that element.
|
||||
@ -719,7 +883,11 @@
|
||||
label: this.label,
|
||||
labelPosition: this.logicalLabelPosition,
|
||||
attributes: this.elementAttributes,
|
||||
blurHandler: blurHandler.bind(this)},
|
||||
blurHandler: blurHandler.bind(this),
|
||||
showImage: this.showImage,
|
||||
uploadUrl: this.uploadUrl,
|
||||
uploader: this.uploader || this.$formulate.getUploader(),
|
||||
immediateUpload: this.immediateUpload},
|
||||
this.typeContext))
|
||||
},
|
||||
nameOrFallback: nameOrFallback,
|
||||
@ -1007,6 +1175,22 @@
|
||||
showErrors: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showImage: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
uploadUrl: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
uploader: {
|
||||
type: [Function, Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
immediateUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: function data () {
|
||||
@ -1995,6 +2179,219 @@
|
||||
//
|
||||
|
||||
var script$6 = {
|
||||
name: 'FormulateFiles',
|
||||
props: {
|
||||
files: {
|
||||
type: FileUpload,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileUploads: function fileUploads () {
|
||||
return this.files.files || []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$6 = script$6;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$6 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
return _vm.fileUploads.length
|
||||
? _c(
|
||||
"ul",
|
||||
{ staticClass: "formulate-files" },
|
||||
_vm._l(_vm.fileUploads, function(file) {
|
||||
return _c("li", { key: file.uuid, staticClass: "formulate-file" }, [
|
||||
_c("span", {
|
||||
staticClass: "formualte-file-name",
|
||||
domProps: { textContent: _vm._s(file.name) }
|
||||
}),
|
||||
_vm._v(" "),
|
||||
file.progress > 0 && file.progress < 100
|
||||
? _c("span", {
|
||||
domProps: { textContent: _vm._s(file.progress + "%") }
|
||||
})
|
||||
: _vm._e()
|
||||
])
|
||||
}),
|
||||
0
|
||||
)
|
||||
: _vm._e()
|
||||
};
|
||||
var __vue_staticRenderFns__$6 = [];
|
||||
__vue_render__$6._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$6 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$6 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$6 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$6 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
|
||||
/* style inject shadow dom */
|
||||
|
||||
|
||||
|
||||
var FormulateFiles = normalizeComponent(
|
||||
{ render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
|
||||
__vue_inject_styles__$6,
|
||||
__vue_script__$6,
|
||||
__vue_scope_id__$6,
|
||||
__vue_is_functional_template__$6,
|
||||
__vue_module_identifier__$6,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
var script$7 = {
|
||||
name: 'FormulateInputFile',
|
||||
components: {
|
||||
FormulateFiles: FormulateFiles
|
||||
},
|
||||
mixins: [FormulateInputMixin],
|
||||
data: function data () {
|
||||
return {
|
||||
isOver: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasFiles: function hasFiles () {
|
||||
return (this.context.model instanceof FileUpload && this.context.model.files.length)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFile: function handleFile () {
|
||||
var input = this.$refs.file;
|
||||
if (input.files.length) {
|
||||
this.context.model = this.$formulate.createUpload(input.files, this.context);
|
||||
}
|
||||
if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
|
||||
this.context.model.upload();
|
||||
}
|
||||
},
|
||||
handleDragOver: function handleDragOver (e) {
|
||||
e.preventDefault();
|
||||
this.isOver = true;
|
||||
},
|
||||
handleDragLeave: function handleDragLeave (e) {
|
||||
e.preventDefault();
|
||||
this.isOver = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$7 = script$7;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$7 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
return _c(
|
||||
"div",
|
||||
{
|
||||
class:
|
||||
"formulate-input-element formulate-input-element--" + _vm.context.type,
|
||||
attrs: { "data-type": _vm.context.type, "data-has-files": _vm.hasFiles }
|
||||
},
|
||||
[
|
||||
_c(
|
||||
"div",
|
||||
{
|
||||
staticClass: "formulate-input-upload-area",
|
||||
attrs: { "data-has-files": _vm.hasFiles }
|
||||
},
|
||||
[
|
||||
_c(
|
||||
"input",
|
||||
_vm._b(
|
||||
{
|
||||
ref: "file",
|
||||
attrs: { "data-is-drag-hover": _vm.isOver, type: "file" },
|
||||
on: {
|
||||
blur: _vm.context.blurHandler,
|
||||
change: _vm.handleFile,
|
||||
dragover: _vm.handleDragOver,
|
||||
dragleave: _vm.handleDragLeave
|
||||
}
|
||||
},
|
||||
"input",
|
||||
_vm.attributes,
|
||||
false
|
||||
)
|
||||
),
|
||||
_vm._v(" "),
|
||||
_c("div", {
|
||||
directives: [
|
||||
{
|
||||
name: "show",
|
||||
rawName: "v-show",
|
||||
value: !_vm.hasFiles,
|
||||
expression: "!hasFiles"
|
||||
}
|
||||
],
|
||||
staticClass: "formulate-input-upload-area-mask"
|
||||
}),
|
||||
_vm._v(" "),
|
||||
_vm.hasFiles
|
||||
? _c("FormulateFiles", { attrs: { files: _vm.context.model } })
|
||||
: _vm._e()
|
||||
],
|
||||
1
|
||||
)
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$7 = [];
|
||||
__vue_render__$7._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$7 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$7 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$7 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$7 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
|
||||
/* style inject shadow dom */
|
||||
|
||||
|
||||
|
||||
var FormulateInputFile = normalizeComponent(
|
||||
{ render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
|
||||
__vue_inject_styles__$7,
|
||||
__vue_script__$7,
|
||||
__vue_scope_id__$7,
|
||||
__vue_is_functional_template__$7,
|
||||
__vue_module_identifier__$7,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
var script$8 = {
|
||||
name: 'FormulateInputSelect',
|
||||
mixins: [FormulateInputMixin],
|
||||
computed: {
|
||||
@ -2011,10 +2408,10 @@
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$6 = script$6;
|
||||
var __vue_script__$8 = script$8;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$6 = function() {
|
||||
var __vue_render__$8 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2126,17 +2523,17 @@
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$6 = [];
|
||||
__vue_render__$6._withStripped = true;
|
||||
var __vue_staticRenderFns__$8 = [];
|
||||
__vue_render__$8._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$6 = undefined;
|
||||
var __vue_inject_styles__$8 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$6 = undefined;
|
||||
var __vue_scope_id__$8 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$6 = undefined;
|
||||
var __vue_module_identifier__$8 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$6 = false;
|
||||
var __vue_is_functional_template__$8 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2146,12 +2543,12 @@
|
||||
|
||||
|
||||
var FormulateInputSelect = normalizeComponent(
|
||||
{ render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
|
||||
__vue_inject_styles__$6,
|
||||
__vue_script__$6,
|
||||
__vue_scope_id__$6,
|
||||
__vue_is_functional_template__$6,
|
||||
__vue_module_identifier__$6,
|
||||
{ render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
|
||||
__vue_inject_styles__$8,
|
||||
__vue_script__$8,
|
||||
__vue_scope_id__$8,
|
||||
__vue_is_functional_template__$8,
|
||||
__vue_module_identifier__$8,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2160,16 +2557,16 @@
|
||||
|
||||
//
|
||||
|
||||
var script$7 = {
|
||||
name: 'FormulateInputText',
|
||||
var script$9 = {
|
||||
name: 'FormulateInputSlider',
|
||||
mixins: [FormulateInputMixin]
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$7 = script$7;
|
||||
var __vue_script__$9 = script$9;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$7 = function() {
|
||||
var __vue_render__$9 = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2290,17 +2687,17 @@
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$7 = [];
|
||||
__vue_render__$7._withStripped = true;
|
||||
var __vue_staticRenderFns__$9 = [];
|
||||
__vue_render__$9._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$7 = undefined;
|
||||
var __vue_inject_styles__$9 = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$7 = undefined;
|
||||
var __vue_scope_id__$9 = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$7 = undefined;
|
||||
var __vue_module_identifier__$9 = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$7 = false;
|
||||
var __vue_is_functional_template__$9 = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2310,12 +2707,12 @@
|
||||
|
||||
|
||||
var FormulateInputSlider = normalizeComponent(
|
||||
{ render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
|
||||
__vue_inject_styles__$7,
|
||||
__vue_script__$7,
|
||||
__vue_scope_id__$7,
|
||||
__vue_is_functional_template__$7,
|
||||
__vue_module_identifier__$7,
|
||||
{ render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
|
||||
__vue_inject_styles__$9,
|
||||
__vue_script__$9,
|
||||
__vue_scope_id__$9,
|
||||
__vue_is_functional_template__$9,
|
||||
__vue_module_identifier__$9,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2324,16 +2721,16 @@
|
||||
|
||||
//
|
||||
|
||||
var script$8 = {
|
||||
var script$a = {
|
||||
name: 'FormulateInputTextArea',
|
||||
mixins: [FormulateInputMixin]
|
||||
};
|
||||
|
||||
/* script */
|
||||
var __vue_script__$8 = script$8;
|
||||
var __vue_script__$a = script$a;
|
||||
|
||||
/* template */
|
||||
var __vue_render__$8 = function() {
|
||||
var __vue_render__$a = function() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || _h;
|
||||
@ -2375,17 +2772,17 @@
|
||||
]
|
||||
)
|
||||
};
|
||||
var __vue_staticRenderFns__$8 = [];
|
||||
__vue_render__$8._withStripped = true;
|
||||
var __vue_staticRenderFns__$a = [];
|
||||
__vue_render__$a._withStripped = true;
|
||||
|
||||
/* style */
|
||||
var __vue_inject_styles__$8 = undefined;
|
||||
var __vue_inject_styles__$a = undefined;
|
||||
/* scoped */
|
||||
var __vue_scope_id__$8 = undefined;
|
||||
var __vue_scope_id__$a = undefined;
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__$8 = undefined;
|
||||
var __vue_module_identifier__$a = undefined;
|
||||
/* functional template */
|
||||
var __vue_is_functional_template__$8 = false;
|
||||
var __vue_is_functional_template__$a = false;
|
||||
/* style inject */
|
||||
|
||||
/* style inject SSR */
|
||||
@ -2395,12 +2792,12 @@
|
||||
|
||||
|
||||
var FormulateInputTextArea = normalizeComponent(
|
||||
{ render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
|
||||
__vue_inject_styles__$8,
|
||||
__vue_script__$8,
|
||||
__vue_scope_id__$8,
|
||||
__vue_is_functional_template__$8,
|
||||
__vue_module_identifier__$8,
|
||||
{ render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
|
||||
__vue_inject_styles__$a,
|
||||
__vue_script__$a,
|
||||
__vue_scope_id__$a,
|
||||
__vue_is_functional_template__$a,
|
||||
__vue_module_identifier__$a,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
@ -2418,6 +2815,7 @@
|
||||
FormulateInputErrors: FormulateInputErrors,
|
||||
FormulateInputBox: FormulateInputBox,
|
||||
FormulateInputText: FormulateInputText,
|
||||
FormulateInputFile: FormulateInputFile,
|
||||
FormulateInputGroup: FormulateInputGroup,
|
||||
FormulateInputSelect: FormulateInputSelect,
|
||||
FormulateInputSlider: FormulateInputSlider,
|
||||
@ -2426,6 +2824,7 @@
|
||||
library: library,
|
||||
rules: rules,
|
||||
locale: 'en',
|
||||
uploader: fauxUploader,
|
||||
locales: {
|
||||
en: en
|
||||
}
|
||||
@ -2514,6 +2913,20 @@
|
||||
return 'This field does not have a valid value'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the file uploader.
|
||||
*/
|
||||
Formulate.prototype.getUploader = function getUploader () {
|
||||
return this.options.uploader || false
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new instance of an upload.
|
||||
*/
|
||||
Formulate.prototype.createUpload = function createUpload (fileList, context) {
|
||||
return new FileUpload(fileList, context, this.options)
|
||||
};
|
||||
|
||||
var Formulate$1 = new Formulate();
|
||||
|
||||
exports.default = Formulate$1;
|
||||
|
116
dist/snow.css
vendored
116
dist/snow.css
vendored
@ -40,12 +40,37 @@
|
||||
padding: .75em;
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: 400; }
|
||||
font-weight: 400;
|
||||
line-height: 1.1em;
|
||||
margin: 0; }
|
||||
.formulate-input[data-classification='text'] input::placeholder {
|
||||
color: #a8a8a8; }
|
||||
.formulate-input[data-classification='text'] input:focus {
|
||||
outline: 0;
|
||||
border: 1px solid #41b883; }
|
||||
.formulate-input[data-classification='text'] input[type="color"] {
|
||||
height: 1.1em;
|
||||
box-sizing: content-box; }
|
||||
.formulate-input[data-classification='text'] input[type="color"]::-webkit-color-swatch-wrapper {
|
||||
padding: 0 0 0 1.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 79.17 79.17"><path fill="%236d6d6d" d="M40.8,22.92c-3.4-3.4-4.76-8.44-1-12.24s8.84-2.44,12.24,1c5-5,10.69-13.33,18.81-11.31a11,11,0,0,1,7.62,14.34c-1.26,3.45-4.63,6.06-7.16,8.59-.92.93-3,2.26-3.46,3.46-.42,1,1.82,2.63,2.36,4a8,8,0,0,1-12.42,9.19c-.21-.16-1.35-1.51-1.59-1.51s-.83.83-1,1L49.71,44.9,32.43,62.18c-3.37,3.38-6.6,7.14-10.26,10.21a11,11,0,0,1-4.48,2.28c-1.25.3-3.11-.22-4.18.18-1.28.48-2.42,2.65-3.68,3.4-6.05,3.61-12.64-4-8.46-9.57.73-1,2.53-1.92,3-3a14.46,14.46,0,0,0-.09-2.52,10.75,10.75,0,0,1,3.14-6.77c.92-1,1.93-1.93,2.89-2.9Zm4.4-1.5c4.19,4,8.24,8.24,12.36,12.36,2.06,2.06,5,5.59,8,2.61,4.65-4.62-5-6.8-2.42-10.78C66.3,20.7,76.4,16.48,74.84,9.45,73.62,4,67.12,2.78,63.29,6.32c-2.55,2.36-4.93,4.94-7.39,7.4-.79.78-1.8,2.28-2.88,2.73-2.14.88-3.4-1.62-4.79-2.77-2.58-2.14-6.89-.82-6.53,3C41.89,18.68,43.87,20.09,45.2,21.42Zm-1.45,4.44L27.82,41.79C22,47.57,15.89,53.14,10.41,59.2a8.23,8.23,0,0,0-1.44,2c-.93,2,.25,4.14-.5,6S4.92,69.94,4.3,72a2.34,2.34,0,0,0,2.56,3c1.11-.17,2-1.33,2.71-2.07a11.17,11.17,0,0,1,2.08-2c1.68-.94,4,.17,5.93-.57C20,69.41,22,66.73,23.76,65L34.42,54.3,53.3,35.42Z"/></svg>');
|
||||
background-repeat: no-repeat;
|
||||
background-size: .9em .9em;
|
||||
background-position: left .1em; }
|
||||
.formulate-input[data-classification='text'] input[type="color"]::-webkit-color-swatch {
|
||||
display: block;
|
||||
height: 1em;
|
||||
border-radius: .2em;
|
||||
border: 0;
|
||||
flex: auto; }
|
||||
.formulate-input[data-classification='text'] input[type="color"]::-moz-color-swatch {
|
||||
display: block;
|
||||
height: 1em;
|
||||
border-radius: .2em;
|
||||
border: 0;
|
||||
flex: auto; }
|
||||
.formulate-input[data-classification='slider'] input {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
@ -96,7 +121,9 @@
|
||||
padding: .75em;
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: 400; }
|
||||
font-weight: 400;
|
||||
line-height: 1.1em;
|
||||
margin: 0; }
|
||||
.formulate-input[data-classification='textarea'] textarea::placeholder {
|
||||
color: #a8a8a8; }
|
||||
.formulate-input[data-classification='textarea'] textarea:focus {
|
||||
@ -127,6 +154,8 @@
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: 400;
|
||||
line-height: 1.1em;
|
||||
margin: 0;
|
||||
padding-right: 2em; }
|
||||
.formulate-input[data-classification='select'] select::placeholder {
|
||||
color: #a8a8a8; }
|
||||
@ -174,7 +203,8 @@
|
||||
.formulate-input[data-classification='box'] .formulate-input-element input[type="checkbox"]:checked ~ .formulate-input-element-decorator {
|
||||
border-color: #41b883; }
|
||||
.formulate-input[data-classification='box'] .formulate-input-element input[type="checkbox"]:checked ~ .formulate-input-element-decorator::before {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%2341b883"><path d="M8.76,56.2c-6.38-6.34,3.26-16,9.64-9.69L38,65.88,80.56,23.29c6.38-6.38,16.07,3.32,9.69,9.69L42.84,80.37a6.83,6.83,0,0,1-9.65,0Z"/></svg>'); }
|
||||
background-color: #41b883;
|
||||
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M8.76,56.2c-6.38-6.34,3.26-16,9.64-9.69L38,65.88,80.56,23.29c6.38-6.38,16.07,3.32,9.69,9.69L42.84,80.37a6.83,6.83,0,0,1-9.65,0Z"/></svg>'); }
|
||||
.formulate-input[data-classification='box'] .formulate-input-element input[type="radio"]:checked ~ .formulate-input-element-decorator {
|
||||
border-color: #41b883; }
|
||||
.formulate-input[data-classification='box'] .formulate-input-element input[type="radio"]:checked ~ .formulate-input-element-decorator::before {
|
||||
@ -187,3 +217,83 @@
|
||||
margin-right: .5em; }
|
||||
.formulate-input[data-classification="group"] > .formulate-input-wrapper > .formulate-input-label {
|
||||
margin-bottom: .5em; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding: 2em; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area[data-has-files] {
|
||||
padding: 0; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input {
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 5; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area-mask {
|
||||
border-radius: .4em;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border: 2px dashed #a8a8a8;
|
||||
z-index: 2; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area-mask::before {
|
||||
content: '';
|
||||
background-color: #a8a8a8;
|
||||
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58"><path d="M29,58A29,29,0,1,0,0,29,29,29,0,0,0,29,58ZM29,4A25,25,0,1,1,4,29,25,25,0,0,1,29,4Z"/><polygon points="27 22 27 44.4 31 44.4 31 22 41.7 31.1 44.3 28.1 29 15 13.7 28.1 16.3 31.1 27 22"/></svg>');
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
position: absolute;
|
||||
pointer-events: none; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input:focus ~ .formulate-input-upload-area-mask,
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input:hover ~ .formulate-input-upload-area-mask,
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input[data-is-drag-hover] ~ .formulate-input-upload-area-mask {
|
||||
border-color: #41b883; }
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input:focus ~ .formulate-input-upload-area-mask::before,
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input:hover ~ .formulate-input-upload-area-mask::before,
|
||||
.formulate-input[data-classification="file"] .formulate-input-upload-area input[data-is-drag-hover] ~ .formulate-input-upload-area-mask::before {
|
||||
background-color: #41b883; }
|
||||
.formulate-input[data-classification="file"] .formulate-files {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
.formulate-input[data-classification="file"] .formulate-files li {
|
||||
appearance: none;
|
||||
border-radius: .3em;
|
||||
border: 1px solid #cecece;
|
||||
box-sizing: border-box;
|
||||
background-color: transparent;
|
||||
font-size: .9em;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
padding: .75em;
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: 400;
|
||||
line-height: 1.1em;
|
||||
margin: 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between; }
|
||||
.formulate-input[data-classification="file"] .formulate-files li::placeholder {
|
||||
color: #a8a8a8; }
|
||||
.formulate-input[data-classification="file"] .formulate-files li:focus {
|
||||
outline: 0;
|
||||
border: 1px solid #41b883; }
|
||||
.formulate-input[data-classification="file"] .formulate-files li ::-webkit-progress-bar {
|
||||
appearance: none;
|
||||
height: .5em;
|
||||
border-radius: .5em;
|
||||
overflow: hidden; }
|
||||
|
4
dist/snow.min.css
vendored
4
dist/snow.min.css
vendored
File diff suppressed because one or more lines are too long
113
src/FileUpload.js
Normal file
113
src/FileUpload.js
Normal file
@ -0,0 +1,113 @@
|
||||
import nanoid from 'nanoid'
|
||||
|
||||
/**
|
||||
* The file upload class holds and represents a file’s upload state durring
|
||||
* the upload flow.
|
||||
*/
|
||||
class FileUpload {
|
||||
/**
|
||||
* Create a file upload object.
|
||||
* @param {FileList} fileList
|
||||
* @param {object} context
|
||||
*/
|
||||
constructor (fileList, context, options) {
|
||||
this.fileList = fileList
|
||||
this.files = []
|
||||
this.options = options
|
||||
this.setFileList(fileList)
|
||||
this.context = context
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce an array of files and alert the callback.
|
||||
* @param {FileList}
|
||||
*/
|
||||
setFileList (fileList) {
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const file = fileList.item(i)
|
||||
this.files.push({
|
||||
progress: 0,
|
||||
name: file.name || 'file-upload',
|
||||
file: file,
|
||||
uuid: nanoid()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file has an.
|
||||
*/
|
||||
hasUploader () {
|
||||
return !!this.context.uploader
|
||||
}
|
||||
|
||||
uploaderIsAxios () {
|
||||
if (
|
||||
this.hasUploader &&
|
||||
typeof this.hasUploader.request === 'function' &&
|
||||
typeof this.hasUploader.get === 'function' &&
|
||||
typeof this.hasUploader.delete === 'function' &&
|
||||
typeof this.hasUploader.post === 'function'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new uploader function.
|
||||
*/
|
||||
getUploader (...args) {
|
||||
if (this.uploaderIsAxios()) {
|
||||
const formData = new FormData()
|
||||
formData.append(this.context.name || 'file', args[0])
|
||||
return this.uploader.post(this.context.uploadUrl, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: progressEvent => {
|
||||
args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total))
|
||||
}
|
||||
})
|
||||
.catch(err => args[2](err))
|
||||
}
|
||||
return this.context.uploader(...args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the file upload.
|
||||
*/
|
||||
upload () {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.hasUploader) {
|
||||
return reject(new Error('No uploader has been defined'))
|
||||
}
|
||||
Promise.all(this.files.map(file => {
|
||||
return this.getUploader(
|
||||
file.file,
|
||||
(progress) => { file.progress = progress },
|
||||
(error) => reject(new Error(error)),
|
||||
this.options
|
||||
)
|
||||
}))
|
||||
.then(results => resolve(results))
|
||||
.catch(err => { throw new Error(err) })
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
getFileList () {
|
||||
return this.fileList
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
*/
|
||||
getFiles () {
|
||||
return this.files
|
||||
}
|
||||
}
|
||||
|
||||
export default FileUpload
|
@ -1,13 +1,16 @@
|
||||
import library from './libs/library'
|
||||
import rules from './libs/rules'
|
||||
import en from './locales/en'
|
||||
import FileUpload from './FileUpload'
|
||||
import isPlainObject from 'is-plain-object'
|
||||
import fauxUploader from './libs/faux-uploader'
|
||||
import FormulateInput from './FormulateInput.vue'
|
||||
import FormulateForm from './FormulateForm.vue'
|
||||
import FormulateInputErrors from './FormulateInputErrors.vue'
|
||||
import FormulateInputGroup from './FormulateInputGroup.vue'
|
||||
import FormulateInputBox from './inputs/FormulateInputBox.vue'
|
||||
import FormulateInputText from './inputs/FormulateInputText.vue'
|
||||
import FormulateInputFile from './inputs/FormulateInputFile.vue'
|
||||
import FormulateInputSelect from './inputs/FormulateInputSelect.vue'
|
||||
import FormulateInputSlider from './inputs/FormulateInputSlider.vue'
|
||||
import FormulateInputTextArea from './inputs/FormulateInputTextArea.vue'
|
||||
@ -27,6 +30,7 @@ class Formulate {
|
||||
FormulateInputErrors,
|
||||
FormulateInputBox,
|
||||
FormulateInputText,
|
||||
FormulateInputFile,
|
||||
FormulateInputGroup,
|
||||
FormulateInputSelect,
|
||||
FormulateInputSlider,
|
||||
@ -35,6 +39,7 @@ class Formulate {
|
||||
library,
|
||||
rules,
|
||||
locale: 'en',
|
||||
uploader: fauxUploader,
|
||||
locales: {
|
||||
en
|
||||
}
|
||||
@ -122,6 +127,20 @@ class Formulate {
|
||||
}
|
||||
return 'This field does not have a valid value'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file uploader.
|
||||
*/
|
||||
getUploader () {
|
||||
return this.options.uploader || false
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of an upload.
|
||||
*/
|
||||
createUpload (fileList, context) {
|
||||
return new FileUpload(fileList, context, this.options)
|
||||
}
|
||||
}
|
||||
|
||||
export default new Formulate()
|
||||
|
40
src/FormulateFiles.vue
Normal file
40
src/FormulateFiles.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<ul
|
||||
v-if="fileUploads.length"
|
||||
class="formulate-files"
|
||||
>
|
||||
<li
|
||||
v-for="file in fileUploads"
|
||||
:key="file.uuid"
|
||||
class="formulate-file"
|
||||
>
|
||||
<span
|
||||
class="formualte-file-name"
|
||||
v-text="file.name"
|
||||
/>
|
||||
<span
|
||||
v-if="file.progress > 0 && file.progress < 100"
|
||||
v-text="`${file.progress}%`"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FileUpload from './FileUpload'
|
||||
|
||||
export default {
|
||||
name: 'FormulateFiles',
|
||||
props: {
|
||||
files: {
|
||||
type: FileUpload,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileUploads () {
|
||||
return this.files.files || []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -136,6 +136,22 @@ export default {
|
||||
showErrors: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showImage: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
uploadUrl: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
uploader: {
|
||||
type: [Function, Object, Boolean],
|
||||
default: false
|
||||
},
|
||||
immediateUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
74
src/inputs/FormulateInputFile.vue
Normal file
74
src/inputs/FormulateInputFile.vue
Normal file
@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div
|
||||
:class="`formulate-input-element formulate-input-element--${context.type}`"
|
||||
:data-type="context.type"
|
||||
:data-has-files="hasFiles"
|
||||
>
|
||||
<div
|
||||
class="formulate-input-upload-area"
|
||||
:data-has-files="hasFiles"
|
||||
>
|
||||
<input
|
||||
ref="file"
|
||||
:data-is-drag-hover="isOver"
|
||||
type="file"
|
||||
v-bind="attributes"
|
||||
@blur="context.blurHandler"
|
||||
@change="handleFile"
|
||||
@dragover="handleDragOver"
|
||||
@dragleave="handleDragLeave"
|
||||
>
|
||||
<div
|
||||
v-show="!hasFiles"
|
||||
class="formulate-input-upload-area-mask"
|
||||
/>
|
||||
<FormulateFiles
|
||||
v-if="hasFiles"
|
||||
:files="context.model"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormulateInputMixin from '../FormulateInputMixin'
|
||||
import FileUpload from '../FileUpload'
|
||||
import FormulateFiles from '../FormulateFiles.vue'
|
||||
|
||||
export default {
|
||||
name: 'FormulateInputFile',
|
||||
components: {
|
||||
FormulateFiles
|
||||
},
|
||||
mixins: [FormulateInputMixin],
|
||||
data () {
|
||||
return {
|
||||
isOver: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasFiles () {
|
||||
return (this.context.model instanceof FileUpload && this.context.model.files.length)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleFile () {
|
||||
const input = this.$refs.file
|
||||
if (input.files.length) {
|
||||
this.context.model = this.$formulate.createUpload(input.files, this.context)
|
||||
}
|
||||
if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
|
||||
this.context.model.upload()
|
||||
}
|
||||
},
|
||||
handleDragOver (e) {
|
||||
e.preventDefault()
|
||||
this.isOver = true
|
||||
},
|
||||
handleDragLeave (e) {
|
||||
e.preventDefault()
|
||||
this.isOver = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -16,7 +16,7 @@
|
||||
import FormulateInputMixin from '../FormulateInputMixin'
|
||||
|
||||
export default {
|
||||
name: 'FormulateInputText',
|
||||
name: 'FormulateInputSlider',
|
||||
mixins: [FormulateInputMixin]
|
||||
}
|
||||
</script>
|
||||
|
@ -19,6 +19,10 @@ export default {
|
||||
labelPosition: this.logicalLabelPosition,
|
||||
attributes: this.elementAttributes,
|
||||
blurHandler: blurHandler.bind(this),
|
||||
showImage: this.showImage,
|
||||
uploadUrl: this.uploadUrl,
|
||||
uploader: this.uploader || this.$formulate.getUploader(),
|
||||
immediateUpload: this.immediateUpload,
|
||||
...this.typeContext
|
||||
})
|
||||
},
|
||||
|
28
src/libs/faux-uploader.js
Normal file
28
src/libs/faux-uploader.js
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* A fake uploader used by default.
|
||||
*
|
||||
* @param {File} file
|
||||
* @param {function} progress
|
||||
* @param {function} error
|
||||
* @param {object} options
|
||||
*/
|
||||
export default function (file, progress, error, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const totalTime = options.fauxUploaderDuration || 2000
|
||||
const start = performance.now()
|
||||
const advance = () => setTimeout(() => {
|
||||
const elapsed = performance.now() - start
|
||||
const currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100))
|
||||
progress(currentProgress)
|
||||
if (currentProgress >= 100) {
|
||||
resolve({
|
||||
url: 'http://via.placeholder.com/350x150.png',
|
||||
name: file.name
|
||||
})
|
||||
} else {
|
||||
advance()
|
||||
}
|
||||
}, 20)
|
||||
advance()
|
||||
})
|
||||
}
|
@ -93,5 +93,16 @@ export default {
|
||||
select: {
|
||||
classification: 'select',
|
||||
component: 'FormulateInputSelect'
|
||||
},
|
||||
|
||||
// === FILE TYPE
|
||||
|
||||
file: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
},
|
||||
image: {
|
||||
classification: 'file',
|
||||
component: 'FormulateInputFile'
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import isUrl from 'is-url'
|
||||
import FileUpload from '../FileUpload'
|
||||
import { shallowEqualObjects, regexForFormat } from './utils'
|
||||
|
||||
/**
|
||||
@ -124,17 +125,18 @@ export default {
|
||||
/**
|
||||
* Check the maximum value of a particular.
|
||||
*/
|
||||
max: function (value, minimum = 10) {
|
||||
max: function (value, minimum = 10, force) {
|
||||
return Promise.resolve((() => {
|
||||
minimum = Number(minimum)
|
||||
if (!isNaN(value)) {
|
||||
value = Number(value)
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
if (Array.isArray(value)) {
|
||||
minimum = !isNaN(minimum) ? Number(minimum) : minimum
|
||||
return value.length <= minimum
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
value = !isNaN(value) ? Number(value) : value
|
||||
return value <= minimum
|
||||
}
|
||||
if (typeof value === 'string' || (force === 'length')) {
|
||||
value = !isNaN(value) ? value.toString() : value
|
||||
return value.length <= minimum
|
||||
}
|
||||
return false
|
||||
@ -146,6 +148,12 @@ export default {
|
||||
*/
|
||||
mime: function (files, ...types) {
|
||||
return Promise.resolve((() => {
|
||||
if (files instanceof FileUpload) {
|
||||
if (files.hasUploader()) {
|
||||
return false
|
||||
}
|
||||
files = files.getFiles()
|
||||
}
|
||||
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
|
||||
for (const i in files) {
|
||||
if (!types.includes(files[i].type)) {
|
||||
|
@ -103,20 +103,28 @@ export default {
|
||||
* The maximum value allowed.
|
||||
*/
|
||||
max: function ({ name, value, args }) {
|
||||
if (!isNaN(value)) {
|
||||
return `${name} must be less than ${args[0]}.`
|
||||
if (Array.isArray(value)) {
|
||||
return `You may only select ${args[0]} ${name}.`
|
||||
}
|
||||
return `${name} must be less than ${args[0]} characters long.`
|
||||
const force = Array.isArray(args) && args[1] ? args[1] : false
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return `${s(name)} must be less than ${args[0]}.`
|
||||
}
|
||||
return `${s(name)} must be less than ${args[0]} characters long.`
|
||||
},
|
||||
|
||||
/**
|
||||
* The maximum value allowed.
|
||||
*/
|
||||
min: function ({ name, value, args }) {
|
||||
if (!isNaN(value)) {
|
||||
return `${name} must be more than ${args[0]}.`
|
||||
if (Array.isArray(value)) {
|
||||
return `You must select at least ${args[0]} ${name}.`
|
||||
}
|
||||
return `${name} must be more than ${args[0]} characters long.`
|
||||
const force = Array.isArray(args) && args[1] ? args[1] : false
|
||||
if ((!isNaN(value) && force !== 'length') || force === 'value') {
|
||||
return `${s(name)} must be more than ${args[0]}.`
|
||||
}
|
||||
return `${s(name)} must be more than ${args[0]} characters long.`
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -53,6 +53,7 @@ test('installs on vue instance', () => {
|
||||
'FormulateInputErrors',
|
||||
'FormulateInputBox',
|
||||
'FormulateInputText',
|
||||
'FormulateInputFile',
|
||||
'FormulateInputGroup',
|
||||
'FormulateInputSelect',
|
||||
'FormulateInputSlider',
|
||||
|
@ -331,11 +331,19 @@ describe('max', () => {
|
||||
|
||||
it('passes when a array length', async () => expect(await rules.max(Array(6), '6')).toBe(true))
|
||||
|
||||
it('passes when forced to validate on length', async () => expect(await rules.max(10, 3, 'length')).toBe(true))
|
||||
|
||||
it('passes when forced to validate string on value', async () => expect(await rules.max('b', 'e', 'value')).toBe(true))
|
||||
|
||||
it('fails when a array length', async () => expect(await rules.max(Array(6), '5')).toBe(false))
|
||||
|
||||
it('fails when a string length', async () => expect(await rules.max('bar', 2)).toBe(false))
|
||||
|
||||
it('fails when a number', async () => expect(await rules.max(10, '7')).toBe(false))
|
||||
|
||||
it('fails when a number', async () => expect(await rules.max(10, '7')).toBe(false))
|
||||
|
||||
it('fails when forced to validate on length', async () => expect(await rules.max(-10, '1', 'length')).toBe(false))
|
||||
})
|
||||
|
||||
/**
|
||||
|
@ -55,6 +55,37 @@
|
||||
input {
|
||||
@include baseinput;
|
||||
}
|
||||
|
||||
input[type="color"] {
|
||||
height: 1.1em;
|
||||
box-sizing: content-box;
|
||||
|
||||
@mixin color-swatch {
|
||||
display: block;
|
||||
height: 1em;
|
||||
border-radius: .2em;
|
||||
border: 0;
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
&::-webkit-color-swatch-wrapper {
|
||||
padding: 0 0 0 1.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 79.17 79.17"><path fill="%23#{str-slice("#{$formulate-gray-ddd}", 2)}" d="M40.8,22.92c-3.4-3.4-4.76-8.44-1-12.24s8.84-2.44,12.24,1c5-5,10.69-13.33,18.81-11.31a11,11,0,0,1,7.62,14.34c-1.26,3.45-4.63,6.06-7.16,8.59-.92.93-3,2.26-3.46,3.46-.42,1,1.82,2.63,2.36,4a8,8,0,0,1-12.42,9.19c-.21-.16-1.35-1.51-1.59-1.51s-.83.83-1,1L49.71,44.9,32.43,62.18c-3.37,3.38-6.6,7.14-10.26,10.21a11,11,0,0,1-4.48,2.28c-1.25.3-3.11-.22-4.18.18-1.28.48-2.42,2.65-3.68,3.4-6.05,3.61-12.64-4-8.46-9.57.73-1,2.53-1.92,3-3a14.46,14.46,0,0,0-.09-2.52,10.75,10.75,0,0,1,3.14-6.77c.92-1,1.93-1.93,2.89-2.9Zm4.4-1.5c4.19,4,8.24,8.24,12.36,12.36,2.06,2.06,5,5.59,8,2.61,4.65-4.62-5-6.8-2.42-10.78C66.3,20.7,76.4,16.48,74.84,9.45,73.62,4,67.12,2.78,63.29,6.32c-2.55,2.36-4.93,4.94-7.39,7.4-.79.78-1.8,2.28-2.88,2.73-2.14.88-3.4-1.62-4.79-2.77-2.58-2.14-6.89-.82-6.53,3C41.89,18.68,43.87,20.09,45.2,21.42Zm-1.45,4.44L27.82,41.79C22,47.57,15.89,53.14,10.41,59.2a8.23,8.23,0,0,0-1.44,2c-.93,2,.25,4.14-.5,6S4.92,69.94,4.3,72a2.34,2.34,0,0,0,2.56,3c1.11-.17,2-1.33,2.71-2.07a11.17,11.17,0,0,1,2.08-2c1.68-.94,4,.17,5.93-.57C20,69.41,22,66.73,23.76,65L34.42,54.3,53.3,35.42Z"/></svg>');
|
||||
background-repeat: no-repeat;
|
||||
background-size: .9em .9em;
|
||||
background-position: left .1em;
|
||||
}
|
||||
|
||||
&::-webkit-color-swatch {
|
||||
@include color-swatch;
|
||||
}
|
||||
|
||||
&::-moz-color-swatch {
|
||||
@include color-swatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slider inputs
|
||||
@ -207,7 +238,8 @@
|
||||
border-color: $formulate-green;
|
||||
|
||||
&::before {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="%23#{str-slice("#{$formulate-green}", 2)}"><path d="M8.76,56.2c-6.38-6.34,3.26-16,9.64-9.69L38,65.88,80.56,23.29c6.38-6.38,16.07,3.32,9.69,9.69L42.84,80.37a6.83,6.83,0,0,1-9.65,0Z"/></svg>');
|
||||
background-color: $formulate-green;
|
||||
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M8.76,56.2c-6.38-6.34,3.26-16,9.64-9.69L38,65.88,80.56,23.29c6.38-6.38,16.07,3.32,9.69,9.69L42.84,80.37a6.83,6.83,0,0,1-9.65,0Z"/></svg>');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -245,4 +277,97 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// File inputs
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
&[data-classification="file"] {
|
||||
.formulate-input-upload-area {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding: 2em;
|
||||
|
||||
&[data-has-files] {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
&-mask {
|
||||
border-radius: .4em;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border: 2px dashed $formulate-gray-dd;
|
||||
z-index: 2;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
background-color: $formulate-gray-dd;
|
||||
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58"><path d="M29,58A29,29,0,1,0,0,29,29,29,0,0,0,29,58ZM29,4A25,25,0,1,1,4,29,25,25,0,0,1,29,4Z"/><polygon points="27 22 27 44.4 31 44.4 31 22 41.7 31.1 44.3 28.1 29 15 13.7 28.1 16.3 31.1 27 22"/></svg>');
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
input:focus,
|
||||
input:hover,
|
||||
input[data-is-drag-hover] {
|
||||
& ~ .formulate-input-upload-area-mask {
|
||||
border-color: $formulate-green;
|
||||
|
||||
&::before {
|
||||
background-color: $formulate-green;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.formulate-files {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
@include baseinput;
|
||||
display: block;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@mixin progress {
|
||||
appearance: none;
|
||||
height: .5em;
|
||||
border-radius: .5em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::-webkit-progress-bar {
|
||||
@include progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ $formulate-yellow-l: #fff8d2;
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-weight: 400;
|
||||
line-height: 1.1em;
|
||||
margin: 0;
|
||||
|
||||
&::placeholder {
|
||||
color: $formulate-gray-dd;
|
||||
|
Loading…
x
Reference in New Issue
Block a user