Commit ed3564c1 by Tomek Romik Committed by Qiang Xue

Added client-side image validation

parent 378b765e
...@@ -68,27 +68,29 @@ yii.validation = (function ($) { ...@@ -68,27 +68,29 @@ yii.validation = (function ($) {
pub.addMessage(messages, options.notEqual, value); pub.addMessage(messages, options.notEqual, value);
} }
}, },
file: function (value, messages, options, attribute) { globalFiles: function(files, messages, options) {
var files = $(attribute.input).get(0).files,
index, ext;
if (options.message && !files) { if (options.message && !files) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message);
} }
if (!options.skipOnEmpty && files.length == 0) { if (!options.skipOnEmpty && files.length === 0) {
pub.addMessage(messages, options.uploadRequired, value); pub.addMessage(messages, options.uploadRequired);
} else if (files.length == 0) { } else if (files.length === 0) {
return; return false;
} }
if (options.maxFiles && options.maxFiles < files.length) { if (options.maxFiles && options.maxFiles < files.length) {
pub.addMessage(messages, options.tooMany); pub.addMessage(messages, options.tooMany);
} }
$.each(files, function (i, file) { return true;
if (options.extensions && options.extensions.length > 0) { },
singleFile: function(file, messages, options) {
var index, ext;
if (options.extensions && options.extensions.length > 0) {
index = file.name.lastIndexOf('.'); index = file.name.lastIndexOf('.');
if (!~index) { if (!~index) {
...@@ -98,25 +100,99 @@ yii.validation = (function ($) { ...@@ -98,25 +100,99 @@ yii.validation = (function ($) {
} }
if (!~options.extensions.indexOf(ext)) { if (!~options.extensions.indexOf(ext)) {
messages.push(options.wrongExtension.replace(/\{file\}/g, file.name)); pub.addMessage(messages, options.wrongExtension.replace(/\{file\}/g, file.name));
} }
} }
if (options.mimeTypes && options.mimeTypes.length > 0) { if (options.mimeTypes && options.mimeTypes.length > 0) {
if (!~options.mimeTypes.indexOf(file.type)) { if (!~options.mimeTypes.indexOf(file.type)) {
messages.push(options.wrongMimeType.replace(/\{file\}/g, file.name)); pub.addMessage(messages, options.wrongMimeType.replace(/\{file\}/g, file.name));
} }
} }
if (options.maxSize && options.maxSize < file.size) { if (options.maxSize && options.maxSize < file.size) {
messages.push(options.tooBig.replace(/\{file\}/g, file.name)); pub.addMessage(messages, options.tooBig.replace(/\{file\}/g, file.name));
} }
if (options.maxSize && options.minSize > file.size) { if (options.maxSize && options.minSize > file.size) {
messages.push(options.tooSmall.replace(/\{file\}/g, file.name)); pub.addMessage(messages, options.tooSmall.replace(/\{file\}/g, file.name));
} }
},
file: function (messages, options, attribute) {
var files = $(attribute.input).get(0).files,
self = this;
if ( !self.globalFiles(files, messages, options) ) {
return;
}
$.each(files, function (i, file) {
self.singleFile(file, messages, options);
});
},
image: function (messages, options, deferred, attribute) {
var files = $(attribute.input).get(0).files,
self = this;
if ( !self.globalFiles(files, messages, options) ) {
return;
}
$.each(files, function (i, file) {
// Perform file validation
self.singleFile(file, messages, options);
// Skip image validation if FileReader API is not available
if (typeof FileReader === "undefined") {
return;
}
var def = $.Deferred(),
fr = new FileReader(),
img = new Image();
img.onload = function () {
if (options.minWidth && this.width < options.minWidth) {
pub.addMessage(messages, options.underWidth.replace(/\{file\}/g, file.name));
}
if (options.maxWidth && this.width > options.maxWidth) {
pub.addMessage(messages, options.overWidth.replace(/\{file\}/g, file.name));
}
if (options.minHeight && this.height < options.minHeight) {
pub.addMessage(messages, options.underHeight.replace(/\{file\}/g, file.name));
}
if (options.maxHeight && this.height > options.maxHeight) {
pub.addMessage(messages, options.overHeight.replace(/\{file\}/g, file.name));
}
def.resolve();
};
img.onerror = function () {
pub.addMessage(messages, options.notImage);
def.resolve();
};
fr.onload = function () {
img.src = fr.result;
};
// Resolve deferred if there was error while reading data
fr.onerror = function () {
def.resolve();
};
fr.readAsDataURL(file);
deferred.push(def);
}); });
}, },
number: function (value, messages, options) { number: function (value, messages, options) {
......
...@@ -122,6 +122,8 @@ class FileValidator extends Validator ...@@ -122,6 +122,8 @@ class FileValidator extends Validator
* - {mimeTypes}: the value of [[mimeTypes]] * - {mimeTypes}: the value of [[mimeTypes]]
*/ */
public $wrongMimeType; public $wrongMimeType;
protected $_clientOptions;
/** /**
...@@ -342,12 +344,15 @@ class FileValidator extends Validator ...@@ -342,12 +344,15 @@ class FileValidator extends Validator
$options['skipOnEmpty'] = $this->skipOnEmpty; $options['skipOnEmpty'] = $this->skipOnEmpty;
if ( !$this->skipOnEmpty ) { if ( !$this->skipOnEmpty ) {
$options['uploadRequired'] = Yii::$app->getI18n()->format($this->uploadRequired, [], Yii::$app->language); $options['uploadRequired'] = Yii::$app->getI18n()->format($this->uploadRequired, [
'attribute' => $label,
], Yii::$app->language);
} }
if ( $this->mimeTypes !== null ) { if ( $this->mimeTypes !== null ) {
$options['mimeTypes'] = $this->mimeTypes; $options['mimeTypes'] = $this->mimeTypes;
$options['wrongMimeType'] = Yii::$app->getI18n()->format($this->wrongMimeType, [ $options['wrongMimeType'] = Yii::$app->getI18n()->format($this->wrongMimeType, [
'attribute' => $label,
'mimeTypes' => join(', ', $this->mimeTypes) 'mimeTypes' => join(', ', $this->mimeTypes)
], Yii::$app->language); ], Yii::$app->language);
} }
...@@ -355,6 +360,7 @@ class FileValidator extends Validator ...@@ -355,6 +360,7 @@ class FileValidator extends Validator
if ( $this->extensions !== null ) { if ( $this->extensions !== null ) {
$options['extensions'] = $this->extensions; $options['extensions'] = $this->extensions;
$options['wrongExtension'] = Yii::$app->getI18n()->format($this->wrongExtension, [ $options['wrongExtension'] = Yii::$app->getI18n()->format($this->wrongExtension, [
'attribute' => $label,
'extensions' => join(', ', $this->extensions) 'extensions' => join(', ', $this->extensions)
], Yii::$app->language); ], Yii::$app->language);
} }
...@@ -362,6 +368,7 @@ class FileValidator extends Validator ...@@ -362,6 +368,7 @@ class FileValidator extends Validator
if ( $this->minSize !== null ) { if ( $this->minSize !== null ) {
$options['minSize'] = $this->minSize; $options['minSize'] = $this->minSize;
$options['tooSmall'] = Yii::$app->getI18n()->format($this->tooSmall, [ $options['tooSmall'] = Yii::$app->getI18n()->format($this->tooSmall, [
'attribute' => $label,
'limit' => $this->minSize 'limit' => $this->minSize
], Yii::$app->language); ], Yii::$app->language);
} }
...@@ -369,6 +376,7 @@ class FileValidator extends Validator ...@@ -369,6 +376,7 @@ class FileValidator extends Validator
if ( $this->maxSize !== null ) { if ( $this->maxSize !== null ) {
$options['maxSize'] = $this->maxSize; $options['maxSize'] = $this->maxSize;
$options['tooBig'] = Yii::$app->getI18n()->format($this->tooBig, [ $options['tooBig'] = Yii::$app->getI18n()->format($this->tooBig, [
'attribute' => $label,
'limit' => $this->maxSize 'limit' => $this->maxSize
], Yii::$app->language); ], Yii::$app->language);
} }
...@@ -376,12 +384,16 @@ class FileValidator extends Validator ...@@ -376,12 +384,16 @@ class FileValidator extends Validator
if ( $this->maxFiles !== null ) { if ( $this->maxFiles !== null ) {
$options['maxFiles'] = $this->maxFiles; $options['maxFiles'] = $this->maxFiles;
$options['tooMany'] = Yii::$app->getI18n()->format($this->tooMany, [ $options['tooMany'] = Yii::$app->getI18n()->format($this->tooMany, [
'attribute' => $label,
'limit' => $this->maxFiles 'limit' => $this->maxFiles
], Yii::$app->language); ], Yii::$app->language);
} }
ValidationAsset::register($view); ValidationAsset::register($view);
return 'yii.validation.file(value, messages, ' . json_encode($options) . ', attribute);'; // Store options for ImageValidator
$this->_clientOptions = $options;
return 'yii.validation.file(messages, ' . json_encode($options) . ', attribute);';
} }
} }
...@@ -158,4 +158,57 @@ class ImageValidator extends FileValidator ...@@ -158,4 +158,57 @@ class ImageValidator extends FileValidator
return null; return null;
} }
/**
* @inheritdoc
*/
public function clientValidateAttribute($object, $attribute, $view)
{
parent::clientValidateAttribute($object, $attribute, $view);
$label = $object->getAttributeLabel($attribute);
// Inherit options from FileValidator
$options = $this->_clientOptions;
if ( $this->notImage !== null ) {
$options['notImage'] = Yii::$app->getI18n()->format($this->notImage, [
'attribute' => $label
], Yii::$app->language);
}
if ( $this->minWidth !== null ) {
$options['minWidth'] = $this->minWidth;
$options['underWidth'] = Yii::$app->getI18n()->format($this->underWidth, [
'attribute' => $label,
'limit' => $this->minWidth
], Yii::$app->language);
}
if ( $this->maxWidth !== null ) {
$options['maxWidth'] = $this->maxWidth;
$options['overWidth'] = Yii::$app->getI18n()->format($this->overWidth, [
'attribute' => $label,
'limit' => $this->maxWidth
], Yii::$app->language);
}
if ( $this->minHeight !== null ) {
$options['minHeight'] = $this->minHeight;
$options['underHeight'] = Yii::$app->getI18n()->format($this->underHeight, [
'attribute' => $label,
'limit' => $this->maxHeight
], Yii::$app->language);
}
if ( $this->maxHeight !== null ) {
$options['maxHeight'] = $this->maxHeight;
$options['overHeight'] = Yii::$app->getI18n()->format($this->overHeight, [
'attribute' => $label,
'limit' => $this->maxHeight
], Yii::$app->language);
}
return 'yii.validation.image(messages, ' . json_encode($options) . ', deferred, attribute);';
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment