vendor and env first commit
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Albert Moreno <albert@memorylimit.net>
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
## Laravel Javascript Validation
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
**Laravel Javascript Validation** package allows to reuse your Laravel [Validation Rules][], [Messages][], [FormRequest][] and [Validators][] to validate forms automatically in client side without need to write any Javascript code or use HTML Builder Class.
|
||||
|
||||
You can validate forms automatically referencing it to your defined validations. The messages are loaded from your validations and translated according your Localization preferences.
|
||||
|
||||
#### Supported versions
|
||||
|
||||
Laravel 9.x - 11.x
|
||||
|
||||
#### Feature overview
|
||||
|
||||
- Automatic creation of Javascript validation based on your [Validation Rules][] or [FormRequest][], no Javascript coding required.
|
||||
- Supports other validation packages.
|
||||
- AJAX validation for [ActiveURL][], [Unique][] and [Exists][] Rules, [Custom Validation Rules][] and other validation packages
|
||||
- Unobtrusive integration, you can use without Laravel Form Builder
|
||||
- The package uses [Jquery Validation Plugin][] bundled in provided script.
|
||||
- Uses Laravel Localization to translate messages.
|
||||
|
||||
#### Supported Rules
|
||||
|
||||
**Almost all [Validation Rules][] provided by Laravel and other packages are supported**.
|
||||
|
||||
Almost are validated in client-side using Javascript, but in some cases, the validation should to be done in server-side via AJAX:
|
||||
- [ActiveURL][]
|
||||
- [Unique][]
|
||||
- [Exists][]
|
||||
- [Custom Validation Rules][]
|
||||
- Validations provided by other packages
|
||||
|
||||
##### Unsupported Rules
|
||||
|
||||
Some Laravel validations are not implemented yet.
|
||||
|
||||
- [Present][]
|
||||
- [DateFormat][] rule don't support timezone format
|
||||
|
||||
#### Getting started
|
||||
|
||||
The easiest way to create Javascript validations is using [Laravel Form Request Validation][].
|
||||
|
||||
##### Installation
|
||||
|
||||
Follow the [Installation Guide][] to install the package. **The default config should work out-of-box**
|
||||
|
||||
##### Validating Form Request
|
||||
|
||||
Call [JsValidator Facade][] in your view to validate any [FormRequest](https://laravel.com/docs/master/validation)
|
||||
|
||||
```html
|
||||
<form>
|
||||
<!-- ... My form stuff ... -->
|
||||
</form>
|
||||
|
||||
<!-- Javascript Requirements -->
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
|
||||
|
||||
<!-- Laravel Javascript Validation -->
|
||||
<script type="text/javascript" src="{{ asset('vendor/jsvalidation/js/jsvalidation.js')}}"></script>
|
||||
|
||||
{!! JsValidator::formRequest('App\Http\Requests\MyFormRequest') !!}
|
||||
```
|
||||
|
||||
Take a look to [Basic Usage](https://github.com/proengsoft/laravel-jsvalidation/wiki/Basic-Usage) or [Examples](https://github.com/proengsoft/laravel-jsvalidation/wiki/Validating-Examples) to get more information.
|
||||
|
||||
#### Documentation
|
||||
|
||||
**To get more info refer to [Project Wiki](https://github.com/proengsoft/laravel-jsvalidation/wiki/Home)**
|
||||
|
||||
#### Changelog
|
||||
|
||||
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
|
||||
|
||||
#### Contributing
|
||||
|
||||
Please see [CONTRIBUTING][] for details.
|
||||
|
||||
#### Credits
|
||||
|
||||
[Laravel Javascript Validation contributors list](../../contributors)
|
||||
|
||||
#### License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
|
||||
[ActiveURL]: https://laravel.com/docs/5.4/validation#rule-active-url
|
||||
[CONTRIBUTING]: https://github.com/proengsoft/laravel-jsvalidation/wiki/Contributing
|
||||
[Custom Validations]: https://laravel.com/docs/5.4/validation#custom-validation-rules
|
||||
[Custom Validation Rules]: https://laravel.com/docs/5.4/validation#custom-validation-rules
|
||||
[DateFormat]: https://laravel.com/docs/5.4/validation#rule-date-format
|
||||
[Exists]: https://laravel.com/docs/5.4/validation#rule-exists
|
||||
[FormRequest]: https://laravel.com/docs/5.4/validation#form-request-validation
|
||||
[Installation Guide]: https://github.com/proengsoft/laravel-jsvalidation/wiki/Installation
|
||||
[JsValidator Facade]: https://github.com/proengsoft/laravel-jsvalidation/wiki/Facade
|
||||
[JQueryValidation]: https://jqueryvalidation.org/
|
||||
[JQuery Validation Plugin]: https://jqueryvalidation.org/
|
||||
[Laravel Form Request Validation]: http://laravel.com/docs/5.4/validation#form-request-validation
|
||||
[Laravel Localization]: https://laravel.com/docs/5.4/localization
|
||||
[Messages]: https://laravel.com/docs/5.4/validation#error-messages-and-views
|
||||
[Present]: https://laravel.com/docs/5.4/validation#rule-present
|
||||
[Unique]: https://laravel.com/docs/5.4/validation#rule-unique
|
||||
[Validation]: https://laravel.com/docs/5.4/validation
|
||||
[Validation Rules]: https://laravel.com/docs/5.4/validation#available-validation-rules
|
||||
[Validators]: https://laravel.com/docs/5.4/validation#form-request-validation
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
* Default view used to render Javascript validation code
|
||||
*
|
||||
* Supported: 'jsvalidation::bootstrap', 'jsvalidation::bootstrap4', 'jsvalidation::bootstrap5', 'jsvalidation::uikit'
|
||||
*/
|
||||
'view' => 'jsvalidation::bootstrap',
|
||||
|
||||
/*
|
||||
* Default JQuery selector find the form to be validated.
|
||||
* By default, the validations are applied to all forms.
|
||||
*/
|
||||
'form_selector' => 'form',
|
||||
|
||||
/*
|
||||
* If you change the focus on detect some error then active
|
||||
* this parameter to move the focus to the first error found.
|
||||
*/
|
||||
'focus_on_error' => false,
|
||||
|
||||
/*
|
||||
* Duration time for the animation when We are moving the focus
|
||||
* to the first error, http://api.jquery.com/animate/ for more information.
|
||||
*/
|
||||
'duration_animate' => 1000,
|
||||
|
||||
/*
|
||||
* Enable or disable Ajax validations of Database and custom rules.
|
||||
* By default Unique, ActiveURL, Exists and custom validations are validated via AJAX
|
||||
*/
|
||||
'disable_remote_validation' => false,
|
||||
|
||||
/*
|
||||
* Field name used in the remote validation Ajax request
|
||||
* You can change this value to avoid conflicts wth your field names
|
||||
*/
|
||||
'remote_validation_field' => '_jsvalidation',
|
||||
|
||||
/*
|
||||
* Whether to escape all validation messages with htmlentities.
|
||||
*/
|
||||
'escape' => true,
|
||||
|
||||
/*
|
||||
* Set a default value for the validate ignore property.
|
||||
*
|
||||
* See https://jqueryvalidation.org/validate/#ignore
|
||||
*/
|
||||
'ignore' => ":hidden, [contenteditable='true']",
|
||||
];
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,535 @@
|
||||
/*!
|
||||
* Laravel Javascript Validation
|
||||
*
|
||||
* https://github.com/proengsoft/laravel-jsvalidation
|
||||
*
|
||||
* Helper functions used by validators
|
||||
*
|
||||
* Copyright (c) 2017 Proengsoft
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
import strlen from 'locutus/php/strings/strlen';
|
||||
import array_diff from 'locutus/php/array/array_diff';
|
||||
import strtotime from 'locutus/php/datetime/strtotime';
|
||||
import is_numeric from 'locutus/php/var/is_numeric';
|
||||
|
||||
$.extend(true, laravelValidation, {
|
||||
|
||||
helpers: {
|
||||
|
||||
/**
|
||||
* Numeric rules
|
||||
*/
|
||||
numericRules: ['Integer', 'Numeric'],
|
||||
|
||||
/**
|
||||
* Gets the file information from file input.
|
||||
*
|
||||
* @param fieldObj
|
||||
* @param index
|
||||
* @returns {{file: *, extension: string, size: number}}
|
||||
*/
|
||||
fileinfo: function (fieldObj, index) {
|
||||
var FileName = fieldObj.value;
|
||||
index = typeof index !== 'undefined' ? index : 0;
|
||||
if ( fieldObj.files !== null ) {
|
||||
if (typeof fieldObj.files[index] !== 'undefined') {
|
||||
return {
|
||||
file: FileName,
|
||||
extension: FileName.substr(FileName.lastIndexOf('.') + 1),
|
||||
size: fieldObj.files[index].size / 1024,
|
||||
type: fieldObj.files[index].type
|
||||
};
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Gets the selectors for th specified field names.
|
||||
*
|
||||
* @param names
|
||||
* @returns {string}
|
||||
*/
|
||||
selector: function (names) {
|
||||
var selector = [];
|
||||
if (! this.isArray(names)) {
|
||||
names = [names];
|
||||
}
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
selector.push("[name='" + names[i] + "']");
|
||||
}
|
||||
return selector.join();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Check if element has numeric rules.
|
||||
*
|
||||
* @param element
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasNumericRules: function (element) {
|
||||
return this.hasRules(element, this.numericRules);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if element has passed rules.
|
||||
*
|
||||
* @param element
|
||||
* @param rules
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasRules: function (element, rules) {
|
||||
|
||||
var found = false;
|
||||
if (typeof rules === 'string') {
|
||||
rules = [rules];
|
||||
}
|
||||
|
||||
var validator = $.data(element.form, "validator");
|
||||
var listRules = [];
|
||||
var cache = validator.arrayRulesCache;
|
||||
if (element.name in cache) {
|
||||
$.each(cache[element.name], function (index, arrayRule) {
|
||||
listRules.push(arrayRule);
|
||||
});
|
||||
}
|
||||
if (element.name in validator.settings.rules) {
|
||||
listRules.push(validator.settings.rules[element.name]);
|
||||
}
|
||||
$.each(listRules, function(index,objRules){
|
||||
if ('laravelValidation' in objRules) {
|
||||
var _rules=objRules.laravelValidation;
|
||||
for (var i = 0; i < _rules.length; i++) {
|
||||
if ($.inArray(_rules[i][0],rules) !== -1) {
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the string length using PHP function.
|
||||
* http://php.net/manual/en/function.strlen.php
|
||||
* http://phpjs.org/functions/strlen/
|
||||
*
|
||||
* @param string
|
||||
*/
|
||||
strlen: function (string) {
|
||||
return strlen(string);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the size of the object depending of his type.
|
||||
*
|
||||
* @param obj
|
||||
* @param element
|
||||
* @param value
|
||||
* @returns int
|
||||
*/
|
||||
getSize: function getSize(obj, element, value) {
|
||||
|
||||
if (this.hasNumericRules(element) && this.is_numeric(value)) {
|
||||
return parseFloat(value);
|
||||
} else if (this.isArray(value)) {
|
||||
return parseFloat(value.length);
|
||||
} else if (element.type === 'file') {
|
||||
return parseFloat(Math.floor(this.fileinfo(element).size));
|
||||
}
|
||||
|
||||
return parseFloat(this.strlen(value));
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Return specified rule from element.
|
||||
*
|
||||
* @param rule
|
||||
* @param element
|
||||
* @returns object
|
||||
*/
|
||||
getLaravelValidation: function(rule, element) {
|
||||
|
||||
var found = undefined;
|
||||
$.each($.validator.staticRules(element), function(key, rules) {
|
||||
if (key==="laravelValidation") {
|
||||
$.each(rules, function (i, value) {
|
||||
if (value[0]===rule) {
|
||||
found=value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return he timestamp of value passed using format or default format in element.
|
||||
*
|
||||
* @param value
|
||||
* @param format
|
||||
* @returns {boolean|int}
|
||||
*/
|
||||
parseTime: function (value, format) {
|
||||
|
||||
var timeValue = false;
|
||||
var fmt = new DateFormatter();
|
||||
|
||||
if (typeof value === 'number' && typeof format === 'undefined') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof format === 'object') {
|
||||
var dateRule = this.getLaravelValidation('DateFormat', format);
|
||||
if (dateRule !== undefined) {
|
||||
format = dateRule[1][0];
|
||||
} else {
|
||||
format = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (format == null) {
|
||||
timeValue = this.strtotime(value);
|
||||
} else {
|
||||
timeValue = fmt.parseDate(value, format);
|
||||
if (timeValue instanceof Date && fmt.formatDate(timeValue, format) === value) {
|
||||
timeValue = Math.round((timeValue.getTime() / 1000));
|
||||
} else {
|
||||
timeValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
return timeValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compare a given date against another using an operator.
|
||||
*
|
||||
* @param validator
|
||||
* @param value
|
||||
* @param element
|
||||
* @param params
|
||||
* @param operator
|
||||
* @return {boolean}
|
||||
*/
|
||||
compareDates: function (validator, value, element, params, operator) {
|
||||
|
||||
var timeCompare = this.parseTime(params);
|
||||
|
||||
if (!timeCompare) {
|
||||
var target = this.dependentElement(validator, element, params);
|
||||
if (target === undefined) {
|
||||
return false;
|
||||
}
|
||||
timeCompare = this.parseTime(validator.elementValue(target), target);
|
||||
}
|
||||
|
||||
var timeValue = this.parseTime(value, element);
|
||||
if (timeValue === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (operator) {
|
||||
case '<':
|
||||
return timeValue < timeCompare;
|
||||
|
||||
case '<=':
|
||||
return timeValue <= timeCompare;
|
||||
|
||||
case '==':
|
||||
case '===':
|
||||
return timeValue === timeCompare;
|
||||
|
||||
case '>':
|
||||
return timeValue > timeCompare;
|
||||
|
||||
case '>=':
|
||||
return timeValue >= timeCompare;
|
||||
|
||||
default:
|
||||
throw new Error('Unsupported operator.');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method allows you to intelligently guess the date by closely matching the specific format.
|
||||
*
|
||||
* @param value
|
||||
* @param format
|
||||
* @returns {Date}
|
||||
*/
|
||||
guessDate: function (value, format) {
|
||||
var fmt = new DateFormatter();
|
||||
return fmt.guessDate(value, format)
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns Unix timestamp based on PHP function strototime.
|
||||
* http://php.net/manual/es/function.strtotime.php
|
||||
* http://phpjs.org/functions/strtotime/
|
||||
*
|
||||
* @param text
|
||||
* @param now
|
||||
* @returns {*}
|
||||
*/
|
||||
strtotime: function (text, now) {
|
||||
return strtotime(text, now)
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if value is numeric.
|
||||
* http://php.net/manual/es/var.is_numeric.php
|
||||
* http://phpjs.org/functions/is_numeric/
|
||||
*
|
||||
* @param mixed_var
|
||||
* @returns {*}
|
||||
*/
|
||||
is_numeric: function (mixed_var) {
|
||||
return is_numeric(mixed_var)
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether the argument is of type Array.
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#Polyfill
|
||||
*
|
||||
* @param arg
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isArray: function(arg) {
|
||||
return Object.prototype.toString.call(arg) === '[object Array]';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns Array diff based on PHP function array_diff.
|
||||
* http://php.net/manual/es/function.array_diff.php
|
||||
* http://phpjs.org/functions/array_diff/
|
||||
*
|
||||
* @param arr1
|
||||
* @param arr2
|
||||
* @returns {*}
|
||||
*/
|
||||
arrayDiff: function (arr1, arr2) {
|
||||
return array_diff(arr1, arr2);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether two arrays are equal to one another.
|
||||
*
|
||||
* @param arr1
|
||||
* @param arr2
|
||||
* @returns {*}
|
||||
*/
|
||||
arrayEquals: function (arr1, arr2) {
|
||||
if (! this.isArray(arr1) || ! this.isArray(arr2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arr1.length !== arr2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $.isEmptyObject(this.arrayDiff(arr1, arr2));
|
||||
},
|
||||
|
||||
/**
|
||||
* Makes element dependant from other.
|
||||
*
|
||||
* @param validator
|
||||
* @param element
|
||||
* @param name
|
||||
* @returns {*}
|
||||
*/
|
||||
dependentElement: function(validator, element, name) {
|
||||
|
||||
var el=validator.findByName(name);
|
||||
|
||||
if ( el[0]!==undefined && validator.settings.onfocusout ) {
|
||||
var event = 'blur';
|
||||
if (el[0].tagName === 'SELECT' ||
|
||||
el[0].tagName === 'OPTION' ||
|
||||
el[0].type === 'checkbox' ||
|
||||
el[0].type === 'radio'
|
||||
) {
|
||||
event = 'click';
|
||||
}
|
||||
|
||||
var ruleName = '.validate-laravelValidation';
|
||||
el.off( ruleName )
|
||||
.off(event + ruleName + '-' + element.name)
|
||||
.on( event + ruleName + '-' + element.name, function() {
|
||||
$( element ).valid();
|
||||
});
|
||||
}
|
||||
|
||||
return el[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses error Ajax response and gets the message.
|
||||
*
|
||||
* @param response
|
||||
* @returns {string[]}
|
||||
*/
|
||||
parseErrorResponse: function (response) {
|
||||
var newResponse = ['Whoops, looks like something went wrong.'];
|
||||
if ('responseText' in response) {
|
||||
var errorMsg = response.responseText.match(/<h1\s*>(.*)<\/h1\s*>/i);
|
||||
if (this.isArray(errorMsg)) {
|
||||
newResponse = [errorMsg[1]];
|
||||
}
|
||||
}
|
||||
return newResponse;
|
||||
},
|
||||
|
||||
/**
|
||||
* Escape string to use as Regular Expression.
|
||||
*
|
||||
* @param str
|
||||
* @returns string
|
||||
*/
|
||||
escapeRegExp: function (str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate RegExp from wildcard attributes.
|
||||
*
|
||||
* @param name
|
||||
* @returns {RegExp}
|
||||
*/
|
||||
regexFromWildcard: function (name) {
|
||||
var nameParts = name.split('[*]');
|
||||
if (nameParts.length === 1) nameParts.push('');
|
||||
|
||||
return new RegExp('^' + nameParts.map(function(x) {
|
||||
return laravelValidation.helpers.escapeRegExp(x)
|
||||
}).join('\\[[^\\]]*\\]') + '$');
|
||||
},
|
||||
|
||||
/**
|
||||
* Merge additional laravel validation rules into the current rule set.
|
||||
*
|
||||
* @param {object} rules
|
||||
* @param {object} newRules
|
||||
* @returns {object}
|
||||
*/
|
||||
mergeRules: function (rules, newRules) {
|
||||
var rulesList = {
|
||||
'laravelValidation': newRules.laravelValidation || [],
|
||||
'laravelValidationRemote': newRules.laravelValidationRemote || []
|
||||
};
|
||||
|
||||
for (var key in rulesList) {
|
||||
if (rulesList[key].length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof rules[key] === "undefined") {
|
||||
rules[key] = [];
|
||||
}
|
||||
|
||||
rules[key] = rules[key].concat(rulesList[key]);
|
||||
}
|
||||
|
||||
return rules;
|
||||
},
|
||||
|
||||
/**
|
||||
* HTML entity encode a string.
|
||||
*
|
||||
* @param string
|
||||
* @returns {string}
|
||||
*/
|
||||
encode: function (string) {
|
||||
return $('<div/>').text(string).html();
|
||||
},
|
||||
|
||||
/**
|
||||
* Lookup name in an array.
|
||||
*
|
||||
* @param validator
|
||||
* @param {string} name Name in dot notation format.
|
||||
* @returns {*}
|
||||
*/
|
||||
findByArrayName: function (validator, name) {
|
||||
var sqName = name.replace(/\.([^\.]+)/g, '[$1]'),
|
||||
lookups = [
|
||||
// Convert dot to square brackets. e.g. foo.bar.0 becomes foo[bar][0]
|
||||
sqName,
|
||||
// Append [] to the name e.g. foo becomes foo[] or foo.bar.0 becomes foo[bar][0][]
|
||||
sqName + '[]',
|
||||
// Remove key from last array e.g. foo[bar][0] becomes foo[bar][]
|
||||
sqName.replace(/(.*)\[(.*)\]$/g, '$1[]')
|
||||
];
|
||||
|
||||
for (var i = 0; i < lookups.length; i++) {
|
||||
var elem = validator.findByName(lookups[i]);
|
||||
if (elem.length > 0) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
return $(null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempt to find an element in the DOM matching the given name.
|
||||
* Example names include:
|
||||
* - domain.0 which matches domain[]
|
||||
* - customfield.3 which matches customfield[3]
|
||||
*
|
||||
* @param validator
|
||||
* @param {string} name
|
||||
* @returns {*}
|
||||
*/
|
||||
findByName: function (validator, name) {
|
||||
// Exact match.
|
||||
var elem = validator.findByName(name);
|
||||
if (elem.length > 0) {
|
||||
return elem;
|
||||
}
|
||||
|
||||
// Find name in data, using dot notation.
|
||||
var delim = '.',
|
||||
parts = name.split(delim);
|
||||
for (var i = parts.length; i > 0; i--) {
|
||||
var reconstructed = [];
|
||||
for (var c = 0; c < i; c++) {
|
||||
reconstructed.push(parts[c]);
|
||||
}
|
||||
|
||||
elem = this.findByArrayName(validator, reconstructed.join(delim));
|
||||
if (elem.length > 0) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
return $(null);
|
||||
},
|
||||
|
||||
/**
|
||||
* If it's an array element, get all values.
|
||||
*
|
||||
* @param validator
|
||||
* @param element
|
||||
* @returns {*|string}
|
||||
*/
|
||||
allElementValues: function (validator, element) {
|
||||
if (element.name.indexOf('[]') !== -1) {
|
||||
return validator.findByName(element.name).map(function (i, e) {
|
||||
return validator.elementValue(e);
|
||||
}).get();
|
||||
}
|
||||
|
||||
return validator.elementValue(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,383 @@
|
||||
/*!
|
||||
* Laravel Javascript Validation
|
||||
*
|
||||
* https://github.com/proengsoft/laravel-jsvalidation
|
||||
*
|
||||
* Copyright (c) 2017 Proengsoft
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
var laravelValidation;
|
||||
laravelValidation = {
|
||||
|
||||
implicitRules: ['Required','Confirmed'],
|
||||
|
||||
/**
|
||||
* Initialize laravel validations.
|
||||
*/
|
||||
init: function () {
|
||||
|
||||
// jquery-validation requires the field under validation to be present. We're adding a dummy hidden
|
||||
// field so that any errors are not visible.
|
||||
var constructor = $.fn.validate;
|
||||
$.fn.validate = function( options ) {
|
||||
var name = 'proengsoft_jsvalidation'; // must match the name defined in JsValidatorFactory.newFormRequestValidator
|
||||
var $elm = $(this).find('input[name="' + name + '"]');
|
||||
if ($elm.length === 0) {
|
||||
$('<input>').attr({type: 'hidden', name: name}).appendTo(this);
|
||||
}
|
||||
|
||||
return constructor.apply(this, [options]);
|
||||
};
|
||||
|
||||
// Disable class rules and attribute rules
|
||||
$.validator.classRuleSettings = {};
|
||||
$.validator.attributeRules = function () {};
|
||||
|
||||
$.validator.dataRules = this.arrayRules;
|
||||
$.validator.prototype.arrayRulesCache = {};
|
||||
|
||||
// Register validations methods
|
||||
this.setupValidations();
|
||||
},
|
||||
|
||||
arrayRules: function(element) {
|
||||
|
||||
var rules = {},
|
||||
validator = $.data( element.form, "validator"),
|
||||
cache = validator.arrayRulesCache;
|
||||
|
||||
// Is not an Array
|
||||
if (element.name.indexOf('[') === -1) {
|
||||
return rules;
|
||||
}
|
||||
|
||||
if (! (element.name in cache)) {
|
||||
cache[element.name] = {};
|
||||
}
|
||||
|
||||
$.each(validator.settings.rules, function(name, tmpRules) {
|
||||
if (name in cache[element.name]) {
|
||||
rules = laravelValidation.helpers.mergeRules(rules, cache[element.name][name]);
|
||||
} else {
|
||||
cache[element.name][name] = {};
|
||||
|
||||
var nameRegExp = laravelValidation.helpers.regexFromWildcard(name);
|
||||
if (element.name.match(nameRegExp)) {
|
||||
var newRules = $.validator.normalizeRule(tmpRules) || {};
|
||||
cache[element.name][name] = newRules;
|
||||
|
||||
rules = laravelValidation.helpers.mergeRules(rules, newRules);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return rules;
|
||||
},
|
||||
|
||||
setupValidations: function () {
|
||||
|
||||
/**
|
||||
* Get CSRF token.
|
||||
*
|
||||
* @param params
|
||||
* @returns {string}
|
||||
*/
|
||||
var getCsrfToken = function (params) {
|
||||
return params[0][1][1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether to validate all attributes.
|
||||
*
|
||||
* @param params
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var isValidateAll = function (params) {
|
||||
return params[0][1][2];
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether the rule is implicit.
|
||||
*
|
||||
* @param params
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var isImplicit = function (params) {
|
||||
var implicit = false;
|
||||
$.each(params, function (i, parameters) {
|
||||
implicit = implicit || parameters[3];
|
||||
});
|
||||
|
||||
return implicit;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get form method from a validator instance.
|
||||
*
|
||||
* @param validator
|
||||
* @returns {string}
|
||||
*/
|
||||
var formMethod = function (validator) {
|
||||
var formMethod = $(validator.currentForm).attr('method');
|
||||
if ($(validator.currentForm).find('input[name="_method"]').length) {
|
||||
formMethod = $(validator.currentForm).find('input[name="_method"]').val();
|
||||
}
|
||||
|
||||
return formMethod;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get AJAX parameters for remote requests.
|
||||
*
|
||||
* @param validator
|
||||
* @param element
|
||||
* @param params
|
||||
* @param data
|
||||
* @returns {object}
|
||||
*/
|
||||
var ajaxOpts = function (validator, element, params, data) {
|
||||
return {
|
||||
mode: 'abort',
|
||||
port: 'validate' + element.name,
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
context: validator.currentForm,
|
||||
url: $(validator.currentForm).attr('action'),
|
||||
type: formMethod(validator),
|
||||
beforeSend: function (xhr) {
|
||||
var token = getCsrfToken(params);
|
||||
if (formMethod(validator) !== 'get' && token) {
|
||||
return xhr.setRequestHeader('X-XSRF-TOKEN', token);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate a set of local JS based rules against an element.
|
||||
*
|
||||
* @param validator
|
||||
* @param values
|
||||
* @param element
|
||||
* @param rules
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var validateLocalRules = function (validator, values, element, rules) {
|
||||
var validated = true,
|
||||
previous = validator.previousValue(element);
|
||||
|
||||
$.each(rules, function (i, param) {
|
||||
var implicit = param[3] || laravelValidation.implicitRules.indexOf(param[0]) !== -1;
|
||||
var rule = param[0];
|
||||
var message = param[2];
|
||||
|
||||
if (! implicit && validator.optional(element)) {
|
||||
validated = "dependency-mismatch";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (laravelValidation.methods[rule] !== undefined) {
|
||||
$.each(values, function(index, value) {
|
||||
validated = laravelValidation.methods[rule].call(validator, value, element, param[1], function(valid) {
|
||||
validator.settings.messages[element.name].laravelValidationRemote = previous.originalMessage;
|
||||
if (valid) {
|
||||
var submitted = validator.formSubmitted;
|
||||
validator.prepareElement(element);
|
||||
validator.formSubmitted = submitted;
|
||||
validator.successList.push(element);
|
||||
delete validator.invalid[element.name];
|
||||
validator.showErrors();
|
||||
} else {
|
||||
var errors = {};
|
||||
errors[ element.name ]
|
||||
= previous.message
|
||||
= typeof message === "function" ? message( value ) : message;
|
||||
validator.invalid[element.name] = true;
|
||||
validator.showErrors(errors);
|
||||
}
|
||||
validator.showErrors(validator.errorMap);
|
||||
previous.valid = valid;
|
||||
});
|
||||
|
||||
// Break loop.
|
||||
if (validated === false) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
validated = false;
|
||||
}
|
||||
|
||||
if (validated !== true) {
|
||||
if (!validator.settings.messages[element.name] ) {
|
||||
validator.settings.messages[element.name] = {};
|
||||
}
|
||||
|
||||
validator.settings.messages[element.name].laravelValidation= message;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return validated;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create JQueryValidation check to validate Laravel rules.
|
||||
*/
|
||||
|
||||
$.validator.addMethod("laravelValidation", function (value, element, params) {
|
||||
var rules = [],
|
||||
arrayRules = [];
|
||||
$.each(params, function (i, param) {
|
||||
// put Implicit rules in front
|
||||
var isArrayRule = param[4].indexOf('[') !== -1;
|
||||
if (param[3] || laravelValidation.implicitRules.indexOf(param[0]) !== -1) {
|
||||
isArrayRule ? arrayRules.unshift(param) : rules.unshift(param);
|
||||
} else {
|
||||
isArrayRule ? arrayRules.push(param) : rules.push(param);
|
||||
}
|
||||
});
|
||||
|
||||
// Validate normal rules.
|
||||
var localRulesResult = validateLocalRules(this, [value], element, rules);
|
||||
|
||||
// Validate items of the array using array rules.
|
||||
var arrayValue = ! Array.isArray(value) ? [value] : value;
|
||||
var arrayRulesResult = validateLocalRules(this, arrayValue, element, arrayRules);
|
||||
|
||||
return localRulesResult && arrayRulesResult;
|
||||
}, '');
|
||||
|
||||
|
||||
/**
|
||||
* Create JQueryValidation check to validate Remote Laravel rules.
|
||||
*/
|
||||
$.validator.addMethod("laravelValidationRemote", function (value, element, params) {
|
||||
|
||||
if (! isImplicit(params) && this.optional( element )) {
|
||||
return "dependency-mismatch";
|
||||
}
|
||||
|
||||
var previous = this.previousValue( element ),
|
||||
validator, data;
|
||||
|
||||
if (! this.settings.messages[ element.name ]) {
|
||||
this.settings.messages[ element.name ] = {};
|
||||
}
|
||||
previous.originalMessage = this.settings.messages[ element.name ].laravelValidationRemote;
|
||||
this.settings.messages[ element.name ].laravelValidationRemote = previous.message;
|
||||
|
||||
if (laravelValidation.helpers.arrayEquals(previous.old, value) || previous.old === value) {
|
||||
return previous.valid;
|
||||
}
|
||||
|
||||
previous.old = value;
|
||||
validator = this;
|
||||
this.startRequest( element );
|
||||
|
||||
data = $(validator.currentForm).serializeArray();
|
||||
data.push({'name': '_jsvalidation', 'value': element.name});
|
||||
data.push({'name': '_jsvalidation_validate_all', 'value': isValidateAll(params)});
|
||||
|
||||
$.ajax( ajaxOpts(validator, element, params, data) )
|
||||
.always(function( response, textStatus ) {
|
||||
var errors, message, submitted, valid;
|
||||
|
||||
if (textStatus === 'error') {
|
||||
valid = false;
|
||||
response = laravelValidation.helpers.parseErrorResponse(response);
|
||||
} else if (textStatus === 'success') {
|
||||
valid = response === true || response === "true";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
validator.settings.messages[ element.name ].laravelValidationRemote = previous.originalMessage;
|
||||
|
||||
if ( valid ) {
|
||||
submitted = validator.formSubmitted;
|
||||
validator.prepareElement( element );
|
||||
validator.formSubmitted = submitted;
|
||||
validator.successList.push( element );
|
||||
delete validator.invalid[ element.name ];
|
||||
validator.showErrors();
|
||||
} else {
|
||||
errors = {};
|
||||
message = response || validator.defaultMessage( element, "remote" );
|
||||
errors[ element.name ]
|
||||
= previous.message
|
||||
= typeof message === "function" ? message( value ) : message[0];
|
||||
validator.invalid[ element.name ] = true;
|
||||
validator.showErrors( errors );
|
||||
}
|
||||
validator.showErrors(validator.errorMap);
|
||||
previous.valid = valid;
|
||||
validator.stopRequest( element, valid );
|
||||
}
|
||||
);
|
||||
return "pending";
|
||||
}, '');
|
||||
|
||||
/**
|
||||
* Create JQueryValidation check to form requests.
|
||||
*/
|
||||
$.validator.addMethod("laravelValidationFormRequest", function (value, element, params) {
|
||||
|
||||
var validator = this,
|
||||
previous = validator.previousValue(element);
|
||||
|
||||
var data = $(validator.currentForm).serializeArray();
|
||||
data.push({name: '__proengsoft_form_request', value: 1}); // must match FormRequest.JS_VALIDATION_FIELD
|
||||
|
||||
// Skip AJAX if the value remains the same as a prior request.
|
||||
if (JSON.stringify(previous.old) === JSON.stringify(data)) {
|
||||
if (! previous.valid) {
|
||||
validator.showErrors(previous.errors || {});
|
||||
}
|
||||
|
||||
return previous.valid;
|
||||
}
|
||||
|
||||
previous.old = data;
|
||||
this.startRequest( element );
|
||||
|
||||
$.ajax(ajaxOpts(validator, element, params, data))
|
||||
.always(function( response, textStatus ) {
|
||||
var errors = {},
|
||||
valid = textStatus === 'success' && (response === true || response === 'true');
|
||||
|
||||
if (valid) {
|
||||
validator.resetInternals();
|
||||
validator.toHide = validator.errorsFor( element );
|
||||
} else {
|
||||
$.each( response, function( fieldName, errorMessages ) {
|
||||
var errorElement = laravelValidation.helpers.findByName(validator, fieldName)[0];
|
||||
if (errorElement) {
|
||||
errors[errorElement.name] = laravelValidation.helpers.encode(errorMessages[0] || '');
|
||||
}
|
||||
});
|
||||
|
||||
// Failed to find the error fields so mark the form as valid otherwise user
|
||||
// will be left in limbo with no visible error messages.
|
||||
if ($.isEmptyObject(errors)) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
previous.valid = valid;
|
||||
previous.errors = errors;
|
||||
validator.showErrors(errors);
|
||||
validator.stopRequest(element, valid);
|
||||
});
|
||||
|
||||
return 'pending';
|
||||
}, '');
|
||||
}
|
||||
};
|
||||
|
||||
$(function() {
|
||||
laravelValidation.init();
|
||||
});
|
||||
@@ -0,0 +1,478 @@
|
||||
/*!
|
||||
* Laravel Javascript Validation
|
||||
*
|
||||
* https://github.com/proengsoft/laravel-jsvalidation
|
||||
*
|
||||
* Timezone Helper functions used by validators
|
||||
*
|
||||
* Copyright (c) 2017 Proengsoft
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
$.extend(true, laravelValidation, {
|
||||
|
||||
helpers: {
|
||||
|
||||
/**
|
||||
* Check if the specified timezone is valid.
|
||||
*
|
||||
* @param value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isTimezone: function (value) {
|
||||
|
||||
var timezones={
|
||||
"africa": [
|
||||
"abidjan",
|
||||
"accra",
|
||||
"addis_ababa",
|
||||
"algiers",
|
||||
"asmara",
|
||||
"bamako",
|
||||
"bangui",
|
||||
"banjul",
|
||||
"bissau",
|
||||
"blantyre",
|
||||
"brazzaville",
|
||||
"bujumbura",
|
||||
"cairo",
|
||||
"casablanca",
|
||||
"ceuta",
|
||||
"conakry",
|
||||
"dakar",
|
||||
"dar_es_salaam",
|
||||
"djibouti",
|
||||
"douala",
|
||||
"el_aaiun",
|
||||
"freetown",
|
||||
"gaborone",
|
||||
"harare",
|
||||
"johannesburg",
|
||||
"juba",
|
||||
"kampala",
|
||||
"khartoum",
|
||||
"kigali",
|
||||
"kinshasa",
|
||||
"lagos",
|
||||
"libreville",
|
||||
"lome",
|
||||
"luanda",
|
||||
"lubumbashi",
|
||||
"lusaka",
|
||||
"malabo",
|
||||
"maputo",
|
||||
"maseru",
|
||||
"mbabane",
|
||||
"mogadishu",
|
||||
"monrovia",
|
||||
"nairobi",
|
||||
"ndjamena",
|
||||
"niamey",
|
||||
"nouakchott",
|
||||
"ouagadougou",
|
||||
"porto-novo",
|
||||
"sao_tome",
|
||||
"tripoli",
|
||||
"tunis",
|
||||
"windhoek"
|
||||
],
|
||||
"america": [
|
||||
"adak",
|
||||
"anchorage",
|
||||
"anguilla",
|
||||
"antigua",
|
||||
"araguaina",
|
||||
"argentina\/buenos_aires",
|
||||
"argentina\/catamarca",
|
||||
"argentina\/cordoba",
|
||||
"argentina\/jujuy",
|
||||
"argentina\/la_rioja",
|
||||
"argentina\/mendoza",
|
||||
"argentina\/rio_gallegos",
|
||||
"argentina\/salta",
|
||||
"argentina\/san_juan",
|
||||
"argentina\/san_luis",
|
||||
"argentina\/tucuman",
|
||||
"argentina\/ushuaia",
|
||||
"aruba",
|
||||
"asuncion",
|
||||
"atikokan",
|
||||
"bahia",
|
||||
"bahia_banderas",
|
||||
"barbados",
|
||||
"belem",
|
||||
"belize",
|
||||
"blanc-sablon",
|
||||
"boa_vista",
|
||||
"bogota",
|
||||
"boise",
|
||||
"cambridge_bay",
|
||||
"campo_grande",
|
||||
"cancun",
|
||||
"caracas",
|
||||
"cayenne",
|
||||
"cayman",
|
||||
"chicago",
|
||||
"chihuahua",
|
||||
"costa_rica",
|
||||
"creston",
|
||||
"cuiaba",
|
||||
"curacao",
|
||||
"danmarkshavn",
|
||||
"dawson",
|
||||
"dawson_creek",
|
||||
"denver",
|
||||
"detroit",
|
||||
"dominica",
|
||||
"edmonton",
|
||||
"eirunepe",
|
||||
"el_salvador",
|
||||
"fortaleza",
|
||||
"glace_bay",
|
||||
"godthab",
|
||||
"goose_bay",
|
||||
"grand_turk",
|
||||
"grenada",
|
||||
"guadeloupe",
|
||||
"guatemala",
|
||||
"guayaquil",
|
||||
"guyana",
|
||||
"halifax",
|
||||
"havana",
|
||||
"hermosillo",
|
||||
"indiana\/indianapolis",
|
||||
"indiana\/knox",
|
||||
"indiana\/marengo",
|
||||
"indiana\/petersburg",
|
||||
"indiana\/tell_city",
|
||||
"indiana\/vevay",
|
||||
"indiana\/vincennes",
|
||||
"indiana\/winamac",
|
||||
"inuvik",
|
||||
"iqaluit",
|
||||
"jamaica",
|
||||
"juneau",
|
||||
"kentucky\/louisville",
|
||||
"kentucky\/monticello",
|
||||
"kralendijk",
|
||||
"la_paz",
|
||||
"lima",
|
||||
"los_angeles",
|
||||
"lower_princes",
|
||||
"maceio",
|
||||
"managua",
|
||||
"manaus",
|
||||
"marigot",
|
||||
"martinique",
|
||||
"matamoros",
|
||||
"mazatlan",
|
||||
"menominee",
|
||||
"merida",
|
||||
"metlakatla",
|
||||
"mexico_city",
|
||||
"miquelon",
|
||||
"moncton",
|
||||
"monterrey",
|
||||
"montevideo",
|
||||
"montreal",
|
||||
"montserrat",
|
||||
"nassau",
|
||||
"new_york",
|
||||
"nipigon",
|
||||
"nome",
|
||||
"noronha",
|
||||
"north_dakota\/beulah",
|
||||
"north_dakota\/center",
|
||||
"north_dakota\/new_salem",
|
||||
"ojinaga",
|
||||
"panama",
|
||||
"pangnirtung",
|
||||
"paramaribo",
|
||||
"phoenix",
|
||||
"port-au-prince",
|
||||
"port_of_spain",
|
||||
"porto_velho",
|
||||
"puerto_rico",
|
||||
"rainy_river",
|
||||
"rankin_inlet",
|
||||
"recife",
|
||||
"regina",
|
||||
"resolute",
|
||||
"rio_branco",
|
||||
"santa_isabel",
|
||||
"santarem",
|
||||
"santiago",
|
||||
"santo_domingo",
|
||||
"sao_paulo",
|
||||
"scoresbysund",
|
||||
"shiprock",
|
||||
"sitka",
|
||||
"st_barthelemy",
|
||||
"st_johns",
|
||||
"st_kitts",
|
||||
"st_lucia",
|
||||
"st_thomas",
|
||||
"st_vincent",
|
||||
"swift_current",
|
||||
"tegucigalpa",
|
||||
"thule",
|
||||
"thunder_bay",
|
||||
"tijuana",
|
||||
"toronto",
|
||||
"tortola",
|
||||
"vancouver",
|
||||
"whitehorse",
|
||||
"winnipeg",
|
||||
"yakutat",
|
||||
"yellowknife"
|
||||
],
|
||||
"antarctica": [
|
||||
"casey",
|
||||
"davis",
|
||||
"dumontdurville",
|
||||
"macquarie",
|
||||
"mawson",
|
||||
"mcmurdo",
|
||||
"palmer",
|
||||
"rothera",
|
||||
"south_pole",
|
||||
"syowa",
|
||||
"vostok"
|
||||
],
|
||||
"arctic": [
|
||||
"longyearbyen"
|
||||
],
|
||||
"asia": [
|
||||
"aden",
|
||||
"almaty",
|
||||
"amman",
|
||||
"anadyr",
|
||||
"aqtau",
|
||||
"aqtobe",
|
||||
"ashgabat",
|
||||
"baghdad",
|
||||
"bahrain",
|
||||
"baku",
|
||||
"bangkok",
|
||||
"beirut",
|
||||
"bishkek",
|
||||
"brunei",
|
||||
"choibalsan",
|
||||
"chongqing",
|
||||
"colombo",
|
||||
"damascus",
|
||||
"dhaka",
|
||||
"dili",
|
||||
"dubai",
|
||||
"dushanbe",
|
||||
"gaza",
|
||||
"harbin",
|
||||
"hebron",
|
||||
"ho_chi_minh",
|
||||
"hong_kong",
|
||||
"hovd",
|
||||
"irkutsk",
|
||||
"jakarta",
|
||||
"jayapura",
|
||||
"jerusalem",
|
||||
"kabul",
|
||||
"kamchatka",
|
||||
"karachi",
|
||||
"kashgar",
|
||||
"kathmandu",
|
||||
"khandyga",
|
||||
"kolkata",
|
||||
"krasnoyarsk",
|
||||
"kuala_lumpur",
|
||||
"kuching",
|
||||
"kuwait",
|
||||
"macau",
|
||||
"magadan",
|
||||
"makassar",
|
||||
"manila",
|
||||
"muscat",
|
||||
"nicosia",
|
||||
"novokuznetsk",
|
||||
"novosibirsk",
|
||||
"omsk",
|
||||
"oral",
|
||||
"phnom_penh",
|
||||
"pontianak",
|
||||
"pyongyang",
|
||||
"qatar",
|
||||
"qyzylorda",
|
||||
"rangoon",
|
||||
"riyadh",
|
||||
"sakhalin",
|
||||
"samarkand",
|
||||
"seoul",
|
||||
"shanghai",
|
||||
"singapore",
|
||||
"taipei",
|
||||
"tashkent",
|
||||
"tbilisi",
|
||||
"tehran",
|
||||
"thimphu",
|
||||
"tokyo",
|
||||
"ulaanbaatar",
|
||||
"urumqi",
|
||||
"ust-nera",
|
||||
"vientiane",
|
||||
"vladivostok",
|
||||
"yakutsk",
|
||||
"yekaterinburg",
|
||||
"yerevan"
|
||||
],
|
||||
"atlantic": [
|
||||
"azores",
|
||||
"bermuda",
|
||||
"canary",
|
||||
"cape_verde",
|
||||
"faroe",
|
||||
"madeira",
|
||||
"reykjavik",
|
||||
"south_georgia",
|
||||
"st_helena",
|
||||
"stanley"
|
||||
],
|
||||
"australia": [
|
||||
"adelaide",
|
||||
"brisbane",
|
||||
"broken_hill",
|
||||
"currie",
|
||||
"darwin",
|
||||
"eucla",
|
||||
"hobart",
|
||||
"lindeman",
|
||||
"lord_howe",
|
||||
"melbourne",
|
||||
"perth",
|
||||
"sydney"
|
||||
],
|
||||
"europe": [
|
||||
"amsterdam",
|
||||
"andorra",
|
||||
"athens",
|
||||
"belgrade",
|
||||
"berlin",
|
||||
"bratislava",
|
||||
"brussels",
|
||||
"bucharest",
|
||||
"budapest",
|
||||
"busingen",
|
||||
"chisinau",
|
||||
"copenhagen",
|
||||
"dublin",
|
||||
"gibraltar",
|
||||
"guernsey",
|
||||
"helsinki",
|
||||
"isle_of_man",
|
||||
"istanbul",
|
||||
"jersey",
|
||||
"kaliningrad",
|
||||
"kiev",
|
||||
"lisbon",
|
||||
"ljubljana",
|
||||
"london",
|
||||
"luxembourg",
|
||||
"madrid",
|
||||
"malta",
|
||||
"mariehamn",
|
||||
"minsk",
|
||||
"monaco",
|
||||
"moscow",
|
||||
"oslo",
|
||||
"paris",
|
||||
"podgorica",
|
||||
"prague",
|
||||
"riga",
|
||||
"rome",
|
||||
"samara",
|
||||
"san_marino",
|
||||
"sarajevo",
|
||||
"simferopol",
|
||||
"skopje",
|
||||
"sofia",
|
||||
"stockholm",
|
||||
"tallinn",
|
||||
"tirane",
|
||||
"uzhgorod",
|
||||
"vaduz",
|
||||
"vatican",
|
||||
"vienna",
|
||||
"vilnius",
|
||||
"volgograd",
|
||||
"warsaw",
|
||||
"zagreb",
|
||||
"zaporozhye",
|
||||
"zurich"
|
||||
],
|
||||
"indian": [
|
||||
"antananarivo",
|
||||
"chagos",
|
||||
"christmas",
|
||||
"cocos",
|
||||
"comoro",
|
||||
"kerguelen",
|
||||
"mahe",
|
||||
"maldives",
|
||||
"mauritius",
|
||||
"mayotte",
|
||||
"reunion"
|
||||
],
|
||||
"pacific": [
|
||||
"apia",
|
||||
"auckland",
|
||||
"chatham",
|
||||
"chuuk",
|
||||
"easter",
|
||||
"efate",
|
||||
"enderbury",
|
||||
"fakaofo",
|
||||
"fiji",
|
||||
"funafuti",
|
||||
"galapagos",
|
||||
"gambier",
|
||||
"guadalcanal",
|
||||
"guam",
|
||||
"honolulu",
|
||||
"johnston",
|
||||
"kiritimati",
|
||||
"kosrae",
|
||||
"kwajalein",
|
||||
"majuro",
|
||||
"marquesas",
|
||||
"midway",
|
||||
"nauru",
|
||||
"niue",
|
||||
"norfolk",
|
||||
"noumea",
|
||||
"pago_pago",
|
||||
"palau",
|
||||
"pitcairn",
|
||||
"pohnpei",
|
||||
"port_moresby",
|
||||
"rarotonga",
|
||||
"saipan",
|
||||
"tahiti",
|
||||
"tarawa",
|
||||
"tongatapu",
|
||||
"wake",
|
||||
"wallis"
|
||||
],
|
||||
"utc": [
|
||||
""
|
||||
]
|
||||
};
|
||||
|
||||
var tzparts= value.split('/',2);
|
||||
var continent=tzparts[0].toLowerCase();
|
||||
var city='';
|
||||
if (tzparts[1]) {
|
||||
city=tzparts[1].toLowerCase();
|
||||
}
|
||||
|
||||
return (continent in timezones && ( timezones[continent].length===0 || timezones[continent].indexOf(city)!==-1))
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,756 @@
|
||||
/*!
|
||||
* Laravel Javascript Validation
|
||||
*
|
||||
* https://github.com/proengsoft/laravel-jsvalidation
|
||||
*
|
||||
* Methods that implement Laravel Validations
|
||||
*
|
||||
* Copyright (c) 2017 Proengsoft
|
||||
* Released under the MIT license
|
||||
*/
|
||||
|
||||
$.extend(true, laravelValidation, {
|
||||
|
||||
methods:{
|
||||
|
||||
helpers: laravelValidation.helpers,
|
||||
|
||||
jsRemoteTimer:0,
|
||||
|
||||
/**
|
||||
* "Validate" optional attributes.
|
||||
* Always returns true, just lets us put sometimes in rules.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Sometimes: function() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bail This is the default behaivour os JSValidation.
|
||||
* Always returns true, just lets us put sometimes in rules.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Bail: function() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* "Indicate" validation should pass if value is null.
|
||||
* Always returns true, just lets us put "nullable" in rules.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Nullable: function() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the given attribute is filled if it is present.
|
||||
*/
|
||||
Filled: function(value, element) {
|
||||
return $.validator.methods.required.call(this, value, element, true);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Validate that a required attribute exists.
|
||||
*/
|
||||
Required: function(value, element) {
|
||||
return $.validator.methods.required.call(this, value, element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when any other attribute exists.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
RequiredWith: function(value, element, params) {
|
||||
var validator=this,
|
||||
required=false;
|
||||
var currentObject=this;
|
||||
|
||||
$.each(params,function(i,param) {
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
currentObject, element, param
|
||||
);
|
||||
required=required || (
|
||||
target!==undefined &&
|
||||
$.validator.methods.required.call(
|
||||
validator,
|
||||
currentObject.elementValue(target),
|
||||
target,true
|
||||
));
|
||||
});
|
||||
|
||||
if (required) {
|
||||
return $.validator.methods.required.call(this, value, element, true);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when all other attribute exists.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
RequiredWithAll: function(value, element, params) {
|
||||
var validator=this,
|
||||
required=true;
|
||||
var currentObject=this;
|
||||
|
||||
$.each(params,function(i,param) {
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
currentObject, element, param
|
||||
);
|
||||
required = required && (
|
||||
target!==undefined &&
|
||||
$.validator.methods.required.call(
|
||||
validator,
|
||||
currentObject.elementValue(target),
|
||||
target,true
|
||||
));
|
||||
});
|
||||
|
||||
if (required) {
|
||||
return $.validator.methods.required.call(this, value, element, true);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when any other attribute does not exists.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
RequiredWithout: function(value, element, params) {
|
||||
var validator=this,
|
||||
required=false;
|
||||
var currentObject=this;
|
||||
|
||||
$.each(params,function(i,param) {
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
currentObject, element, param
|
||||
);
|
||||
required = required ||
|
||||
target===undefined||
|
||||
!$.validator.methods.required.call(
|
||||
validator,
|
||||
currentObject.elementValue(target),
|
||||
target,true
|
||||
);
|
||||
});
|
||||
|
||||
if (required) {
|
||||
return $.validator.methods.required.call(this, value, element, true);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when all other attribute does not exists.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
RequiredWithoutAll: function(value, element, params) {
|
||||
var validator=this,
|
||||
required=true,
|
||||
currentObject=this;
|
||||
|
||||
$.each(params,function(i, param) {
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
currentObject, element, param
|
||||
);
|
||||
required = required && (
|
||||
target===undefined ||
|
||||
!$.validator.methods.required.call(
|
||||
validator,
|
||||
currentObject.elementValue(target),
|
||||
target,true
|
||||
));
|
||||
});
|
||||
|
||||
if (required) {
|
||||
return $.validator.methods.required.call(this, value, element, true);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when another attribute has a given value.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
RequiredIf: function(value, element, params) {
|
||||
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
this, element, params[0]
|
||||
);
|
||||
|
||||
if (target!==undefined) {
|
||||
var val=String(this.elementValue(target));
|
||||
if (typeof val !== 'undefined') {
|
||||
var data = params.slice(1);
|
||||
if ($.inArray(val, data) !== -1) {
|
||||
return $.validator.methods.required.call(
|
||||
this, value, element, true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when another
|
||||
* attribute does not have a given value.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
RequiredUnless: function(value, element, params) {
|
||||
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
this, element, params[0]
|
||||
);
|
||||
|
||||
if (target!==undefined) {
|
||||
var val=String(this.elementValue(target));
|
||||
if (typeof val !== 'undefined') {
|
||||
var data = params.slice(1);
|
||||
if ($.inArray(val, data) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $.validator.methods.required.call(
|
||||
this, value, element, true
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute has a matching confirmation.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Confirmed: function(value, element, params) {
|
||||
return laravelValidation.methods.Same.call(this,value, element, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that two attributes match.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Same: function(value, element, params) {
|
||||
|
||||
var target=laravelValidation.helpers.dependentElement(
|
||||
this, element, params[0]
|
||||
);
|
||||
|
||||
if (target!==undefined) {
|
||||
return String(value) === String(this.elementValue(target));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that the values of an attribute is in another attribute.
|
||||
*
|
||||
* @param value
|
||||
* @param element
|
||||
* @param params
|
||||
* @returns {boolean}
|
||||
* @constructor
|
||||
*/
|
||||
InArray: function (value, element, params) {
|
||||
if (typeof params[0] === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
var elements = this.elements();
|
||||
var found = false;
|
||||
var nameRegExp = laravelValidation.helpers.regexFromWildcard(params[0]);
|
||||
|
||||
for ( var i = 0; i < elements.length ; i++ ) {
|
||||
var targetName = elements[i].name;
|
||||
if (targetName.match(nameRegExp)) {
|
||||
var equals = laravelValidation.methods.Same.call(this,value, element, [targetName]);
|
||||
found = found || equals;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate an attribute is unique among other values.
|
||||
*
|
||||
* @param value
|
||||
* @param element
|
||||
* @param params
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Distinct: function (value, element, params) {
|
||||
if (typeof params[0] === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var elements = this.elements();
|
||||
var found = false;
|
||||
var nameRegExp = laravelValidation.helpers.regexFromWildcard(params[0]);
|
||||
|
||||
for ( var i = 0; i < elements.length ; i++ ) {
|
||||
var targetName = elements[i].name;
|
||||
if (targetName !== element.name && targetName.match(nameRegExp)) {
|
||||
var equals = laravelValidation.methods.Same.call(this,value, element, [targetName]);
|
||||
found = found || equals;
|
||||
}
|
||||
}
|
||||
|
||||
return !found;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Validate that an attribute is different from another attribute.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Different: function(value, element, params) {
|
||||
return ! laravelValidation.methods.Same.call(this,value, element, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute was "accepted".
|
||||
* This validation rule implies the attribute is "required".
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Accepted: function(value) {
|
||||
var regex = new RegExp("^(?:(yes|on|1|true))$",'i');
|
||||
return regex.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is an array.
|
||||
*
|
||||
* @param value
|
||||
* @param element
|
||||
*/
|
||||
Array: function(value, element) {
|
||||
if (element.name.indexOf('[') !== -1 && element.name.indexOf(']') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return laravelValidation.helpers.isArray(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a boolean.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Boolean: function(value) {
|
||||
var regex= new RegExp("^(?:(true|false|1|0))$",'i');
|
||||
return regex.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is an integer.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Integer: function(value) {
|
||||
var regex= new RegExp("^(?:-?\\d+)$",'i');
|
||||
return regex.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is numeric.
|
||||
*/
|
||||
Numeric: function(value, element) {
|
||||
return $.validator.methods.number.call(this, value, element, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a string.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
String: function(value) {
|
||||
return typeof value === 'string';
|
||||
},
|
||||
|
||||
/**
|
||||
* The field under validation must be numeric and must have an exact length of value.
|
||||
*/
|
||||
Digits: function(value, element, params) {
|
||||
return (
|
||||
$.validator.methods.number.call(this, value, element, true) &&
|
||||
value.length === parseInt(params, 10)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* The field under validation must have a length between the given min and max.
|
||||
*/
|
||||
DigitsBetween: function(value, element, params) {
|
||||
return ($.validator.methods.number.call(this, value, element, true)
|
||||
&& value.length>=parseFloat(params[0]) && value.length<=parseFloat(params[1]));
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the size of an attribute.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Size: function(value, element, params) {
|
||||
return laravelValidation.helpers.getSize(this, element,value) === parseFloat(params[0]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the size of an attribute is between a set of values.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Between: function(value, element, params) {
|
||||
return ( laravelValidation.helpers.getSize(this, element,value) >= parseFloat(params[0]) &&
|
||||
laravelValidation.helpers.getSize(this,element,value) <= parseFloat(params[1]));
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the size of an attribute is greater than a minimum value.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Min: function(value, element, params) {
|
||||
value = laravelValidation.helpers.allElementValues(this, element);
|
||||
|
||||
return laravelValidation.helpers.getSize(this, element, value) >= parseFloat(params[0]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the size of an attribute is less than a maximum value.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Max: function(value, element, params) {
|
||||
value = laravelValidation.helpers.allElementValues(this, element);
|
||||
|
||||
return laravelValidation.helpers.getSize(this, element, value) <= parseFloat(params[0]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate an attribute is contained within a list of values.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
In: function(value, element, params) {
|
||||
if (laravelValidation.helpers.isArray(value)
|
||||
&& laravelValidation.helpers.hasRules(element, "Array")
|
||||
) {
|
||||
var diff = laravelValidation.helpers.arrayDiff(value, params);
|
||||
|
||||
return Object.keys(diff).length === 0;
|
||||
}
|
||||
|
||||
return params.indexOf(value.toString()) !== -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate an attribute is not contained within a list of values.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
NotIn: function(value, element, params) {
|
||||
return params.indexOf(value.toString()) === -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a valid IP.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Ip: function(value) {
|
||||
return /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i.test(value) ||
|
||||
/^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a valid e-mail address.
|
||||
*/
|
||||
Email: function(value, element) {
|
||||
return $.validator.methods.email.call(this, value, element, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a valid URL.
|
||||
*/
|
||||
Url: function(value, element) {
|
||||
return $.validator.methods.url.call(this, value, element, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* The field under validation must be a successfully uploaded file.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
File: function(value, element) {
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
|
||||
return true;
|
||||
}
|
||||
if ('files' in element ) {
|
||||
return (element.files.length > 0);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the MIME type of a file upload attribute is in a set of MIME types.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Mimes: function(value, element, params) {
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
|
||||
return true;
|
||||
}
|
||||
var lowerParams = $.map(params, function(item) {
|
||||
return item.toLowerCase();
|
||||
});
|
||||
|
||||
var fileinfo = laravelValidation.helpers.fileinfo(element);
|
||||
return (fileinfo !== false && lowerParams.indexOf(fileinfo.extension.toLowerCase())!==-1);
|
||||
},
|
||||
|
||||
/**
|
||||
* The file under validation must match one of the given MIME types.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Mimetypes: function(value, element, params) {
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
|
||||
return true;
|
||||
}
|
||||
var lowerParams = $.map(params, function(item) {
|
||||
return item.toLowerCase();
|
||||
});
|
||||
|
||||
var fileinfo = laravelValidation.helpers.fileinfo(element);
|
||||
|
||||
if (fileinfo === false) {
|
||||
return false;
|
||||
}
|
||||
return (lowerParams.indexOf(fileinfo.type.toLowerCase())!==-1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the MIME type of a file upload attribute is in a set of MIME types.
|
||||
*/
|
||||
Image: function(value, element) {
|
||||
return laravelValidation.methods.Mimes.call(this, value, element, [
|
||||
'jpg', 'png', 'gif', 'bmp', 'svg', 'jpeg'
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate dimensions of Image.
|
||||
*
|
||||
* @return {boolean|string}
|
||||
*/
|
||||
Dimensions: function(value, element, params, callback) {
|
||||
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
|
||||
return true;
|
||||
}
|
||||
if (element.files === null || typeof element.files[0] === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var fr = new FileReader;
|
||||
fr.onload = function () {
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
var height = parseFloat(img.naturalHeight);
|
||||
var width = parseFloat(img.naturalWidth);
|
||||
var ratio = width / height;
|
||||
var notValid = ((params['width']) && parseFloat(params['width'] !== width)) ||
|
||||
((params['min_width']) && parseFloat(params['min_width']) > width) ||
|
||||
((params['max_width']) && parseFloat(params['max_width']) < width) ||
|
||||
((params['height']) && parseFloat(params['height']) !== height) ||
|
||||
((params['min_height']) && parseFloat(params['min_height']) > height) ||
|
||||
((params['max_height']) && parseFloat(params['max_height']) < height) ||
|
||||
((params['ratio']) && ratio !== parseFloat(eval(params['ratio']))
|
||||
);
|
||||
callback(! notValid);
|
||||
};
|
||||
img.onerror = function() {
|
||||
callback(false);
|
||||
};
|
||||
img.src = fr.result;
|
||||
};
|
||||
fr.readAsDataURL(element.files[0]);
|
||||
|
||||
return 'pending';
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute contains only alphabetic characters.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Alpha: function(value) {
|
||||
if (typeof value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var regex = new RegExp("^(?:^[a-z\u00E0-\u00FC]+$)$",'i');
|
||||
return regex.test(value);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute contains only alpha-numeric characters.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
AlphaNum: function(value) {
|
||||
if (typeof value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
var regex = new RegExp("^(?:^[a-z0-9\u00E0-\u00FC]+$)$",'i');
|
||||
return regex.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute contains only alphabetic characters.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
AlphaDash: function(value) {
|
||||
if (typeof value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
var regex = new RegExp("^(?:^[a-z0-9\u00E0-\u00FC_-]+$)$",'i');
|
||||
return regex.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute passes a regular expression check.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Regex: function(value, element, params) {
|
||||
var invalidModifiers=['x','s','u','X','U','A'];
|
||||
// Converting php regular expression
|
||||
var phpReg= new RegExp('^(?:\/)(.*\\\/?[^\/]*|[^\/]*)(?:\/)([gmixXsuUAJ]*)?$');
|
||||
var matches=params[0].match(phpReg);
|
||||
if (matches === null) {
|
||||
return false;
|
||||
}
|
||||
// checking modifiers
|
||||
var php_modifiers=[];
|
||||
if (matches[2]!==undefined) {
|
||||
php_modifiers=matches[2].split('');
|
||||
for (var i=0; i<php_modifiers.length<i ;i++) {
|
||||
if (invalidModifiers.indexOf(php_modifiers[i])!==-1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
var regex = new RegExp("^(?:"+matches[1]+")$",php_modifiers.join());
|
||||
return regex.test(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a valid date.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Date: function(value) {
|
||||
return (laravelValidation.helpers.strtotime(value)!==false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate that an attribute matches a date format.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
DateFormat: function(value, element, params) {
|
||||
return laravelValidation.helpers.parseTime(value,params[0])!==false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the date is before a given date.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Before: function(value, element, params) {
|
||||
return laravelValidation.helpers.compareDates(this, value, element, params[0], '<');
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the date is equal or before a given date.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
BeforeOrEqual: function(value, element, params) {
|
||||
return laravelValidation.helpers.compareDates(this, value, element, params[0], '<=');
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the date is after a given date.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
After: function(value, element, params) {
|
||||
return laravelValidation.helpers.compareDates(this, value, element, params[0], '>');
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate the date is equal or after a given date.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
AfterOrEqual: function(value, element, params) {
|
||||
return laravelValidation.helpers.compareDates(this, value, element, params[0], '>=');
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Validate that an attribute is a valid date.
|
||||
*/
|
||||
Timezone: function(value) {
|
||||
return laravelValidation.helpers.isTimezone(value);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Validate the attribute is a valid JSON string.
|
||||
*
|
||||
* @param value
|
||||
* @return bool
|
||||
*/
|
||||
Json: function(value) {
|
||||
var result = true;
|
||||
try {
|
||||
JSON.parse(value);
|
||||
} catch (e) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Noop (always returns true).
|
||||
*
|
||||
* @param value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
ProengsoftNoop: function (value) {
|
||||
return true;
|
||||
},
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
<script>
|
||||
jQuery(document).ready(function(){
|
||||
|
||||
$("<?= $validator['selector']; ?>").each(function() {
|
||||
$(this).validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'help-block error-help-block',
|
||||
|
||||
errorPlacement: function (error, element) {
|
||||
if (element.parent('.input-group').length ||
|
||||
element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
|
||||
error.insertAfter(element.parent());
|
||||
// else just place the validation message immediately after the input
|
||||
} else {
|
||||
error.insertAfter(element);
|
||||
}
|
||||
},
|
||||
highlight: function (element) {
|
||||
$(element).closest('.form-group').removeClass('has-success').addClass('has-error'); // add the Bootstrap error class to the control group
|
||||
},
|
||||
|
||||
<?php if (isset($validator['ignore']) && is_string($validator['ignore'])): ?>
|
||||
|
||||
ignore: "<?= $validator['ignore']; ?>",
|
||||
<?php endif; ?>
|
||||
|
||||
/*
|
||||
// Uncomment this to mark as validated non required fields
|
||||
unhighlight: function(element) {
|
||||
$(element).closest('.form-group').removeClass('has-error').addClass('has-success');
|
||||
},
|
||||
*/
|
||||
success: function (element) {
|
||||
$(element).closest('.form-group').removeClass('has-error').addClass('has-success'); // remove the Boostrap error class from the control group
|
||||
},
|
||||
|
||||
focusInvalid: true,
|
||||
<?php if (Config::get('jsvalidation.focus_on_error')): ?>
|
||||
invalidHandler: function (form, validator) {
|
||||
|
||||
if (!validator.numberOfInvalids())
|
||||
return;
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: $(validator.errorList[0].element).offset().top
|
||||
}, <?= Config::get('jsvalidation.duration_animate') ?>);
|
||||
|
||||
},
|
||||
<?php endif; ?>
|
||||
|
||||
rules: <?= json_encode($validator['rules']); ?>
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,54 @@
|
||||
<script>
|
||||
jQuery(document).ready(function(){
|
||||
|
||||
$("<?= $validator['selector']; ?>").each(function() {
|
||||
$(this).validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'invalid-feedback',
|
||||
|
||||
errorPlacement: function (error, element) {
|
||||
if (element.parent('.input-group').length ||
|
||||
element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
|
||||
error.insertAfter(element.parent());
|
||||
// else just place the validation message immediately after the input
|
||||
} else {
|
||||
error.insertAfter(element);
|
||||
}
|
||||
},
|
||||
highlight: function (element) {
|
||||
$(element).closest('.form-control').removeClass('is-valid').addClass('is-invalid'); // add the Bootstrap error class to the control group
|
||||
},
|
||||
|
||||
<?php if (isset($validator['ignore']) && is_string($validator['ignore'])): ?>
|
||||
|
||||
ignore: "<?= $validator['ignore']; ?>",
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
unhighlight: function(element) {
|
||||
$(element).closest('.form-control').removeClass('is-invalid').addClass('is-valid');
|
||||
},
|
||||
|
||||
success: function (element) {
|
||||
$(element).closest('.form-control').removeClass('is-invalid').addClass('is-valid'); // remove the Boostrap error class from the control group
|
||||
},
|
||||
|
||||
focusInvalid: true,
|
||||
<?php if (Config::get('jsvalidation.focus_on_error')): ?>
|
||||
invalidHandler: function (form, validator) {
|
||||
|
||||
if (!validator.numberOfInvalids())
|
||||
return;
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: $(validator.errorList[0].element).offset().top
|
||||
}, <?= Config::get('jsvalidation.duration_animate') ?>);
|
||||
|
||||
},
|
||||
<?php endif; ?>
|
||||
|
||||
rules: <?= json_encode($validator['rules']); ?>
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,48 @@
|
||||
<script>
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
$("<?= $validator['selector']; ?>").each(function () {
|
||||
$(this).validate({
|
||||
errorElement: 'div',
|
||||
errorClass: 'invalid-feedback',
|
||||
|
||||
errorPlacement: function (error, element) {
|
||||
error.insertAfter(element);
|
||||
},
|
||||
highlight: function (element) {
|
||||
$(element).removeClass('is-valid').addClass('is-invalid'); // add the Bootstrap error class to the control group
|
||||
},
|
||||
|
||||
<?php if (isset($validator['ignore']) && is_string($validator['ignore'])): ?>
|
||||
|
||||
ignore: "<?= $validator['ignore']; ?>",
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
unhighlight: function (element) {
|
||||
$(element).removeClass('is-invalid').addClass('is-valid');
|
||||
},
|
||||
|
||||
success: function (element) {
|
||||
$(element).removeClass('is-invalid').addClass('is-valid'); // remove the Boostrap error class from the control group
|
||||
},
|
||||
|
||||
focusInvalid: true,
|
||||
<?php if (Config::get('jsvalidation.focus_on_error')): ?>
|
||||
invalidHandler: function (form, validator) {
|
||||
|
||||
if (!validator.numberOfInvalids())
|
||||
return;
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: $(validator.errorList[0].element).offset().top
|
||||
}, <?= Config::get('jsvalidation.duration_animate') ?>);
|
||||
|
||||
},
|
||||
<?php endif; ?>
|
||||
|
||||
rules: <?= json_encode($validator['rules']); ?>
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,55 @@
|
||||
<script>
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
$("<?= $validator['selector']; ?>").each(function () {
|
||||
$(this).validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'uk-text-danger',
|
||||
|
||||
errorPlacement: function (error, element) {
|
||||
if (element.closest('.uk-input').length ||
|
||||
element.closest('.uk-select').length || element.closest('.uk-textarea').length ||
|
||||
element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
|
||||
error.insertAfter(element.parent());
|
||||
// else just place the validation message immediately after the input
|
||||
} else {
|
||||
error.insertAfter(element);
|
||||
}
|
||||
},
|
||||
highlight: function (element) {
|
||||
$(element).closest('.uk-input').removeClass('uk-form-success').addClass('uk-form-danger'); // add the Bootstrap error class to the control group
|
||||
},
|
||||
|
||||
<?php if (isset($validator['ignore']) && is_string($validator['ignore'])): ?>
|
||||
|
||||
ignore: "<?= $validator['ignore']; ?>",
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
unhighlight: function (element) {
|
||||
$(element).closest('.uk-input').removeClass('uk-form-danger').addClass('uk-form-success');
|
||||
},
|
||||
|
||||
success: function (element) {
|
||||
$(element).closest('.uk-input').removeClass('uk-form-danger').addClass('uk-form-success'); // remove the Boostrap error class from the control group
|
||||
},
|
||||
|
||||
focusInvalid: true,
|
||||
<?php if (Config::get('jsvalidation.focus_on_error')): ?>
|
||||
invalidHandler: function (form, validator) {
|
||||
|
||||
if (!validator.numberOfInvalids())
|
||||
return;
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: $(validator.errorList[0].element).offset().top
|
||||
}, <?= Config::get('jsvalidation.duration_animate') ?>);
|
||||
|
||||
},
|
||||
<?php endif; ?>
|
||||
|
||||
rules: <?= json_encode($validator['rules']); ?>
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class PropertyNotFoundException extends Exception
|
||||
{
|
||||
/**
|
||||
* Property Not Found Exception.
|
||||
*
|
||||
* @param string $property
|
||||
* @param string $caller
|
||||
* @param \Exception $previous
|
||||
*/
|
||||
public function __construct($property = '', $caller = '', Exception $previous = null)
|
||||
{
|
||||
$message = "'$property' not found in '$caller'' object";
|
||||
parent::__construct($message, 0, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class JsValidatorFacade extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'jsvalidator';
|
||||
}
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Javascript;
|
||||
|
||||
trait JavascriptRulesTrait
|
||||
{
|
||||
/**
|
||||
* Handles multidimensional attribute names.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getAttributeName($attribute);
|
||||
|
||||
/**
|
||||
* Parse named parameters to $key => $value items.
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
abstract public function parseNamedParameters($parameters);
|
||||
|
||||
/**
|
||||
* Confirmed rule is applied to confirmed attribute.
|
||||
*
|
||||
* @param $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleConfirmed($attribute, array $parameters)
|
||||
{
|
||||
$parameters[0] = $this->getAttributeName($attribute);
|
||||
$attribute = "{$attribute}_confirmation";
|
||||
|
||||
return [$attribute, $parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Javascript parameters for After rule.
|
||||
*
|
||||
* @param $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleAfter($attribute, array $parameters)
|
||||
{
|
||||
if (! ($date = strtotime($parameters[0]))) {
|
||||
$date = $this->getAttributeName($parameters[0]);
|
||||
}
|
||||
|
||||
return [$attribute, [$date]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Javascript parameters for Before rule.
|
||||
*
|
||||
* @param $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleBefore($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleAfter($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that two attributes match.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleSame($attribute, array $parameters)
|
||||
{
|
||||
$other = $this->getAttributeName($parameters[0]);
|
||||
|
||||
return [$attribute, [$other]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute is different from another attribute.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleDifferent($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleSame($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when any other attribute exists.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleRequiredWith($attribute, array $parameters)
|
||||
{
|
||||
$parameters = array_map([$this, 'getAttributeName'], $parameters);
|
||||
|
||||
return [$attribute, $parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when all other attributes exists.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleRequiredWithAll($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleRequiredWith($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when another attribute does not.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleRequiredWithout($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleRequiredWith($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when all other attributes do not.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleRequiredWithoutAll($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleRequiredWith($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when another attribute has a given value.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleRequiredIf($attribute, array $parameters)
|
||||
{
|
||||
$parameters[0] = $this->getAttributeName($parameters[0]);
|
||||
|
||||
return [$attribute, $parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an attribute exists when another attribute does not have a given value.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleRequiredUnless($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleRequiredIf($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the values of an attribute is in another attribute.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleInArray($attribute, array $parameters)
|
||||
{
|
||||
return $this->ruleRequiredIf($attribute, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the dimensions of an image matches the given values.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleDimensions($attribute, $parameters)
|
||||
{
|
||||
$parameters = $this->parseNamedParameters($parameters);
|
||||
|
||||
return [$attribute, $parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an attribute is unique among other values.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function ruleDistinct($attribute, array $parameters)
|
||||
{
|
||||
$parameters[0] = $attribute;
|
||||
|
||||
return $this->ruleRequiredIf($attribute, $parameters);
|
||||
}
|
||||
}
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Javascript;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Proengsoft\JsValidation\Exceptions\PropertyNotFoundException;
|
||||
|
||||
class JavascriptValidator implements Arrayable
|
||||
{
|
||||
/**
|
||||
* Registered validator instance.
|
||||
*
|
||||
* @var ValidatorHandler
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* Selector used in javascript generation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selector;
|
||||
|
||||
/**
|
||||
* View that renders Javascript.
|
||||
*
|
||||
* @var
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Enable or disable remote validations.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $remote;
|
||||
|
||||
/**
|
||||
* 'ignore' option for jQuery Validation Plugin.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $ignore;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ValidatorHandler $validator
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(ValidatorHandler $validator, $options = [])
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->setDefaults($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default parameters.
|
||||
*
|
||||
* @param $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setDefaults($options)
|
||||
{
|
||||
$this->selector = empty($options['selector']) ? 'form' : $options['selector'];
|
||||
$this->view = empty($options['view']) ? 'jsvalidation::bootstrap' : $options['view'];
|
||||
$this->remote = isset($options['remote']) ? $options['remote'] : true;
|
||||
|
||||
if (isset($options['ignore'])) {
|
||||
$this->ignore = $options['ignore'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the specified view with validator data.
|
||||
*
|
||||
* @param null|\Illuminate\Contracts\View\View|string $view
|
||||
* @param null|string $selector
|
||||
* @return string
|
||||
*/
|
||||
public function render($view = null, $selector = null)
|
||||
{
|
||||
$this->view($view);
|
||||
$this->selector($selector);
|
||||
|
||||
return View::make($this->view, ['validator' => $this->getViewData()])
|
||||
->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view data as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->getViewData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string resulting of render default view.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
return $this->render();
|
||||
} catch (Exception $exception) {
|
||||
return trigger_error($exception->__toString(), E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value from view data.
|
||||
*
|
||||
* @param $name
|
||||
* @return string
|
||||
*
|
||||
* @throws \Proengsoft\JsValidation\Exceptions\PropertyNotFoundException
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$data = $this->getViewData();
|
||||
if (! array_key_exists($name, $data)) {
|
||||
throw new PropertyNotFoundException($name, get_class());
|
||||
}
|
||||
|
||||
return $data[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets view data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getViewData()
|
||||
{
|
||||
$this->validator->setRemote($this->remote);
|
||||
$data = $this->validator->validationData();
|
||||
$data['selector'] = $this->selector;
|
||||
|
||||
if (! is_null($this->ignore)) {
|
||||
$data['ignore'] = $this->ignore;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the form selector to validate.
|
||||
*
|
||||
* @param string $selector
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function setSelector($selector)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the form selector to validate.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function selector($selector)
|
||||
{
|
||||
$this->selector = is_null($selector) ? $this->selector : $selector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input selector to ignore for validation.
|
||||
*
|
||||
* @param string $ignore
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function ignore($ignore)
|
||||
{
|
||||
$this->ignore = $ignore;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view to render Javascript Validations.
|
||||
*
|
||||
* @param null|\Illuminate\Contracts\View\View|string $view
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function view($view)
|
||||
{
|
||||
$this->view = is_null($view) ? $this->view : $view;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables remote validations.
|
||||
*
|
||||
* @param null|bool $enabled
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function remote($enabled = true)
|
||||
{
|
||||
$this->remote = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Conditional Validations using Ajax in specified fields.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string|array $rules
|
||||
* @param null $callback Dummy attribute to make API seamless with Laravel sometimes()
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function sometimes($attribute, $rules, $callback = null)
|
||||
{
|
||||
$this->validator->sometimes($attribute, $rules);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Javascript;
|
||||
|
||||
use Proengsoft\JsValidation\JsValidatorFactory;
|
||||
use Proengsoft\JsValidation\Support\DelegatedValidator;
|
||||
use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class MessageParser
|
||||
{
|
||||
use UseDelegatedValidatorTrait;
|
||||
|
||||
/**
|
||||
* Whether to escape messages using htmlentities.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $escape;
|
||||
|
||||
/**
|
||||
* Create a new JsValidation instance.
|
||||
*
|
||||
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
|
||||
* @param bool $escape
|
||||
*/
|
||||
public function __construct(DelegatedValidator $validator, $escape = false)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->escape = $escape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace javascript error message place-holders with actual values.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $rule
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMessage($attribute, $rule, $parameters)
|
||||
{
|
||||
$attribute = str_replace(JsValidatorFactory::ASTERISK, '*', $attribute);
|
||||
|
||||
$data = $this->fakeValidationData($attribute, $rule, $parameters);
|
||||
|
||||
$message = $this->validator->getMessage($attribute, $rule);
|
||||
$message = $this->validator->makeReplacements($message, $attribute, $rule, $parameters);
|
||||
|
||||
$this->validator->setData($data);
|
||||
|
||||
return $this->escape ? e($message) : $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates fake data needed to parse messages
|
||||
* Returns original data.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $rule
|
||||
* @param $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function fakeValidationData($attribute, $rule, $parameters)
|
||||
{
|
||||
$data = $this->validator->getData();
|
||||
|
||||
$this->fakeFileData($data, $attribute);
|
||||
$this->fakeRequiredIfData($data, $rule, $parameters);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate fake data to get RequiredIf message.
|
||||
*
|
||||
* @param $data
|
||||
* @param $rule
|
||||
* @param $parameters
|
||||
* @return void
|
||||
*/
|
||||
private function fakeRequiredIfData($data, $rule, $parameters)
|
||||
{
|
||||
if ($rule !== 'RequiredIf') {
|
||||
return;
|
||||
}
|
||||
|
||||
$newData = $data;
|
||||
$newData[$parameters[0]] = $parameters[1];
|
||||
$this->validator->setData($newData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate fake data to get file type messages.
|
||||
*
|
||||
* @param $data
|
||||
* @param $attribute
|
||||
* @return void
|
||||
*/
|
||||
private function fakeFileData($data, $attribute)
|
||||
{
|
||||
if (! $this->validator->hasRule($attribute, ['Mimes', 'Image'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newFiles = $data;
|
||||
$newFiles[$attribute] = $this->createUploadedFile();
|
||||
$this->validator->setData($newFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create fake UploadedFile to generate file messages.
|
||||
*
|
||||
* @return UploadedFile
|
||||
*/
|
||||
protected function createUploadedFile()
|
||||
{
|
||||
return new UploadedFile('fakefile', 'fakefile', null, UPLOAD_ERR_NO_FILE, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Javascript;
|
||||
|
||||
use Proengsoft\JsValidation\JsValidatorFactory;
|
||||
use Proengsoft\JsValidation\Support\DelegatedValidator;
|
||||
use Proengsoft\JsValidation\Support\RuleListTrait;
|
||||
use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait;
|
||||
|
||||
class RuleParser
|
||||
{
|
||||
use JavascriptRulesTrait;
|
||||
use RuleListTrait;
|
||||
use UseDelegatedValidatorTrait;
|
||||
|
||||
/**
|
||||
* Dummy Laravel validation rule for form requests.
|
||||
*/
|
||||
const FORM_REQUEST_RULE_NAME = 'ProengsoftFormRequest';
|
||||
|
||||
/**
|
||||
* Js validation rule used to validate form requests.
|
||||
*/
|
||||
const FORM_REQUEST_RULE = 'laravelValidationFormRequest';
|
||||
|
||||
/**
|
||||
* Rule used to validate remote requests.
|
||||
*/
|
||||
const REMOTE_RULE = 'laravelValidationRemote';
|
||||
|
||||
/**
|
||||
* Rule used to validate javascript fields.
|
||||
*/
|
||||
const JAVASCRIPT_RULE = 'laravelValidation';
|
||||
|
||||
/**
|
||||
* Token used to secure romte validations.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
protected $remoteToken;
|
||||
|
||||
/**
|
||||
* Conditional Validations.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conditional = [];
|
||||
|
||||
/**
|
||||
* Create a new JsValidation instance.
|
||||
*
|
||||
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
|
||||
* @param null|string $remoteToken
|
||||
*/
|
||||
public function __construct(DelegatedValidator $validator, $remoteToken = null)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->remoteToken = $remoteToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return parsed Javascript Rule.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $rule
|
||||
* @param $parameters
|
||||
* @param $rawRule
|
||||
* @return array
|
||||
*/
|
||||
public function getRule($attribute, $rule, $parameters, $rawRule)
|
||||
{
|
||||
$isConditional = $this->isConditionalRule($attribute, $rawRule);
|
||||
$isRemote = $this->isRemoteRule($rule);
|
||||
$isFormRequest = $this->isFormRequestRule($rule);
|
||||
|
||||
if ($isFormRequest || $isConditional || $isRemote) {
|
||||
[$attribute, $parameters] = $this->remoteRule($attribute, $isConditional);
|
||||
$jsRule = $isFormRequest ? static::FORM_REQUEST_RULE : static::REMOTE_RULE;
|
||||
} else {
|
||||
[$jsRule, $attribute, $parameters] = $this->clientRule($attribute, $rule, $parameters);
|
||||
}
|
||||
|
||||
$attribute = $this->getAttributeName($attribute);
|
||||
|
||||
return [$attribute, $jsRule, $parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets rules from Validator instance.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValidatorRules()
|
||||
{
|
||||
return $this->validator->getRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add conditional rules.
|
||||
*
|
||||
* @param mixed $attribute
|
||||
* @param array $rules
|
||||
* @return void
|
||||
*/
|
||||
public function addConditionalRules($attribute, $rules = [])
|
||||
{
|
||||
foreach ((array) $attribute as $key) {
|
||||
$current = isset($this->conditional[$key]) ? $this->conditional[$key] : [];
|
||||
$merge = head($this->validator->explodeRules((array) $rules));
|
||||
$this->conditional[$key] = array_merge($current, $merge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if rule is passed with sometimes.
|
||||
*
|
||||
* @param mixed $attribute
|
||||
* @param string $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function isConditionalRule($attribute, $rule)
|
||||
{
|
||||
return isset($this->conditional[$attribute])
|
||||
&& in_array($rule, $this->conditional[$attribute]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Javascript parameters for remote validated rules.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $rule
|
||||
* @param $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function clientRule($attribute, $rule, $parameters)
|
||||
{
|
||||
$jsRule = self::JAVASCRIPT_RULE;
|
||||
$method = "rule{$rule}";
|
||||
|
||||
if (method_exists($this, $method)) {
|
||||
[$attribute, $parameters] = $this->$method($attribute, $parameters);
|
||||
}
|
||||
|
||||
return [$jsRule, $attribute, $parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Javascript parameters for remote validated rules.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param bool $forceRemote
|
||||
* @return array
|
||||
*/
|
||||
protected function remoteRule($attribute, $forceRemote)
|
||||
{
|
||||
$attrHtmlName = $this->getAttributeName($attribute);
|
||||
$params = [
|
||||
$attrHtmlName,
|
||||
$this->remoteToken,
|
||||
$forceRemote,
|
||||
];
|
||||
|
||||
return [$attribute, $params];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles multidimensional attribute names.
|
||||
*
|
||||
* @param mixed $attribute
|
||||
* @return string
|
||||
*/
|
||||
protected function getAttributeName($attribute)
|
||||
{
|
||||
$attribute = str_replace(JsValidatorFactory::ASTERISK, '*', $attribute);
|
||||
|
||||
$attributeArray = explode('.', $attribute);
|
||||
if (count($attributeArray) > 1) {
|
||||
return $attributeArray[0].'['.implode('][', array_slice($attributeArray, 1)).']';
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse named parameters to $key => $value items.
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return array
|
||||
*/
|
||||
public function parseNamedParameters($parameters)
|
||||
{
|
||||
return array_reduce($parameters, function ($result, $item) {
|
||||
[$key, $value] = array_pad(explode('=', $item, 2), 2, null);
|
||||
|
||||
$result[$key] = $value;
|
||||
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Javascript;
|
||||
|
||||
use Proengsoft\JsValidation\Support\DelegatedValidator;
|
||||
use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait;
|
||||
|
||||
class ValidatorHandler
|
||||
{
|
||||
use UseDelegatedValidatorTrait;
|
||||
|
||||
/**
|
||||
* Rule used to disable validations.
|
||||
*
|
||||
* @const string
|
||||
*/
|
||||
const JSVALIDATION_DISABLE = 'NoJsValidation';
|
||||
|
||||
/**
|
||||
* @var RuleParser
|
||||
*/
|
||||
protected $rules;
|
||||
/**
|
||||
* @var MessageParser
|
||||
*/
|
||||
protected $messages;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $remote = true;
|
||||
|
||||
/**
|
||||
* Create a new JsValidation instance.
|
||||
*
|
||||
* @param RuleParser $rules
|
||||
* @param MessageParser $messages
|
||||
*/
|
||||
public function __construct(RuleParser $rules, MessageParser $messages)
|
||||
{
|
||||
$this->rules = $rules;
|
||||
$this->messages = $messages;
|
||||
$this->validator = $rules->getDelegatedValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets delegated Validator instance.
|
||||
*
|
||||
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
|
||||
* @return void
|
||||
*/
|
||||
public function setDelegatedValidator(DelegatedValidator $validator)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->rules->setDelegatedValidator($validator);
|
||||
$this->messages->setDelegatedValidator($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disables remote validations.
|
||||
*
|
||||
* @param bool $enabled
|
||||
* @return void
|
||||
*/
|
||||
public function setRemote($enabled)
|
||||
{
|
||||
$this->remote = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Javascript Validations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function generateJavascriptValidations()
|
||||
{
|
||||
$jsValidations = [];
|
||||
|
||||
foreach ($this->validator->getRules() as $attribute => $rules) {
|
||||
if (! $this->jsValidationEnabled($attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newRules = $this->jsConvertRules($attribute, $rules, $this->remote);
|
||||
$jsValidations = array_merge($jsValidations, $newRules);
|
||||
}
|
||||
|
||||
return $jsValidations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make Laravel Validations compatible with JQuery Validation Plugin.
|
||||
*
|
||||
* @param $attribute
|
||||
* @param $rules
|
||||
* @param bool $includeRemote
|
||||
* @return array
|
||||
*/
|
||||
protected function jsConvertRules($attribute, $rules, $includeRemote)
|
||||
{
|
||||
$jsRules = [];
|
||||
foreach ($rules as $rawRule) {
|
||||
[$rule, $parameters] = $this->validator->parseRule($rawRule);
|
||||
[$jsAttribute, $jsRule, $jsParams] = $this->rules->getRule($attribute, $rule, $parameters, $rawRule);
|
||||
if ($this->isValidatable($jsRule, $includeRemote)) {
|
||||
$jsRules[$jsAttribute][$jsRule][] = [
|
||||
$rule,
|
||||
$jsParams,
|
||||
$this->messages->getMessage($attribute, $rule, $parameters),
|
||||
$this->validator->isImplicit($rule),
|
||||
$jsAttribute,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $jsRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if rule should be validated with javascript.
|
||||
*
|
||||
* @param $jsRule
|
||||
* @param bool $includeRemote
|
||||
* @return bool
|
||||
*/
|
||||
protected function isValidatable($jsRule, $includeRemote)
|
||||
{
|
||||
return $jsRule && ($includeRemote || $jsRule !== RuleParser::REMOTE_RULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if JS Validation is disabled for attribute.
|
||||
*
|
||||
* @param $attribute
|
||||
* @return bool
|
||||
*/
|
||||
public function jsValidationEnabled($attribute)
|
||||
{
|
||||
return ! $this->validator->hasRule($attribute, self::JSVALIDATION_DISABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns view data to render javascript.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validationData()
|
||||
{
|
||||
$jsMessages = [];
|
||||
$jsValidations = $this->generateJavascriptValidations();
|
||||
|
||||
return [
|
||||
'rules' => $jsValidations,
|
||||
'messages' => $jsMessages,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Conditional Validations using Ajax in specified fields.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string|array $rules
|
||||
* @return void
|
||||
*/
|
||||
public function sometimes($attribute, $rules = [])
|
||||
{
|
||||
$callback = function () {
|
||||
return true;
|
||||
};
|
||||
$this->validator->sometimes($attribute, $rules, $callback);
|
||||
$this->rules->addConditionalRules($attribute, (array) $rules);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation;
|
||||
|
||||
use Illuminate\Contracts\Http\Kernel;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Proengsoft\JsValidation\Javascript\ValidatorHandler;
|
||||
|
||||
class JsValidationServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->bootstrapConfigs();
|
||||
$this->bootstrapViews();
|
||||
$this->bootstrapValidator();
|
||||
$this->publishAssets();
|
||||
|
||||
if ($this->app['config']->get('jsvalidation.disable_remote_validation') === false) {
|
||||
$this->app[Kernel::class]->pushMiddleware(RemoteValidationMiddleware::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton('jsvalidator', function ($app) {
|
||||
$config = $app['config']->get('jsvalidation');
|
||||
|
||||
return new JsValidatorFactory($app, $config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure and publish views.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function bootstrapViews()
|
||||
{
|
||||
$viewPath = realpath(__DIR__.'/../resources/views');
|
||||
|
||||
$this->loadViewsFrom($viewPath, 'jsvalidation');
|
||||
$this->publishes([
|
||||
$viewPath => $this->app['path.base'].'/resources/views/vendor/jsvalidation',
|
||||
], 'views');
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure Laravel Validator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function bootstrapValidator()
|
||||
{
|
||||
$callback = function () {
|
||||
return true;
|
||||
};
|
||||
$this->app['validator']->extend(ValidatorHandler::JSVALIDATION_DISABLE, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and publishes configs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function bootstrapConfigs()
|
||||
{
|
||||
$configFile = realpath(__DIR__.'/../config/jsvalidation.php');
|
||||
|
||||
$this->mergeConfigFrom($configFile, 'jsvalidation');
|
||||
$this->publishes([$configFile => $this->app['path.config'].'/jsvalidation.php'], 'config');
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish public assets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function publishAssets()
|
||||
{
|
||||
$this->publishes([
|
||||
realpath(__DIR__.'/../public') => $this->app['path.public'].'/vendor/jsvalidation',
|
||||
], 'public');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation;
|
||||
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Illuminate\Foundation\Http\FormRequest as IlluminateFormRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Proengsoft\JsValidation\Javascript\JavascriptValidator;
|
||||
use Proengsoft\JsValidation\Javascript\MessageParser;
|
||||
use Proengsoft\JsValidation\Javascript\RuleParser;
|
||||
use Proengsoft\JsValidation\Javascript\ValidatorHandler;
|
||||
use Proengsoft\JsValidation\Remote\FormRequest;
|
||||
use Proengsoft\JsValidation\Support\DelegatedValidator;
|
||||
use Proengsoft\JsValidation\Support\ValidationRuleParserProxy;
|
||||
|
||||
class JsValidatorFactory
|
||||
{
|
||||
const ASTERISK = '__asterisk__';
|
||||
|
||||
/**
|
||||
* The application instance.
|
||||
*
|
||||
* @var \Illuminate\Container\Container
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* Configuration options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Create a new Validator factory instance.
|
||||
*
|
||||
* @param \Illuminate\Container\Container $app
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($app, array $options = [])
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $options
|
||||
* @return void
|
||||
*/
|
||||
protected function setOptions($options)
|
||||
{
|
||||
$options['disable_remote_validation'] = empty($options['disable_remote_validation']) ? false : $options['disable_remote_validation'];
|
||||
$options['view'] = empty($options['view']) ? 'jsvalidation:bootstrap' : $options['view'];
|
||||
$options['form_selector'] = empty($options['form_selector']) ? 'form' : $options['form_selector'];
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates JsValidator instance based on rules and message arrays.
|
||||
*
|
||||
* @param array $rules
|
||||
* @param array $messages
|
||||
* @param array $customAttributes
|
||||
* @param null|string $selector
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function make(array $rules, array $messages = [], array $customAttributes = [], $selector = null)
|
||||
{
|
||||
$validator = $this->getValidatorInstance($rules, $messages, $customAttributes);
|
||||
|
||||
return $this->validator($validator, $selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validator instance for the request.
|
||||
*
|
||||
* @param array $rules
|
||||
* @param array $messages
|
||||
* @param array $customAttributes
|
||||
* @return \Illuminate\Validation\Validator
|
||||
*/
|
||||
protected function getValidatorInstance(array $rules, array $messages = [], array $customAttributes = [])
|
||||
{
|
||||
$factory = $this->app->make(ValidationFactory::class);
|
||||
|
||||
$data = $this->getValidationData($rules, $customAttributes);
|
||||
$validator = $factory->make($data, $rules, $messages, $customAttributes);
|
||||
$validator->addCustomAttributes($customAttributes);
|
||||
|
||||
return $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fake data when validator has wildcard rules.
|
||||
*
|
||||
* @param array $rules
|
||||
* @param array $customAttributes
|
||||
* @return array
|
||||
*/
|
||||
protected function getValidationData(array $rules, array $customAttributes = [])
|
||||
{
|
||||
$attributes = array_filter(array_keys($rules), function ($attribute) {
|
||||
return $attribute !== '' && mb_strpos($attribute, '*') !== false;
|
||||
});
|
||||
|
||||
$attributes = array_merge(array_keys($customAttributes), $attributes);
|
||||
$data = array_reduce($attributes, function ($data, $attribute) {
|
||||
// Prevent wildcard rule being removed as an implicit attribute (not present in the data).
|
||||
$attribute = str_replace('*', self::ASTERISK, $attribute);
|
||||
|
||||
Arr::set($data, $attribute, true);
|
||||
|
||||
return $data;
|
||||
}, []);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates JsValidator instance based on FormRequest.
|
||||
*
|
||||
* @param $formRequest
|
||||
* @param null|string $selector
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function formRequest($formRequest, $selector = null)
|
||||
{
|
||||
if (! is_object($formRequest)) {
|
||||
$formRequest = $this->createFormRequest($formRequest);
|
||||
}
|
||||
|
||||
if ($formRequest instanceof FormRequest) {
|
||||
return $this->newFormRequestValidator($formRequest, $selector);
|
||||
}
|
||||
|
||||
return $this->oldFormRequestValidator($formRequest, $selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create form request validator.
|
||||
*
|
||||
* @param FormRequest $formRequest
|
||||
* @param string $selector
|
||||
* @return JavascriptValidator
|
||||
*/
|
||||
private function newFormRequestValidator($formRequest, $selector)
|
||||
{
|
||||
// Replace all rules with Noop rules which are checked client-side and always valid to true.
|
||||
// This is important because jquery-validation expects fields under validation to have rules present. For
|
||||
// example, if you mark a field as invalid without a defined rule, then unhighlight won't be called.
|
||||
$rules = method_exists($formRequest, 'rules') ? $formRequest->rules() : [];
|
||||
foreach ($rules as $key => $value) {
|
||||
$rules[$key] = 'proengsoft_noop';
|
||||
}
|
||||
|
||||
// This rule controls AJAX validation of all fields.
|
||||
$rules['proengsoft_jsvalidation'] = RuleParser::FORM_REQUEST_RULE_NAME;
|
||||
|
||||
$baseValidator = $this->getValidatorInstance($rules);
|
||||
|
||||
return $this->validator($baseValidator, $selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a form request validator instance.
|
||||
*
|
||||
* @param IlluminateFormRequest $formRequest
|
||||
* @param string $selector
|
||||
* @return JavascriptValidator
|
||||
*/
|
||||
private function oldFormRequestValidator($formRequest, $selector)
|
||||
{
|
||||
$rules = method_exists($formRequest, 'rules') ? $this->app->call([$formRequest, 'rules']) : [];
|
||||
|
||||
$validator = $this->getValidatorInstance($rules, $formRequest->messages(), $formRequest->attributes());
|
||||
|
||||
$jsValidator = $this->validator($validator, $selector);
|
||||
|
||||
if (method_exists($formRequest, 'withJsValidator')) {
|
||||
$formRequest->withJsValidator($jsValidator);
|
||||
}
|
||||
|
||||
return $jsValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $class
|
||||
* @return array
|
||||
*/
|
||||
protected function parseFormRequestName($class)
|
||||
{
|
||||
$params = [];
|
||||
if (is_array($class)) {
|
||||
$params = empty($class[1]) ? $params : $class[1];
|
||||
$class = $class[0];
|
||||
}
|
||||
|
||||
return [$class, $params];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and initializes an Form Request instance.
|
||||
*
|
||||
* @param string $class
|
||||
* @return IlluminateFormRequest
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
protected function createFormRequest($class)
|
||||
{
|
||||
/*
|
||||
* @var $formRequest \Illuminate\Foundation\Http\FormRequest
|
||||
* @var $request Request
|
||||
*/
|
||||
[$class, $params] = $this->parseFormRequestName($class);
|
||||
|
||||
$request = $this->app->__get('request');
|
||||
$formRequest = $this->app->build($class, $params);
|
||||
|
||||
if ($request->hasSession() && $session = $request->session()) {
|
||||
$formRequest->setLaravelSession($session);
|
||||
}
|
||||
$formRequest->setUserResolver($request->getUserResolver());
|
||||
$formRequest->setRouteResolver($request->getRouteResolver());
|
||||
$formRequest->setContainer($this->app);
|
||||
$formRequest->query = $request->query;
|
||||
|
||||
return $formRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates JsValidator instance based on Validator.
|
||||
*
|
||||
* @param \Illuminate\Validation\Validator $validator
|
||||
* @param null|string $selector
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
public function validator(Validator $validator, $selector = null)
|
||||
{
|
||||
return $this->jsValidator($validator, $selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates JsValidator instance based on Validator.
|
||||
*
|
||||
* @param \Illuminate\Validation\Validator $validator
|
||||
* @param null|string $selector
|
||||
* @return \Proengsoft\JsValidation\Javascript\JavascriptValidator
|
||||
*/
|
||||
protected function jsValidator(Validator $validator, $selector = null)
|
||||
{
|
||||
$remote = ! $this->options['disable_remote_validation'];
|
||||
$view = $this->options['view'];
|
||||
$selector = is_null($selector) ? $this->options['form_selector'] : $selector;
|
||||
$ignore = $this->options['ignore'];
|
||||
|
||||
$delegated = new DelegatedValidator($validator, new ValidationRuleParserProxy($validator->getData()));
|
||||
$rules = new RuleParser($delegated, $this->getSessionToken());
|
||||
$messages = new MessageParser($delegated, isset($this->options['escape']) ? $this->options['escape'] : false);
|
||||
|
||||
$jsValidator = new ValidatorHandler($rules, $messages);
|
||||
|
||||
return new JavascriptValidator($jsValidator, compact('view', 'selector', 'remote', 'ignore'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and encrypt token from session store.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getSessionToken()
|
||||
{
|
||||
$token = null;
|
||||
if ($session = $this->app->__get('session')) {
|
||||
$token = $session->token();
|
||||
}
|
||||
|
||||
if ($encrypter = $this->app->__get('encrypter')) {
|
||||
$token = $encrypter->encrypt($token);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Remote;
|
||||
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Foundation\Http\FormRequest as Request;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class FormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Field to identify requests originating from this library.
|
||||
*/
|
||||
const JS_VALIDATION_FIELD = '__proengsoft_form_request';
|
||||
|
||||
/**
|
||||
* Validate the class instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function validateResolved()
|
||||
{
|
||||
parent::validateResolved();
|
||||
|
||||
// BC for Laravel versions prior to 6.x.
|
||||
$this->passedValidation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a passed validation attempt.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function passedValidation()
|
||||
{
|
||||
if ($this->isJsValidation()) {
|
||||
throw new HttpResponseException(
|
||||
new JsonResponse(true, 200)
|
||||
);
|
||||
}
|
||||
|
||||
parent::passedValidation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a failed validation attempt.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Validation\Validator $validator
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
protected function failedValidation(Validator $validator)
|
||||
{
|
||||
if ($this->isJsValidation()) {
|
||||
throw new ValidationException(
|
||||
$validator,
|
||||
new JsonResponse($validator->errors()->messages(), 200)
|
||||
);
|
||||
}
|
||||
|
||||
parent::failedValidation($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the request originated from laravel-jsvalidation.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isJsValidation()
|
||||
{
|
||||
return $this->has(static::JS_VALIDATION_FIELD);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Remote;
|
||||
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\Validator as BaseValidator;
|
||||
use Proengsoft\JsValidation\Support\AccessProtectedTrait;
|
||||
|
||||
class Resolver
|
||||
{
|
||||
use AccessProtectedTrait;
|
||||
|
||||
/**
|
||||
* @var \Closure
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Validation\Factory
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
/**
|
||||
* Whether to escape validation messages.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $escape;
|
||||
|
||||
/**
|
||||
* RemoteValidator constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Validation\Factory $factory
|
||||
* @param bool $escape
|
||||
*/
|
||||
public function __construct(ValidationFactory $factory, $escape = false)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->resolver = $this->getProtected($factory, 'resolver');
|
||||
$this->escape = $escape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closure used to resolve Validator instance.
|
||||
*
|
||||
* @param $field
|
||||
* @return \Closure
|
||||
*/
|
||||
public function resolver($field)
|
||||
{
|
||||
return function ($translator, $data, $rules, $messages, $customAttributes) use ($field) {
|
||||
return $this->resolve($translator, $data, $rules, $messages, $customAttributes, $field);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves Validator instance.
|
||||
*
|
||||
* @param $translator
|
||||
* @param $data
|
||||
* @param $rules
|
||||
* @param $messages
|
||||
* @param $customAttributes
|
||||
* @param $field
|
||||
* @return \Illuminate\Validation\Validator
|
||||
*/
|
||||
protected function resolve($translator, $data, $rules, $messages, $customAttributes, $field)
|
||||
{
|
||||
$validateAll = Arr::get($data, $field.'_validate_all', false);
|
||||
$validationRule = 'bail|'.Validator::EXTENSION_NAME.':'.$validateAll;
|
||||
$rules = [$field => $validationRule] + $rules;
|
||||
$validator = $this->createValidator($translator, $data, $rules, $messages, $customAttributes);
|
||||
|
||||
return $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new validator instance.
|
||||
*
|
||||
* @param $translator
|
||||
* @param $data
|
||||
* @param $rules
|
||||
* @param $messages
|
||||
* @param $customAttributes
|
||||
* @return \Illuminate\Validation\Validator
|
||||
*/
|
||||
protected function createValidator($translator, $data, $rules, $messages, $customAttributes)
|
||||
{
|
||||
if (is_null($this->resolver)) {
|
||||
return new BaseValidator($translator, $data, $rules, $messages, $customAttributes);
|
||||
}
|
||||
|
||||
return call_user_func($this->resolver, $translator, $data, $rules, $messages, $customAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closure used to trigger JsValidations.
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
public function validatorClosure()
|
||||
{
|
||||
return function ($attribute, $value, $parameters, BaseValidator $validator) {
|
||||
$remoteValidator = new Validator($validator, $this->escape);
|
||||
$remoteValidator->validate($value, $parameters);
|
||||
|
||||
return $attribute;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Remote;
|
||||
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Validation\ValidationRuleParser;
|
||||
use Illuminate\Validation\Validator as BaseValidator;
|
||||
use Proengsoft\JsValidation\Support\AccessProtectedTrait;
|
||||
use Proengsoft\JsValidation\Support\RuleListTrait;
|
||||
|
||||
class Validator
|
||||
{
|
||||
use AccessProtectedTrait;
|
||||
use RuleListTrait;
|
||||
|
||||
/**
|
||||
* Validator extension name.
|
||||
*/
|
||||
const EXTENSION_NAME = 'jsvalidation';
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Validation\Validator
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* Whether to escape validation messages.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $escape;
|
||||
|
||||
/**
|
||||
* RemoteValidator constructor.
|
||||
*
|
||||
* @param \Illuminate\Validation\Validator $validator
|
||||
* @param bool $escape
|
||||
*/
|
||||
public function __construct(BaseValidator $validator, $escape = false)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->escape = $escape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate request.
|
||||
*
|
||||
* @param $field
|
||||
* @param $parameters
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function validate($field, $parameters = [])
|
||||
{
|
||||
$attribute = $this->parseAttributeName($field);
|
||||
$validationParams = $this->parseParameters($parameters);
|
||||
$validationResult = $this->validateJsRemoteRequest($attribute, $validationParams);
|
||||
|
||||
$this->throwValidationException($validationResult, $this->validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw the failed validation exception.
|
||||
*
|
||||
* @param mixed $result
|
||||
* @param \Illuminate\Validation\Validator $validator
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException|\Illuminate\Http\Exceptions\HttpResponseException
|
||||
*/
|
||||
protected function throwValidationException($result, $validator)
|
||||
{
|
||||
$response = new JsonResponse($result, 200);
|
||||
|
||||
if ($result !== true && class_exists(ValidationException::class)) {
|
||||
throw new ValidationException($validator, $response);
|
||||
}
|
||||
|
||||
throw new HttpResponseException($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Validation input request data.
|
||||
*
|
||||
* @param $data
|
||||
* @return array
|
||||
*/
|
||||
protected function parseAttributeName($data)
|
||||
{
|
||||
parse_str($data, $attrParts);
|
||||
$attrParts = is_null($attrParts) ? [] : $attrParts;
|
||||
$newAttr = array_keys(Arr::dot($attrParts));
|
||||
|
||||
return array_pop($newAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Validation parameters.
|
||||
*
|
||||
* @param $parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function parseParameters($parameters)
|
||||
{
|
||||
$newParams = ['validate_all' => false];
|
||||
if (isset($parameters[0])) {
|
||||
$newParams['validate_all'] = ($parameters[0] === 'true') ? true : false;
|
||||
}
|
||||
|
||||
return $newParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate remote Javascript Validations.
|
||||
*
|
||||
* @param $attribute
|
||||
* @param array $parameters
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function validateJsRemoteRequest($attribute, $parameters)
|
||||
{
|
||||
$this->setRemoteValidation($attribute, $parameters['validate_all']);
|
||||
|
||||
$validator = $this->validator;
|
||||
if ($validator->passes()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$messages = $validator->messages()->get($attribute);
|
||||
|
||||
if ($this->escape) {
|
||||
foreach ($messages as $key => $value) {
|
||||
$messages[$key] = e($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data for validate remote rules.
|
||||
*
|
||||
* @param $attribute
|
||||
* @param bool $validateAll
|
||||
* @return void
|
||||
*/
|
||||
protected function setRemoteValidation($attribute, $validateAll = false)
|
||||
{
|
||||
$validator = $this->validator;
|
||||
$rules = $validator->getRules();
|
||||
$rules = isset($rules[$attribute]) ? $rules[$attribute] : [];
|
||||
if (in_array('no_js_validation', $rules)) {
|
||||
$validator->setRules([$attribute => []]);
|
||||
|
||||
return;
|
||||
}
|
||||
if (! $validateAll) {
|
||||
$rules = $this->purgeNonRemoteRules($rules, $validator);
|
||||
}
|
||||
$validator->setRules([$attribute => $rules]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove rules that should not be validated remotely.
|
||||
*
|
||||
* @param $rules
|
||||
* @param BaseValidator $validator
|
||||
* @return mixed
|
||||
*/
|
||||
protected function purgeNonRemoteRules($rules, $validator)
|
||||
{
|
||||
$protectedValidator = $this->createProtectedCaller($validator);
|
||||
|
||||
foreach ($rules as $i => $rule) {
|
||||
$parsedRule = ValidationRuleParser::parse($rule);
|
||||
if (! $this->isRemoteRule($parsedRule[0])) {
|
||||
unset($rules[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Config\Repository as Config;
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Illuminate\Http\Request;
|
||||
use Proengsoft\JsValidation\Remote\Resolver;
|
||||
use Proengsoft\JsValidation\Remote\Validator as RemoteValidator;
|
||||
|
||||
class RemoteValidationMiddleware
|
||||
{
|
||||
/**
|
||||
* Validator factory instance to wrap.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Validation\Factory
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
/**
|
||||
* Field used to detect Javascript validation.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* Whether to escape messages or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $escape;
|
||||
|
||||
/**
|
||||
* RemoteValidationMiddleware constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Validation\Factory $validator
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
*/
|
||||
public function __construct(ValidationFactory $validator, Config $config)
|
||||
{
|
||||
$this->factory = $validator;
|
||||
$this->field = $config->get('jsvalidation.remote_validation_field');
|
||||
$this->escape = (bool) $config->get('jsvalidation.escape', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($request->has($this->field)) {
|
||||
$this->wrapValidator();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps Validator resolver with RemoteValidator resolver.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function wrapValidator()
|
||||
{
|
||||
$resolver = new Resolver($this->factory, $this->escape);
|
||||
$this->factory->resolver($resolver->resolver($this->field));
|
||||
$this->factory->extend(RemoteValidator::EXTENSION_NAME, $resolver->validatorClosure());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Support;
|
||||
|
||||
use Closure;
|
||||
|
||||
trait AccessProtectedTrait
|
||||
{
|
||||
/**
|
||||
* Create closure to call inaccessible method.
|
||||
*
|
||||
* @param $instance
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function createProtectedCaller($instance)
|
||||
{
|
||||
$closure = function ($method, $args) {
|
||||
$callable = [$this, $method];
|
||||
|
||||
return call_user_func_array($callable, $args);
|
||||
};
|
||||
|
||||
return $closure->bindTo($instance, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets inaccessible property.
|
||||
*
|
||||
* @param $instance
|
||||
* @param $property
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getProtected($instance, $property)
|
||||
{
|
||||
$closure = function ($property) {
|
||||
return $this->$property;
|
||||
};
|
||||
$callback = $closure->bindTo($instance, $instance);
|
||||
|
||||
return $callback($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls inaccessible method.
|
||||
*
|
||||
* @param object|\Closure $instance
|
||||
* @param $method
|
||||
* @param $args
|
||||
* @return mixed
|
||||
*/
|
||||
protected function callProtected($instance, $method, $args = [])
|
||||
{
|
||||
if (! ($instance instanceof Closure)) {
|
||||
$instance = $this->createProtectedCaller($instance);
|
||||
}
|
||||
|
||||
return call_user_func($instance, $method, $args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Support;
|
||||
|
||||
use Illuminate\Validation\Validator as BaseValidator;
|
||||
|
||||
class DelegatedValidator
|
||||
{
|
||||
use AccessProtectedTrait;
|
||||
|
||||
/**
|
||||
* The Validator resolved instance.
|
||||
*
|
||||
* @var \Illuminate\Validation\Validator
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* Validation rule parser instance.
|
||||
*
|
||||
* @var \Proengsoft\JsValidation\Support\ValidationRuleParserProxy
|
||||
*/
|
||||
protected $ruleParser;
|
||||
|
||||
/**
|
||||
* Closure to invoke non accessible Validator methods.
|
||||
*
|
||||
* @var \Closure
|
||||
*/
|
||||
protected $validatorMethod;
|
||||
|
||||
/**
|
||||
* DelegatedValidator constructor.
|
||||
*
|
||||
* @param \Illuminate\Validation\Validator $validator
|
||||
* @param \Proengsoft\JsValidation\Support\ValidationRuleParserProxy $ruleParser
|
||||
*/
|
||||
public function __construct(BaseValidator $validator, ValidationRuleParserProxy $ruleParser)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->ruleParser = $ruleParser;
|
||||
$this->validatorMethod = $this->createProtectedCaller($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call validator method.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
private function callValidator($method, $args = [])
|
||||
{
|
||||
return $this->callProtected($this->validatorMethod, $method, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current \Illuminate\Validation\Validator instance.
|
||||
*
|
||||
* @return \Illuminate\Validation\Validator
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data under validation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->validator->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data under validation.
|
||||
*
|
||||
* @param array
|
||||
*/
|
||||
public function setData($data)
|
||||
{
|
||||
$rules = $this->validator->getRules();
|
||||
$this->validator->setData($data);
|
||||
if (is_array($rules)) {
|
||||
$this->validator->setRules($rules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRules()
|
||||
{
|
||||
return $this->validator->getRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given rule implies the attribute is required.
|
||||
*
|
||||
* @param string $rule
|
||||
* @return bool
|
||||
*/
|
||||
public function isImplicit($rule)
|
||||
{
|
||||
return $this->callValidator('isImplicit', [$rule]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all error message place-holders with actual values.
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $attribute
|
||||
* @param string $rule
|
||||
* @param array $parameters
|
||||
* @return string
|
||||
*/
|
||||
public function makeReplacements($message, $attribute, $rule, $parameters)
|
||||
{
|
||||
if (is_object($rule)) {
|
||||
$rule = get_class($rule);
|
||||
}
|
||||
|
||||
return $this->callValidator('makeReplacements', [$message, $attribute, $rule, $parameters]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given attribute has a rule in the given set.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string|array $rules
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRule($attribute, $rules)
|
||||
{
|
||||
return $this->callValidator('hasRule', [$attribute, $rules]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation message for an attribute and rule.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string $rule
|
||||
* @return string
|
||||
*/
|
||||
public function getMessage($attribute, $rule)
|
||||
{
|
||||
if (is_object($rule)) {
|
||||
$rule = get_class($rule);
|
||||
}
|
||||
|
||||
return $this->callValidator('getMessage', [$attribute, $rule]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the rule name and parameters from a rule.
|
||||
*
|
||||
* @param array|string $rules
|
||||
* @return array
|
||||
*/
|
||||
public function parseRule($rules)
|
||||
{
|
||||
return $this->ruleParser->parse($rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode the rules into an array of rules.
|
||||
*
|
||||
* @param string|array $rules
|
||||
* @return array
|
||||
*/
|
||||
public function explodeRules($rules)
|
||||
{
|
||||
return $this->ruleParser->explodeRules($rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add conditions to a given field based on a Closure.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param string|array $rules
|
||||
* @param callable $callback
|
||||
* @return void
|
||||
*/
|
||||
public function sometimes($attribute, $rules, callable $callback)
|
||||
{
|
||||
$this->validator->sometimes($attribute, $rules, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate method calls to validator instance.
|
||||
*
|
||||
* @param $method
|
||||
* @param $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $params)
|
||||
{
|
||||
$arrCaller = [$this->validator, $method];
|
||||
|
||||
return call_user_func_array($arrCaller, $params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Support;
|
||||
|
||||
use Proengsoft\JsValidation\Javascript\RuleParser;
|
||||
|
||||
trait RuleListTrait
|
||||
{
|
||||
/**
|
||||
* Rules validated with Javascript.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $clientRules = [
|
||||
'Accepted', 'After', 'AfterOrEqual', 'Alpha', 'AlphaDash',
|
||||
'AlphaNum', 'Array', 'Bail', 'Before', 'BeforeOrEqual', 'Between', 'Boolean', 'Confirmed', 'Date', 'Dimensions',
|
||||
'DateFormat', 'Different', 'Digits', 'DigitsBetween', 'Distinct', 'Email', 'File', 'Filled', 'Image',
|
||||
'In', 'InArray', 'Integer', 'Ip', 'Json', 'Max', 'Mimes', 'Mimetypes', 'Min', 'NotIn', 'Nullable',
|
||||
'Numeric', 'Regex', 'Required', 'RequiredIf', 'RequiredUnless', 'RequiredWith', 'RequiredWithAll',
|
||||
'RequiredWithout', 'RequiredWithoutAll', 'Same', 'Size', 'Sometimes',
|
||||
'String', 'Timezone', 'ProengsoftNoop',
|
||||
];
|
||||
|
||||
/**
|
||||
* Rules validated in Server-Side.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $serverRules = ['ActiveUrl', 'Exists', 'Unique', 'Url'];
|
||||
|
||||
/**
|
||||
* Rules applyed to files.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fileRules = ['File', 'Image', 'Mimes', 'Mimetypes'];
|
||||
|
||||
/**
|
||||
* Rule used to disable validations.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $disableJsValidationRule = 'NoJsValidation';
|
||||
|
||||
/**
|
||||
* Returns if rule is validated using Javascript.
|
||||
*
|
||||
* @param $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function isImplemented($rule)
|
||||
{
|
||||
return in_array($rule, $this->clientRules) || in_array($rule, $this->serverRules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if rule must be validated in server-side.
|
||||
*
|
||||
* @param $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function isRemoteRule($rule)
|
||||
{
|
||||
return in_array($rule, $this->serverRules) ||
|
||||
! in_array($rule, $this->clientRules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form request rule.
|
||||
*
|
||||
* @param string $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFormRequestRule($rule)
|
||||
{
|
||||
return $rule === RuleParser::FORM_REQUEST_RULE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if rule disables rule processing.
|
||||
*
|
||||
* @param $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDisableRule($rule)
|
||||
{
|
||||
return $rule === $this->disableJsValidationRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if rules should be validated.
|
||||
*
|
||||
* @param $rules
|
||||
* @return bool
|
||||
*/
|
||||
protected function validationDisabled($rules)
|
||||
{
|
||||
$rules = (array) $rules;
|
||||
|
||||
return in_array($this->disableJsValidationRule, $rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if rules is for input file type.
|
||||
*
|
||||
* @param $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFileRule($rule)
|
||||
{
|
||||
return in_array($rule, $this->fileRules);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Support;
|
||||
|
||||
trait UseDelegatedValidatorTrait
|
||||
{
|
||||
/**
|
||||
* Delegated validator.
|
||||
*
|
||||
* @var \Proengsoft\JsValidation\Support\DelegatedValidator
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* Sets delegated Validator instance.
|
||||
*
|
||||
* @param \Proengsoft\JsValidation\Support\DelegatedValidator $validator
|
||||
* @return void
|
||||
*/
|
||||
public function setDelegatedValidator(DelegatedValidator $validator)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets current DelegatedValidator instance.
|
||||
*
|
||||
* @return \Proengsoft\JsValidation\Support\DelegatedValidator
|
||||
*/
|
||||
public function getDelegatedValidator()
|
||||
{
|
||||
return $this->validator;
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Proengsoft\JsValidation\Support;
|
||||
|
||||
use Illuminate\Validation\ValidationRuleParser;
|
||||
|
||||
class ValidationRuleParserProxy
|
||||
{
|
||||
use AccessProtectedTrait;
|
||||
|
||||
/**
|
||||
* ValidationRuleParser instance.
|
||||
*
|
||||
* @var ValidationRuleParser
|
||||
*/
|
||||
protected $parser;
|
||||
|
||||
/**
|
||||
* Closure to invoke non accessible Validator methods.
|
||||
*
|
||||
* @var \Closure
|
||||
*/
|
||||
protected $parserMethod;
|
||||
|
||||
/**
|
||||
* ValidationRuleParserProxy constructor.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct($data = [])
|
||||
{
|
||||
$this->parser = new ValidationRuleParser((array) $data);
|
||||
$this->parserMethod = $this->createProtectedCaller($this->parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the rule name and parameters from a rule.
|
||||
*
|
||||
* @param array|string $rules
|
||||
* @return array
|
||||
*/
|
||||
public function parse($rules)
|
||||
{
|
||||
return $this->parser->parse($rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode the rules into an array of explicit rules.
|
||||
*
|
||||
* @param array $rules
|
||||
* @return mixed
|
||||
*/
|
||||
public function explodeRules($rules)
|
||||
{
|
||||
return $this->callProtected($this->parserMethod, 'explodeRules', [$rules]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate method calls to parser instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param mixed $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $params)
|
||||
{
|
||||
$arrCaller = [$this->parser, $method];
|
||||
|
||||
return call_user_func_array($arrCaller, $params);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user