[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Fmsystem-commits] [12129] Add form-validator
From: |
Sigurd Nes |
Subject: |
[Fmsystem-commits] [12129] Add form-validator |
Date: |
Thu, 09 Oct 2014 19:00:02 +0000 |
Revision: 12129
http://svn.sv.gnu.org/viewvc/?view=rev&root=fmsystem&revision=12129
Author: sigurdne
Date: 2014-10-09 19:00:00 +0000 (Thu, 09 Oct 2014)
Log Message:
-----------
Add form-validator
Added Paths:
-----------
branches/dev-syncromind/phpgwapi/js/form-validator/
branches/dev-syncromind/phpgwapi/js/form-validator/README.md
branches/dev-syncromind/phpgwapi/js/form-validator/date.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/date.js
branches/dev-syncromind/phpgwapi/js/form-validator/file.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/file.js
branches/dev-syncromind/phpgwapi/js/form-validator/form-test.html
branches/dev-syncromind/phpgwapi/js/form-validator/html5.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/html5.js
branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.js
branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.min.js
branches/dev-syncromind/phpgwapi/js/form-validator/location.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/location.js
branches/dev-syncromind/phpgwapi/js/form-validator/qunit.html
branches/dev-syncromind/phpgwapi/js/form-validator/security.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/security.js
branches/dev-syncromind/phpgwapi/js/form-validator/sweden.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/sweden.js
branches/dev-syncromind/phpgwapi/js/form-validator/uk.dev.js
branches/dev-syncromind/phpgwapi/js/form-validator/uk.js
Added: branches/dev-syncromind/phpgwapi/js/form-validator/README.md
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/README.md
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/README.md
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,400 @@
+# jQuery Form Validator
+
+With this feature rich jQuery plugin it becomes easy to validate user input
while keeping your
+ HTML markup clean from javascript code. Even though this plugin has **a wide
range of validation functions**
+it's designed to require as little bandwidth as possible. This is achieved by
grouping together validation functions
+in "modules", making it possible for the programmer to load **only those
functions that's needed** to validate a
+particular form.
+
+**Form demos and full documentation is available at http://formvalidator.net/**
+
+*Usage example*
+
+```html
+<form action="" method="POST">
+ <p>
+ Name (4 characters minimum):
+ <input name="user" data-validation="length" data-validation-length="min4"
/>
+ </p>
+ <p>
+ Birthdate (yyyy-mm-dd):
+ <input name="birth" data-validation="birthdate" />
+ </p>
+ <p>
+ Website:
+ <input name="website" data-validation="url" />
+ </p>
+ <p>
+ <input type="submit" />
+ </p>
+</form>
+<script src="js/jquery.min.js"></script>
+<script src="js/form-validator/jquery.form-validator.min.js"></script>
+<script>
+/* important to locate this script AFTER the closing form element, so form
object is loaded in DOM before setup is called */
+ $.validate({
+ modules : 'date, security'
+ });
+</script>
+```
+
+### Support for HTML5
+
+As of version 2.2 (unreleased) you can use this plugin as a fallback solution
for the validation attributes in the HTML5 spec. Add the module `html5` to the
module string and you can use the following native features:
+
+**Attributes**: require, pattern, maxlength, min, max, placeholder
+
+**Input types**: url, date, time, email, number
+
+**Elements**: Use the element `datalist` to create input suggestions
+
+
+### Default validators and features (no module needed)
+ * **url**
+ * **email**
+ * **domain** — *domain.com*
+ * **number** — *float/negative/positive/range/step*
+ * **date** — *yyyy-mm-dd (format can be customized, more information below)*
+ * **alphanumeric** — *with support for defining additional characters*
+ * **length** — *min/max/range*
+ * **required** — *no validation except that a value has to be given*
+ * **custom** — *Validate value against regexp*
+ * **checkboxgroup** — *ensure at least 1 checkbox in group has been selected*
+ * Show help information automatically when input is focused
+ * Validate given values immediately when input looses focus.
+ * Make validation optional by adding attribute
data-validation-optional="true" to the element. This means
+ that the validation defined in data-validation only will take place in case a
value is given.
+ * Make validation dependent on another input of type checkbox being checked
by adding attribute
+ data-validation-if-checked="name of checkbox input"
+ * Create input suggestions with ease, no jquery-ui needed
+ * to apply multiple validators to an input element, separate the validator
names using a space (ex: required email)
+
+Read the documentation for the default features at
[http://formvalidator.net/#default-validators](http://formvalidator.net/#default-validators)
+
+### Module: security
+ * **spamcheck**
+ * **confirmation**
+ * **creditcard**
+ * **CVV**
+ * **strength** — *Validate the strength of a password*
+ * **server** — *Validate value of input on server side*
+
+Read the documentation for the security module at
[http://formvalidator.net/#security-validators](http://formvalidator.net/#security-validators)
+
+### Module: date
+ * **time** — *hh:mm*
+ * **birthdate** — *yyyy-mm-dd, not allowing dates in the future or dates
that's older than 122 years (format can be customized, more information below)*
+
+Read the documentation for the date module at
[http://formvalidator.net/#date-validators](http://formvalidator.net/#date-validators)
+
+### Module: location
+ * **country**
+ * **federatestate**
+ * **longlat**
+ * Suggest countries (english only)
+ * Suggest states in the US
+
+Read the documentation for the location module at
[http://formvalidator.net/#location-validators](http://formvalidator.net/#location-validators)
+
+### Module: file
+ * **mime**
+ * **extension**
+ * **size**
+
+Read the documentation for the file module at
[http://formvalidator.net/#file-validators](http://formvalidator.net/#file-validators)
+
+### Module: sweden
+ * **swemob** — *validate that the value is a swedish mobile telephone number*
+ * **swesec** — *validate swedish social security number*
+ * **county** - *validate that the value is an existing county in Sweden*
+ * **municipality** - *validate that the value is an existing municipality in
Sweden*
+ * Suggest county
+ * Suggest municipality
+
+Read the documentation for the Swedish module at
[http://formvalidator.net/#sweden-validators](http://formvalidator.net/#sweden-validators)
+
+### Module: uk
+ * **ukvatnumber**
+
+Read the documentation for the UK module at
[http://formvalidator.net/#uk-validators](http://formvalidator.net/#uk-validators)
+
+
+## Writing a custom validator
+You can use the function `$.formUtils.addValidator()` to add your own
validation function. Here's an example of a validator
+that checks if the input contains an even number.
+
+```html
+<form action="" method="POST">
+ <p>
+ <input type="text" data-validation="even" />
+ </p>
+ ...
+</form>
+<script src="js/jquery.min.js"></script>
+<script src="js/form-validator/jquery.form-validator.min.js"></script>
+<script>
+
+ // Add validator
+ $.formUtils.addValidator({
+ name : 'even',
+ validatorFunction : function(value, $el, config, language, $form) {
+ return parseInt(value, 10) % 2 === 0;
+ },
+ errorMessage : 'You have to answer an even number',
+ errorMessageKey: 'badEvenNumber'
+ });
+
+ // Initiate form validation
+ $.validate();
+
+</script>
+```
+
+### Required properties passed into $.formUtils.addValidator
+
+*name* - The name of the validator, which is used in the validation attribute
of the input element.
+
+*validatorFunction* - Callback function that validates the input. Should
return a boolean telling if the value is considered valid or not.
+
+*errorMessageKey* - Name of language property that is used in case the value
of the input is invalid.
+
+*errorMessage* - An alternative error message that is used if errorMessageKey
is left with an empty value or isn't defined
+in the language object. Note that you also can use [inline error
messages](http://formvalidator.net/#localization) in your form.
+
+
+The validation function takes these five arguments:
+- value — the value of the input thats being validated
+- $el — jQuery object referring to the input element being validated
+- config — Object containing the configuration of this form validation
+- language — Object with error dialogs
+- $form — jQuery object referring to the form element being validated
+
+## Creating a custom module
+
+A "module" is basically a javascript file containing one or more calls to
[$.formUtils.addValidator()](#writing-a-custom-validator). The module file
+should either have the file extension *.js* (as an ordinary javascript file)
or *.dev.js*.
+
+Using the file extension **.dev.js** will tell *$.formUtils.loadModules* to
always append a timestamp to the end of the
+URL, so that the browser never caches the file. You should of course never use
*.dev.js* on a production website.
+
+### Loading your module ###
+
+```html
+<html>
+<head>
+ <script src="js/form-validator/jquery.form-validator.min.js"></script>
+ <script>
+ $.formUtils.loadModules('mymodule.dev', 'js/validation-modules/');
+ </script>
+</head>
+</html>
+...
+```
+
+The first argument of $.formUtils.loadModules is a comma separated string with
names of module files, without
+file extension (add .dev if the file name is for example mymodule.dev.js, this
will insure that the browser never
+caches the javascript).
+
+The second argument is the path where the module files is located. This
argument is optional, if not given
+the module files has to be located in the same directory as the core modules
shipped together with this jquery plugin
+(js/form-validator/)
+
+## Show help information
+It is possible to display help information for each input. The information
will fade in when input is focused and fade out when input looses focus.
+
+```html
+<form action="" id="my_form">
+ <p>
+ <strong>Why not:</strong>
+ <textarea name="why" data-validation-help="Please give us some more
information" data-validation="required"></textarea>
+ </p>
+ ...
+```
+
+## Fully customizable
+
+Read about how to customize this plugin over at
[http://formvalidator.net/#configuration](http://formvalidator.net/#configuration)
+
+## Localization
+This plugin contains a set of error dialogs. In case you don't define an
inline error message the plugin
+will fall back on one of the dialogs below. You can how ever add the attribute
*data-validation-error-msg* to an
+element, and that message will be displayed instead. All error dialogs can be
overwritten by passing an
+object into the validation function.
+
+```javascript
+var enErrorDialogs = {
+ errorTitle : 'Form submission failed!',
+ requiredFields : 'You have not answered all required fields',
+ badTime : 'You have not given a correct time',
+ badEmail : 'You have not given a correct e-mail address',
+ badTelephone : 'You have not given a correct phone number',
+ badSecurityAnswer : 'You have not given a correct answer to the security
question',
+ badDate : 'You have not given a correct date',
+ lengthBadStart : 'You must give an answer between ',
+ lengthBadEnd : 'characters',
+ lengthTooLongStart : 'You have given an answer longer than ',
+ lengthTooShortStart : 'You have given an answer shorter than ',
+ notConfirmed : 'Values could not be confirmed',
+ badDomain : 'Incorrect domain value',
+ badUrl : 'The answer you gave was not a correct URL',
+ badCustomVal : 'You gave an incorrect answer',
+ badInt : 'The answer you gave was not a correct number',
+ badSecurityNumber : 'Your social security number was incorrect',
+ badUKVatAnswer : 'Incorrect UK VAT Number',
+ badStrength : 'The password isn\'t strong enough',
+ badNumberOfSelectedOptionsStart : 'You have to choose at least ',
+ badNumberOfSelectedOptionsEnd : ' answers',
+ badAlphaNumeric : 'The answer you gave must contain only alphanumeric
characters ',
+ badAlphaNumericExtra: ' and ',
+ wrongFileSize : 'The file you are trying to upload is too large',
+ wrongFileType : 'The file you are trying to upload is of wrong type',
+ groupCheckedTooFewStart : 'Please choose at least ',
+ groupCheckedTooManyStart : 'Please choose a maximum of ',
+ groupCheckedRangeStart : 'Please choose between ',
+ groupCheckedEnd : ' item(s)'
+};
+```
+
+```html
+<form action="script.php">
+ ...
+</form>
+<script src="js/jquery.min.js"></script>
+<script src="js/form-validator/jquery.form-validator.min.js"></script>
+<script src="js/form-validator/locale.en.js"></script>
+<script>
+ $.validate({
+ language : enErrorDialogs
+ });
+</script>
+...
+```
+
+It's also possible to add inline error messages. If you add attribute
`data-validation-error-msg` to an element the value of
+that attribute will be displayed instead of the error dialog that the
validation function refers to.
+
+## Input length restriction
+```html
+<p>
+ History (<span id="maxlength">50</span> characters left)
+ <textarea rows="3" id="area"></textarea>
+</p>
+<script type="text/javascript">
+ $('#area').restrictLength( $('#maxlength') );
+</script>
+```
+
+## Program Flow
+Form submit() event is bound to jQ func **validateForm()** when the form is
submitted, it calls
+jQ func **$.formUtils.validateInput**, which calls **validatorFunction** for
the specific validation
+rule assigned to the input element. If a validation fails, error messages are
assigned and displayed
+as configured. If **validateOnBlur** is set to true, jQ finds all form input
elements with the
+data-validation attribute and binds their onBlur event to call the function
**validateInputOnBlur**.
+it calls jQ func **$.formUtils.validateInput** to validate the single input
when blurred.
+
+
+## Changelog
+
+#### 2.2.0 (unreleased)
+* Now possible to define an error message for each validation rule on a
certain input (issue #113)
+* This plugin now serves as a html5 fallback. You can now use the native
attributes to declare which type
+of validation that should be applied.
+* Use a template for error messages when having errorMessagePosition set to top
+* Added validation of credit card number and CVV to the security module
+* Event onElementValidate added
+* Use the attribute data-validation-confirm to declare which input that should
be confirmed when using validation=confirmation (issue #112)
+* Validation "required" now supports inputs of type radio
+* $.validateForm is now deprecated, use $.isValid instead
+
+
+#### 2.1.47
+* Incorrect error-styling when using datepicker or suggestions is now fixed
+* Incorrect error-styling of select elements is now fixed
+* Deprecated function $.validationSetup is now removed, use $.validate()
instead
+* You can now return an array with errors using the event `onValidate`
+* You can now declare an element where all error messages should be placed
(config.errorMessagePosition)
+
+#### 2.1.36
+* Now possible to use the native reset() function to clear error messages and
error styling of the input elements
+
+#### 2.1.34
+* General improvements and bug fixes
+* Added events "beforeValidation" and "validation" (see
http://formvalidator.net/#configuration_callbacks for more info)
+
+#### 2.1.27
+ * E-mail validation support .eu top domain
+ * Improvements in server validation
+ * Now possible to re-initiate the validation. This makes it possible to
dynamically change the form and then call $.validate() again to refresh the
validation (issue #59)
+ * Number validation now supports range
+
+#### 2.1.15
+ * E-mail addresses can now contain + symbol
+ * Correction of the US states in validation "federatestate"
+ * Fixed bug in server validation
+
+#### 2.1.9
+ * File validation now support multiple files
+ * Length validation can now be used to validate the number of uploaded files
using a file input that supports multiple files
+ * Validation classes is no longer applied on inputs that for some reason
shouldn't become validated
+
+#### 2.1.8
+ * Now possible to configure the decimal separator when validating float
values. Use either the
+ attribute *data-validation-decimal-separator* or the property
*decimalSeparator* when
+calling $.validate()
+ * $.validationSetup is renamed to $.validate. You will still be able to
initiate the validation by calling
+ the $.validationSetup but it's considered deprecated.
+
+#### 2.1.6
+ * Modules can now be loaded from remote website
+
+#### 2.1.5
+ * Fixed language bug (issue #43 on github)
+ * Validation on server side is now triggered by the blur event
+ * Now using class names that's compliant with twitter bootstrap 3.x
+
+#### 2.1
+ * Code refactoring and some functions renamed
+ * Validator "checkbox_group" added
+
+#### 2.0.7
+ * Now possible to validate file size, extension and mime type (using the file
module)
+
+#### 2.0
+ * [min|max]_length is removed (now merged with length validation).
+ * The number, int and float validation is merged together, all three variants
is now validated by the number validation.
+ * Phone validation is moved to "sweden" module and renamed to swephone.
+ * The attribute to be used when defining the regular expression for custom
validations is now moved to its own attribute (data-validation-regexp)
+ * Length validation now looks at attribute data-validation-length (eg. min5,
max200, 3-12).
+ * The validation rule no longer needs to be prefixed with "validate_" (it's
still possible to use the prefix but it's considered deprecated).
+ * Some validation functions is moved to modules (see the function reference
over at http://formvalidator.net).
+ * Added function $.validationSetup() to reduce the amount of code that has to
be written when initiating the form validation.
+
+
+## Credits
+
+#### Maintainer
+
+[Victor Jonsson](https://github.com/victorjonsson)
+
+#### Contributors
+<a href="http://stevewasiura.waztech.com" target="_blank">Steve Wasiura</a><br
/>
+<a href="http://lagden.github.com" target="_blank">Thiago Lagden</a><br />
+<a href="https://github.com/robamaton" target="_blank">Joel Sutherland</a><br
/>
+<a href="https://github.com/mattclements" target="_blank">Matt Clements</a><br
/>
+<a href="http://www.joshtoft.com/" target="_blank">Josh Toft</a><br/>
+<a href="https://github.com/dfcplc" target="_blank">@dfcplc</a><br />
+<a href="https://github.com/coffein" target="_blank">Andree Wendel</a><br />
+<a href="http://www.huotmedia.com" target="_blank">Nicholas Huot</a><br />
+<a href="https://github.com/Repkit" target="_blank">@repkit</a><br />
+<a href="https://github.com/aL3xa" target="_blank">Alexandar Blagotic</a><br />
+<a href="http://thekindof.me/" target="_blank">Yasith Fernando</a><br />
+<a href="https://github.com/S0L4R1S" target="_blank">@S0L4R1S</a><br />
+<a href="http://lisangan.com/">Erick Lisangan</a><br />
+<a href="https://github.com/kirbs-">@kirbs</a>
+<a href="https://github.com/hslee87">hslee87</a>
+
+#### Additional credits
+
+<a href="http://projects.scottsplayground.com/iri/" target="_blank">Scott
Gonzales</a> (URL regexp)<br />
+<a href="http://www.mypocket-technologies.com" target="_blank">Darren
Mason</a> (Password strength meter)<br />
+<a href="http://stevewasiura.waztech.com" target="_blank">Steve Wasiura</a>
(Checkbox group)
Added: branches/dev-syncromind/phpgwapi/js/form-validator/date.dev.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/date.dev.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/date.dev.js
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,81 @@
+/**
+ * jQuery Form Validator Module: Date
+ * ------------------------------------------
+ * Created by Victor Jonsson <http://www.victorjonsson.se>
+ * Documentation and issue tracking on Github
<https://github.com/victorjonsson/jQuery-Form-Validator/>
+ *
+ * The following validators will be added by this module:
+ * - Time (HH:mmm)
+ * - Birth date
+ *
+ * @website http://formvalidator.net/#location-validators
+ * @license Dual licensed under the MIT or GPL Version 2 licenses
+ * @version 2.2.beta.13
+ */
+(function($) {
+
+ /*
+ * Validate time hh:mm
+ */
+ $.formUtils.addValidator({
+ name : 'time',
+ validatorFunction : function(time) {
+ if (time.match(/^(\d{2}):(\d{2})$/) === null) {
+ return false;
+ } else {
+ var hours = parseInt(time.split(':')[0],10);
+ var minutes = parseInt(time.split(':')[1],10);
+ if( hours > 23 || minutes > 59 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+ errorMessage : '',
+ errorMessageKey: 'badTime'
+ });
+
+ /*
+ * Is this a valid birth date
+ */
+ $.formUtils.addValidator({
+ name : 'birthdate',
+ validatorFunction : function(val, $el, conf) {
+ var dateFormat = 'yyyy-mm-dd';
+ if($el.valAttr('format')) {
+ dateFormat = $el.valAttr('format');
+ }
+ else if(typeof conf.dateFormat != 'undefined') {
+ dateFormat = conf.dateFormat;
+ }
+
+ var inputDate = $.formUtils.parseDate(val, dateFormat);
+ if (!inputDate) {
+ return false;
+ }
+
+ var d = new Date();
+ var currentYear = d.getFullYear();
+ var year = inputDate[0];
+ var month = inputDate[1];
+ var day = inputDate[2];
+
+ if (year === currentYear) {
+ var currentMonth = d.getMonth() + 1;
+ if (month === currentMonth) {
+ var currentDay = d.getDate();
+ return day <= currentDay;
+ }
+ else {
+ return month < currentMonth;
+ }
+ }
+ else {
+ return year < currentYear && year > (currentYear - 124); // we
can not live for ever yet...
+ }
+ },
+ errorMessage : '',
+ errorMessageKey: 'badDate'
+ });
+
+})(jQuery);
\ No newline at end of file
Added: branches/dev-syncromind/phpgwapi/js/form-validator/date.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/date.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/date.js 2014-10-09
19:00:00 UTC (rev 12129)
@@ -0,0 +1 @@
+(function($){$.formUtils.addValidator({name:"time",validatorFunction:function(time){if(time.match(/^(\d{2}):(\d{2})$/)===null){return
false}else{var hours=parseInt(time.split(":")[0],10);var
minutes=parseInt(time.split(":")[1],10);if(hours>23||minutes>59){return
false}}return
true},errorMessage:"",errorMessageKey:"badTime"});$.formUtils.addValidator({name:"birthdate",validatorFunction:function(val,$el,conf){var
dateFormat="yyyy-mm-dd";if($el.valAttr("format")){dateFormat=$el.valAttr("format")}else
if(typeof conf.dateFormat!="undefined"){dateFormat=conf.dateFormat}var
inputDate=$.formUtils.parseDate(val,dateFormat);if(!inputDate){return false}var
d=new Date;var currentYear=d.getFullYear();var year=inputDate[0];var
month=inputDate[1];var day=inputDate[2];if(year===currentYear){var
currentMonth=d.getMonth()+1;if(month===currentMonth){var
currentDay=d.getDate();return day<=currentDay}else{return
month<currentMonth}}else{return
year<currentYear&&year>currentYear-124}},errorMessage:"",errorMessageKey:"badDate"})})(jQuery);
\ No newline at end of file
Added: branches/dev-syncromind/phpgwapi/js/form-validator/file.dev.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/file.dev.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/file.dev.js
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,169 @@
+/**
+ * jQuery Form Validator Module: File
+ * ------------------------------------------
+ * Created by Victor Jonsson <http://www.victorjonsson.se>
+ *
+ * The following validators will be added by this module:
+ * - mime type
+ * - file size
+ * - file extension
+ *
+ * @website http://formvalidator.net/
+ * @license Dual licensed under the MIT or GPL Version 2 licenses
+ * @version 2.2.beta.13
+ */
+(function($, window) {
+
+ var SUPPORTS_FILE_READER = typeof window.FileReader != 'undefined',
+
+ /**
+ * @return {Array}
+ */
+ _getTypes = function($input) {
+ var allowedTypes = $.split( ($input.valAttr('allowing') ||
'').toLowerCase() );
+
+ if( $.inArray('jpg', allowedTypes) > -1 && $.inArray('jpeg',
allowedTypes) == -1)
+ allowedTypes.push('jpeg');
+ else if( $.inArray('jpeg', allowedTypes) > -1 && $.inArray('jpg',
allowedTypes) == -1)
+ allowedTypes.push('jpg');
+ return allowedTypes;
+ },
+
+ /**
+ * @param {String} msg
+ */
+ _log = function(msg) {
+ if( window.console && window.console.log ) {
+ window.console.log(msg);
+ }
+ };
+
+ /*
+ * Validate mime type (falls back on validate_extension in older browsers)
+ */
+ $.formUtils.addValidator({
+ name : 'mime',
+ validatorFunction : function(str, $input) {
+ var files = $input.get(0).files || [];
+
+ if( SUPPORTS_FILE_READER ) {
+ var valid = true,
+ mime = '',
+ allowedTypes = _getTypes($input);
+
+ $.each(files, function(i, file) {
+ valid = false;
+ mime = file.type || '';
+ $.each(allowedTypes, function(j, type) {
+ valid = mime.indexOf(type) > -1;
+ if( valid ) {
+ return false;
+ }
+ });
+ return valid;
+ });
+
+ if( !valid ) {
+ _log('Trying to upload a file with mime type '+mime+'
which is not allowed');
+ }
+ return valid;
+
+ } else {
+ _log('FileReader not supported by browser, will check file
extension');
+ return
$.formUtils.validators.validate_extension.validatorFunction(str, $input);
+ }
+ },
+ errorMessage : 'The file you are trying to upload is of wrong type',
+ errorMessageKey: 'wrongFileType'
+ });
+
+ /**
+ * Validate file extension
+ */
+ $.formUtils.addValidator({
+ name : 'extension',
+ validatorFunction : function(value, $input) {
+ var valid = true,
+ types = _getTypes($input);
+
+ $.each($input.get(0).files || [], function(i, file) {
+ var val = file.value,
+ ext = val.substr( val.lastIndexOf('.')+1 );
+ if( $.inArray(ext.toLowerCase(), types) == -1 ) {
+ valid = false;
+ return false;
+ }
+ });
+ return valid;
+ },
+ errorMessage : 'The file you are trying to upload is of wrong type',
+ errorMessageKey: 'wrongFileType'
+ });
+
+ /**
+ * Validate file size
+ */
+ $.formUtils.addValidator({
+ name : 'size',
+ validatorFunction : function(val, $input) {
+ var maxSize = $input.valAttr('max-size');
+ if( !maxSize ) {
+ _log('Input "'+$input.attr('name')+'" is missing
data-validation-max-size attribute');
+ return true;
+ } else if( !SUPPORTS_FILE_READER ) {
+ return true; // no fallback available
+ }
+
+ var maxBytes = $.formUtils.convertSizeNameToBytes(maxSize),
+ valid = true;
+ $.each($input.get(0).files || [], function(i, file) {
+ valid = file.size <= maxBytes;
+ return valid;
+ });
+ return valid;
+ },
+ errorMessage : 'The file you are trying to upload is too large',
+ errorMessageKey: 'wrongFileSize'
+ });
+
+ /**
+ * Make this function accessible via formUtils for unit tests
+ * @param {String} sizeName
+ * @return {Number}
+ */
+ $.formUtils.convertSizeNameToBytes = function(sizeName) {
+ sizeName = sizeName.toUpperCase();
+ if( sizeName.substr(sizeName.length-1, 1) == 'M' ) {
+ return parseInt(sizeName.substr(0, sizeName.length-1), 10) * 1024
* 1024;
+ } else if( sizeName.substr(sizeName.length-2, 2) == 'MB' ) {
+ return parseInt(sizeName.substr(0, sizeName.length-2), 10) * 1024
* 1024;
+ } else if( sizeName.substr(sizeName.length-2, 2) == 'KB' ) {
+ return parseInt(sizeName.substr(0, sizeName.length-2), 10) * 1024;
+ } else if( sizeName.substr(sizeName.length-1, 1) == 'B' ) {
+ return parseInt(sizeName.substr(0, sizeName.length-1), 10);
+ } else {
+ return parseInt(sizeName, 10);
+ }
+ };
+
+ /*
+ * This event listener will remove error messages for file
+ * inputs when file changes
+ */
+ $(window).one('validatorsLoaded formValidationSetup', function(evt, $form)
{
+ var $inputs;
+ if( $form ) {
+ $inputs = $form.find('input[type="file"]');
+ } else {
+ $inputs = $('input[type="file"]');
+ }
+
+ $inputs.filter('*[data-validation]').bind('change', function() {
+ $(this)
+ .removeClass('error')
+ .parent()
+ .find('.form-error').remove();
+ });
+ });
+
+})(jQuery, window);
\ No newline at end of file
Added: branches/dev-syncromind/phpgwapi/js/form-validator/file.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/file.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/file.js 2014-10-09
19:00:00 UTC (rev 12129)
@@ -0,0 +1 @@
+(function($,window){var SUPPORTS_FILE_READER=typeof
window.FileReader!="undefined",_getTypes=function($input){var
allowedTypes=$.split(($input.valAttr("allowing")||"").toLowerCase());if($.inArray("jpg",allowedTypes)>-1&&$.inArray("jpeg",allowedTypes)==-1)allowedTypes.push("jpeg");else
if($.inArray("jpeg",allowedTypes)>-1&&$.inArray("jpg",allowedTypes)==-1)allowedTypes.push("jpg");return
allowedTypes},_log=function(msg){if(window.console&&window.console.log){window.console.log(msg)}};$.formUtils.addValidator({name:"mime",validatorFunction:function(str,$input){var
files=$input.get(0).files||[];if(SUPPORTS_FILE_READER){var
valid=true,mime="",allowedTypes=_getTypes($input);$.each(files,function(i,file){valid=false;mime=file.type||"";$.each(allowedTypes,function(j,type){valid=mime.indexOf(type)>-1;if(valid){return
false}});return valid});if(!valid){_log("Trying to upload a file with mime
type "+mime+" which is not allowed")}return valid}else{_log("FileReader not
supported by browser, will check file extension");return
$.formUtils.validators.validate_extension.validatorFunction(str,$input)}},errorMessage:"The
file you are trying to upload is of wrong
type",errorMessageKey:"wrongFileType"});$.formUtils.addValidator({name:"extension",validatorFunction:function(value,$input){var
valid=true,types=_getTypes($input);$.each($input.get(0).files||[],function(i,file){var
val=file.value,ext=val.substr(val.lastIndexOf(".")+1);if($.inArray(ext.toLowerCase(),types)==-1){valid=false;return
false}});return valid},errorMessage:"The file you are trying to upload is of
wrong
type",errorMessageKey:"wrongFileType"});$.formUtils.addValidator({name:"size",validatorFunction:function(val,$input){var
maxSize=$input.valAttr("max-size");if(!maxSize){_log('Input
"'+$input.attr("name")+'" is missing data-validation-max-size
attribute');return true}else if(!SUPPORTS_FILE_READER){return true}var
maxBytes=$.formUtils.convertSizeNameToBytes(maxSize),valid=true;$.each($input.get(0).files||[],function(i,file){valid=file.size<=maxBytes;return
valid});return valid},errorMessage:"The file you are trying to upload is too
large",errorMessageKey:"wrongFileSize"});$.formUtils.convertSizeNameToBytes=function(sizeName){sizeName=sizeName.toUpperCase();if(sizeName.substr(sizeName.length-1,1)=="M"){return
parseInt(sizeName.substr(0,sizeName.length-1),10)*1024*1024}else
if(sizeName.substr(sizeName.length-2,2)=="MB"){return
parseInt(sizeName.substr(0,sizeName.length-2),10)*1024*1024}else
if(sizeName.substr(sizeName.length-2,2)=="KB"){return
parseInt(sizeName.substr(0,sizeName.length-2),10)*1024}else
if(sizeName.substr(sizeName.length-1,1)=="B"){return
parseInt(sizeName.substr(0,sizeName.length-1),10)}else{return
parseInt(sizeName,10)}};$(window).one("validatorsLoaded
formValidationSetup",function(evt,$form){var
$inputs;if($form){$inputs=$form.find('input[type="file"]')}else{$inputs=$('input[type="file"]')}$inputs.filter("*[data-validation]").bind("change",function(){$(this).removeClass("error").parent().find(".form-error").remove()})})})(jQuery,window);
\ No newline at end of file
Added: branches/dev-syncromind/phpgwapi/js/form-validator/form-test.html
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/form-test.html
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/form-test.html
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,415 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title>Form Test</title>
+ <link rel="stylesheet"
href="//netdna.bootstrapcdn.com/bootstrap/3.0.0-wip/css/bootstrap.min.css" />
+ <link rel="stylesheet"
href="//code.jquery.com/ui/1.10.4/themes/black-tie/jquery-ui.css" />
+ <style>
+
+ /* Form and inputs */
+ form {
+ width: 500px;
+ margin: 0 auto;
+ padding: 20px;
+ display: block;
+ }
+
+ input.form-control {
+ width: 375px;
+ }
+
+ button, input[type="submit"], .button {
+ margin-bottom: 8px;
+ }
+
+ /* While server is being requested */
+ form.validating-server-side {
+ background: #F2F2F2;
+ }
+
+ input.validating-server-side {
+ opacity: 0.5;
+ background: lightgoldenrodyellow;
+ }
+
+ /* modify inputs for password strength */
+ .password-strength input.form-control {
+ width: 375px;
+ margin-right: 4px;
+ display: inline;
+ }
+
+ .password-strength label {
+ display: block;
+ }
+
+ /* Checkboxes */
+ .form-group.check-boxes input {
+ margin-left: 10px;
+ }
+
+ span.help {
+ color: #999 !important;
+ }
+
+ /* Error container for form C */
+
+ #error-container div {
+ color: red;
+ line-height: 140%;
+ }
+
+ #error-container div:last-child {
+ padding-bottom: 10px;
+ }
+
+ </style>
+</head>
+<body>
+<div>
+ <form action="" id="form-a" role="form">
+ <div class="form-group">
+ <label class="control-label" for="inline-suggestions">Inline
suggestions</label>
+ <input name="inline suggestions" type="text"
id="inline-suggestions" class="form-control" data-suggestions="Monkey, Horse,
Fox, Tiger, Elephant" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label" for="country-suggestions">Country
suggestions</label>
+ <input name="country suggestions" data-validation="country"
type="text" id="country-suggestions" class="form-control" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label" for="country-suggestions">Swedish
county suggestions</label>
+ <input name="Swedish county suggestion"
data-validation="swecounty" type="text" id="swedish-county-suggestions"
class="form-control" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Year</label>
+ <input name="birth" class="form-control"
+ data-validation="date"
+ data-validation-format="yyyy-mm-dd"
+ data-suggestions="2014-01-15,2014-01-16,2014-01-17" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Datepicker</label>
+ <input name="birth2" class="form-control"
+ data-validation="date"
+ data-validation-format="mm/dd/yyyy"
+ id="datepicker" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Number 0-10 (accepting floats with
comma)</label>
+ <input name="floats" class="form-control"
+ data-validation="number"
+ data-validation-allowing="range[0;10], float"
+ data-validation-decimal-separator=","
+ />
+ </div>
+
+ <div class="form-group password-strength">
+ <label class="control-label" for="password">Display password
strength (only strong)</label>
+ <input name="password" type="password" id="password"
class="form-control" data-validation="strength" data-validation-strength="3" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Alphanumeric and -_ and spaces</label>
+ <input name="alphanumeric with spaces" class="form-control"
name="test" data-validation="alphanumeric" data-validation-allowing="-_ " />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Alphanumeric only</label>
+ <input name="aplhanumeric only" class="form-control" name="test2"
data-validation="alphanumeric" />
+ </div>
+
+ <div class="checkbox form-group">
+ <label>
+ <input name="checkbox" type="checkbox"
data-validation="required" /> Must be checked
+ </label>
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Must choose one</label>
+ <br />
+ <input name="radio" type="radio" data-validation="required"
value="1" /> A
+ <input name="radio" type="radio" value="1" /> B
+ <input name="radio" type="radio" value="1" /> C
+ <input name="radio" type="radio" value="1" /> D
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Even numbers only</label>
+ <input name="even numbers" class="form-control" name="test4"
data-validation="even_number" />
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Make a choice</label>
+ <br />
+ <select name="choice" data-validation="required"
data-validation-error-msg="Please make a choice">
+ <option value="">- - Choose - -</option>
+ <option>A</option>
+ <option>B</option>
+ <option>C</option>
+ <option>D</option>
+ </select>
+ </div>
+
+ <div class="form-group">
+ <label class="control-label">Text</label>
+ (<span id="max-len">20</span> chars left)<br />
+ <textarea id="text-area" class="form-control"
name="some-text"></textarea>
+ </div>
+ <div class="form-group">
+ <label class="control-label">Server validation</label>
+ <input class="form-control" name="code" value="secret"
+ data-validation-help="The word is "secret""
+ data-validation="server"
+
data-validation-url="http://formvalidator.net/validate-email.php" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">File validation</label>
+ <input type="file" name="some-file1" class="form-control"
+ data-validation="size mime required"
+ data-validation-size-error-msg="The file cant be larger
than 400kb"
+ data-validation-error-msg="You must upload an image file
(max 400 kb)"
+ data-validation-allowing="jpg, png, ico"
+ data-validation-max-size="400kb" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">
+ Callback validation, set this value to "1" and
+ validation will fail
+ </label>
+ <input id="callback" class="form-control" />
+ </div>
+
+ <div class="form-group check-boxes">
+ <label>Checkbox group</label><br />
+ <label>
+ <input type="checkbox" name="box" value="1"
+ data-validation="checkbox_group"
+ data-validation-qty="1-2" /> 1
+ </label>
+ <label>
+ <input type="checkbox" name="box" value="2" /> 2
+ </label>
+ <label>
+ <input type="checkbox" name="box" value="3" /> 3
+ </label>
+ <label>
+ <input type="checkbox" name="box" value="4" /> 4
+ </label>
+ <label>
+ <input type="checkbox" name="box" value="5" /> 5
+ </label>
+ </div>
+ <p style="line-height: 200%">
+ <input type="submit" class="button">
+ <br />
+ <button class="button" type="button"
+ onclick="alert('From a is ' + ( $('#form-a').isValid({},
{}, false) ? 'VALID':'NOT VALID'));">
+ Test validation via js (<strong>without error
messages</strong>)
+ </button>
+ <br />
+ <button class="button" type="button"
+ onclick="alert('From a is ' + ( $('#form-a').isValid() ?
'VALID':'NOT VALID'));">
+ Test validation via js (showing error messages)
+ </button>
+ <br />
+ <input type="reset" class="button">
+ </p>
+ </form>
+ <hr />
+ <form id="form-b">
+ <div class="form-group">
+ <label class="control-label">Test</label>
+ <input name="test" data-validation="number" type="text" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">Password</label>
+ <input name="pass" data-validation="confirmation" type="password"
/>
+ </div>
+ <div class="form-group">
+ <label class="control-label">Password again</label>
+ <input name="pass_confirmation" type="password" />
+ </div>
+ <p>
+ <input type="submit" class="button">
+ <input type="reset" class="button">
+ </p>
+ </form>
+ <hr />
+ <form id="form-c">
+ <div class="form-group">
+ <label class="control-label">Country</label>
+ <input name="test" data-validation="country"
data-validation-error-msg="No valid country given" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">E-mail</label>
+ <input name="testmail" data-validation="email"
data-validation-error-msg="E-mail is not valid" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">Confirm e-mail</label>
+ <input name="test" data-validation="confirmation"
data-validation-confirm="testmail" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">Alphanumeric (will only be validated
if the checkbox is checked)</label>
+ <input name="test2"
+ data-validation="alphanumeric"
+ data-validation-error-msg="Invalid..."
+ data-validation-if-checked="checker" />
+ <br />
+ <input type="checkbox" name="checker" />
+ </div>
+ <div id="error-container">
+
+ </div>
+ <p>
+ <input type="submit" class="button">
+ <input type="reset" class="button">
+ </p>
+ </form>
+ <hr />
+ <form id="form-d">
+ <h2>HTML5 attributes</h2>
+ <div class="form-group">
+ <label class="control-label">type="email"</label>
+ <input type="text" required="required" list="mejl" />
+ <datalist id="mejl">
+ <option value="Test">Test</option>
+ <option value="test2">test2</option>
+ <option value="test3">test3</option>
+ </datalist>
+ </div>
+ <div class="form-group">
+ <label class="control-label">type="url" (optional)</label>
+ <input type="url" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">type="number"</label>
+ <input type="number" required="required" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">type="number"</label>
+ <input type="number" required="required" maxlength="30" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">type="number" range[-5;5]</label>
+ <input type="number" min="-5" max="5" required="required" />
+ </div>
+ <div class="form-group">
+ <label class="control-label">pattern="^([a-z]+)$"</label>
+ <input type="text" name="some-colorz" list="some-colorz"
pattern="^([a-z]+)$" required="required" />
+ <datalist id="some-colorz" style="display: none">
+ <option value="Green">Green</option>
+ <option value="Blue">Blue</option>
+ <option value="Red">Red</option>
+ <option value="Black">Black</option>
+ <option value="White">White</option>
+ </datalist>
+ </div>
+ <p>
+ <input type="submit" class="button">
+ <input type="reset" class="button">
+ </p>
+ </form>
+</div>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+<script src="//code.jquery.com/ui/1.10.4/jquery-ui.min.js"></script>
+<script src="jquery.form-validator.js"></script>
+<script>
+(function($, window) {
+
+ var dev = '.dev'; //window.location.hash.indexOf('dev') > -1 ? '.dev' : '';
+
+ // setup datepicker
+ $("#datepicker").datepicker();
+
+ // Add a new validator
+ $.formUtils.addValidator({
+ name : 'even_number',
+ validatorFunction : function(value, $el, config, language, $form) {
+ return parseInt(value, 10) % 2 === 0;
+ },
+ borderColorOnError : '',
+ errorMessage : 'You have to give an even number',
+ errorMessageKey: 'badEvenNumber'
+ });
+
+ window.applyValidation = function(validateOnBlur, forms, messagePosition) {
+ if( !forms )
+ forms = 'form';
+ if( !messagePosition )
+ messagePosition = 'top';
+
+ $.validate({
+ form : forms,
+ language : {
+ requiredFields: 'Du måste bocka för denna'
+ },
+ validateOnBlur : validateOnBlur,
+ errorMessagePosition : messagePosition,
+ scrollToTopOnError : true,
+ borderColorOnError : 'purple',
+ modules : 'security'+dev+', location'+dev+', sweden'+dev+',
html5'+dev+', file'+dev+', uk'+dev,
+ onModulesLoaded: function() {
+ $('#country-suggestions').suggestCountry();
+ $('#swedish-county-suggestions').suggestSwedishCounty();
+ $('#password').displayPasswordStrength();
+ },
+ onValidate : function($f) {
+
+ console.log('about to validate form '+$f.attr('id'));
+
+ var $callbackInput = $('#callback');
+ if( $callbackInput.val() == 1 ) {
+ return {
+ element : $callbackInput,
+ message : 'This validation was made in a callback'
+ };
+ }
+ },
+ onError : function($form) {
+ if( !$.formUtils.haltValidation ) {
+ alert('Invalid '+$form.attr('id'));
+ }
+ },
+ onSuccess : function($form) {
+ alert('Valid '+$form.attr('id'));
+ return false;
+ }
+ });
+ };
+
+ $('#text-area').restrictLength($('#max-len'));
+
+ window.applyValidation(true, '#form-a', 'top');
+ window.applyValidation(false, '#form-b', 'element');
+ window.applyValidation(true, '#form-c', $('#error-container'));
+ window.applyValidation(true, '#form-d', 'element');
+
+ // Load one module outside $.validate() even though you do not have to
+ $.formUtils.loadModules('date'+dev+'.js', false, false);
+
+ $('input')
+ .on('zbeforeValidation', function() {
+ console.log('About to validate input "'+this.name+'"');
+ })
+ .on('validationz', function(evt, isValid) {
+ var validationResult = '';
+ if( isValid === null ) {
+ validationResult = 'not validated';
+ } else if( isValid ) {
+ validationResult = 'VALID';
+ } else {
+ validationResult = 'INVALID';
+ }
+ console.log('Input '+this.name+' is '+validationResult);
+ });
+
+})(jQuery, window);
+</script>
+<body>
+</html>
\ No newline at end of file
Added: branches/dev-syncromind/phpgwapi/js/form-validator/html5.dev.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/html5.dev.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/html5.dev.js
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,144 @@
+/**
+ * jQuery Form Validator Module: html5
+ * ------------------------------------------
+ * Created by Victor Jonsson <http://www.victorjonsson.se>
+ *
+ * The following module will make this jQuery plugin serve as a
+ * html5 fallback. It makes older browsers support the following
+ * - validation when type="email"
+ * - validation when type="url"
+ * - validation when type="time"
+ * - validation when type="date"
+ * - validation when type="number" and max="" min=""
+ * - validation when pattern="REGEXP"
+ * - validation when using maxlength
+ * - Using datalist element for creating suggestions
+ * - placeholders
+ *
+ * @website http://formvalidator.net/
+ * @license Dual licensed under the MIT or GPL Version 2 licenses
+ * @version 2.2.beta.13
+ */
+(function($, window) {
+
+ "use strict";
+
+ var SUPPORTS_PLACEHOLDER = 'placeholder' in
document.createElement('INPUT'),
+ SUPPORTS_DATALIST = 'options' in document.createElement('DATALIST');
+
+ $(window).bind('validatorsLoaded formValidationSetup', function(evt,
$form) {
+
+ if( !$form ) {
+ $form = $('form');
+ }
+
+ var hasLoadedDateModule = false;
+
+ $form.each(function() {
+ var $f = $(this),
+ $formInputs = $f.find('input,textarea,select'),
+ foundHtml5Rule = false;
+
+ $formInputs.each(function() {
+ var validation = [],
+ $input = $(this),
+ isRequired = $input.attr('required'),
+ attrs = {};
+
+ switch ( ($input.attr('type') || '').toLowerCase() ) {
+ case 'time':
+ validation.push('time');
+ if( !$.formUtils.validators.validate_date &&
!hasLoadedDateModule ) {
+ hasLoadedDateModule = true;
+ $.formUtils.loadModules('date');
+ }
+ break;
+ case 'url':
+ validation.push('url');
+ break;
+ case 'email':
+ validation.push('email');
+ break;
+ case 'date':
+ validation.push('date');
+ break;
+ case 'number':
+ validation.push('number');
+ var max = $input.attr('max'),
+ min = $input.attr('min');
+ if( min || max ) {
+ if( !min )
+ min = 0;
+ if( !max )
+ max = 9007199254740992; // js max int
+
+ attrs['data-validation-allowing'] =
'range['+min+';'+max+']';
+ if( min.indexOf('-') === 0 || max.indexOf('-') ===
0 ) {
+ attrs['data-validation-allowing'] +=
',negative';
+ }
+ if( min.indexOf('.') > -1 || max.indexOf('.') > -1
) {
+ attrs['data-validation-allowing'] += ',float';
+ }
+ }
+ break;
+ }
+
+ if( $input.attr('pattern') ) {
+ validation.push('custom');
+ attrs['data-validation-regexp'] = $input.attr('pattern');
+ }
+ if( $input.attr('maxlength') ) {
+ validation.push('length');
+ attrs['data-validation-length'] =
'max'+$input.attr('maxlength');
+ }
+
+ if( !SUPPORTS_DATALIST && $input.attr('list') ) {
+ var suggestions = [];
+ $('#'+$input.attr('list')+' option').each(function() {
+ var $opt = $(this);
+ suggestions.push($opt.attr('value') || $opt.text());
+ });
+ $.formUtils.suggest( $input, suggestions );
+ }
+
+ if( validation.length ) {
+ if( !isRequired ) {
+ attrs['data-validation-optional'] = 'true';
+ }
+
+ foundHtml5Rule = true;
+ $input.attr('data-validation', validation.join(' '));
+
+ $.each(attrs, function(attrName, attrVal) {
+ $input.attr(attrName, attrVal);
+ });
+ }
+ });
+
+ if( foundHtml5Rule ) {
+ $f.trigger('html5ValidationAttrsFound');
+ }
+
+ if( !SUPPORTS_PLACEHOLDER ) {
+ $formInputs.filter('input[placeholder]').each(function() {
+ this.defaultValue = this.getAttribute('placeholder');
+ $(this)
+ .bind('focus', function() {
+ if(this.value == this.defaultValue) {
+ this.value = '';
+ $(this).removeClass('showing-placeholder');
+ }
+ })
+ .bind('blur', function() {
+ if($.trim(this.value) == '') {
+ this.value = this.defaultValue;
+ $(this).addClass('showing-placeholder');
+ }
+ });
+ });
+ }
+
+ });
+ });
+
+})(jQuery, window);
\ No newline at end of file
Added: branches/dev-syncromind/phpgwapi/js/form-validator/html5.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/html5.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/html5.js 2014-10-09
19:00:00 UTC (rev 12129)
@@ -0,0 +1 @@
+(function($,window){"use strict";var SUPPORTS_PLACEHOLDER="placeholder"in
document.createElement("INPUT"),SUPPORTS_DATALIST="options"in
document.createElement("DATALIST");$(window).bind("validatorsLoaded
formValidationSetup",function(evt,$form){if(!$form){$form=$("form")}var
hasLoadedDateModule=false;$form.each(function(){var
$f=$(this),$formInputs=$f.find("input,textarea,select"),foundHtml5Rule=false;$formInputs.each(function(){var
validation=[],$input=$(this),isRequired=$input.attr("required"),attrs={};switch(($input.attr("type")||"").toLowerCase()){case"time":validation.push("time");if(!$.formUtils.validators.validate_date&&!hasLoadedDateModule){hasLoadedDateModule=true;$.formUtils.loadModules("date")}break;case"url":validation.push("url");break;case"email":validation.push("email");break;case"date":validation.push("date");break;case"number":validation.push("number");var
max=$input.attr("max"),min=$input.attr("min");if(min||max){if(!min)min=0;if(!max)max=9007199254740992;attrs["data-validation-allowing"]="range["+min+";"+max+"]";if(min.indexOf("-")===0||max.indexOf("-")===0){attrs["data-validation-allowing"]+=",negative"}if(min.indexOf(".")>-1||max.indexOf(".")>-1){attrs["data-validation-allowing"]+=",float"}}break}if($input.attr("pattern")){validation.push("custom");attrs["data-validation-regexp"]=$input.attr("pattern")}if($input.attr("maxlength")){validation.push("length");attrs["data-validation-length"]="max"+$input.attr("maxlength")}if(!SUPPORTS_DATALIST&&$input.attr("list")){var
suggestions=[];$("#"+$input.attr("list")+" option").each(function(){var
$opt=$(this);suggestions.push($opt.attr("value")||$opt.text())});$.formUtils.suggest($input,suggestions)}if(validation.length){if(!isRequired){attrs["data-validation-optional"]="true"}foundHtml5Rule=true;$input.attr("data-validation",validation.join("
"));$.each(attrs,function(attrName,attrVal){$input.attr(attrName,attrVal)})}});if(foundHtml5Rule){$f.trigger("html5ValidationAttrsFound")}if(!SUPPORTS_PLACEHOLDER){$formInputs.filter("input[placeholder]").each(function(){this.defaultValue=this.getAttribute("placeholder");$(this).bind("focus",function(){if(this.value==this.defaultValue){this.value="";$(this).removeClass("showing-placeholder")}}).bind("blur",function(){if($.trim(this.value)==""){this.value=this.defaultValue;$(this).addClass("showing-placeholder")}})})}})})})(jQuery,window);
\ No newline at end of file
Added:
branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.js
===================================================================
--- branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.js
(rev 0)
+++ branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.js
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,1689 @@
+/**
+* jQuery Form Validator
+* ------------------------------------------
+* Created by Victor Jonsson <http://www.victorjonsson.se>
+*
+* @website http://formvalidator.net/
+* @license Dual licensed under the MIT or GPL Version 2 licenses
+* @version 2.2.beta.13
+*/
+(function($) {
+
+ 'use strict';
+
+ var $window = $(window),
+ _applyErrorStyle = function($elem, conf) {
+ var $parent = $elem.parent();
+ $elem
+ .addClass(conf.errorElementClass)
+ .removeClass('valid');
+ if($parent.hasClass("input-group")) $parent = $parent.parent();
+
+ $parent.addClass('has-error') .removeClass('has-success');
//twitter bs
+
+
+ if(conf.borderColorOnError !== '') {
+ $elem.css('border-color', conf.borderColorOnError);
+ }
+ },
+ _removeErrorStyle = function($elem, conf) {
+ $elem.each(function() {
+ _setInlineErrorMessage($(this), '', conf,
conf.errorMessagePosition);
+ var $parent = $(this).parent();
+
+ if($parent.hasClass("input-group")) $parent = $parent.parent();
+ $(this)
+ .removeClass('valid')
+ .removeClass(conf.errorElementClass)
+ .css('border-color', '');
+ $parent
+ .removeClass('has-error')
+ .removeClass('has-success')
+ .find('.'+conf.errorMessageClass) // remove inline error
message
+ .remove();
+ });
+ },
+ _setInlineErrorMessage = function($input, mess, conf,
$messageContainer) {
+ var custom = _getInlineErrorElement($input);
+ var $parent = $input.parent();
+ if($parent.hasClass("input-group")) $parent = $parent.parent();
+ if( custom ) {
+ custom.innerHTML = mess;
+ }
+ else if( typeof $messageContainer == 'object' ) {
+ var $found = false;
+
$messageContainer.find('.'+conf.errorMessageClass).each(function() {
+ if( this.inputReferer == $input[0] ) {
+ $found = $(this);
+ return false;
+ }
+ });
+ if( $found ) {
+ if( !mess ) {
+ $found.remove();
+ } else {
+ $found.html(mess);
+ }
+ } else {
+ var $mess = $('<div
class="'+conf.errorMessageClass+'">'+mess+'</div>');
+ $mess[0].inputReferer = $input[0];
+ $messageContainer.prepend($mess);
+ }
+ }
+ else {
+ var $mess =
$parent.find('.'+conf.errorMessageClass+'.help-block');
+ if( $mess.length == 0 ) {
+ $mess =
$('<span></span>').addClass('help-block').addClass(conf.errorMessageClass);
+ $mess.appendTo($parent);
+ }
+ $mess.html(mess);
+ }
+ },
+ _getInlineErrorElement = function($input, conf) {
+ return document.getElementById($input.attr('name')+'_err_msg');
+ },
+ _templateMessage = function($form, title, errorMessages, conf) {
+ var messages =
conf.errorMessageTemplate.messages.replace(/\{errorTitle\}/g, title);
+ var fields = [];
+ $.each(errorMessages, function(i, msg) {
+
fields.push(conf.errorMessageTemplate.field.replace(/\{msg\}/g, msg));
+ });
+ messages = messages.replace(/\{fields\}/g, fields.join(''));
+ var container =
conf.errorMessageTemplate.container.replace(/\{errorMessageClass\}/g,
conf.errorMessageClass);
+ container = container.replace(/\{messages\}/g, messages);
+ $form.children().eq(0).before(container);
+ };
+
+ /**
+ * Assigns validateInputOnBlur function to elements blur event
+ *
+ * @param {Object} language Optional, will override $.formUtils.LANG
+ * @param {Object} settings Optional, will override the default settings
+ * @return {jQuery}
+ */
+ $.fn.validateOnBlur = function(language, settings) {
+
this.find('input[data-validation],textarea[data-validation],select[data-validation]')
+ .bind('blur.validation', function() {
+ $(this).validateInputOnBlur(language, settings, true, 'blur');
+ });
+
+ return this;
+ };
+
+ /*
+ * Assigns validateInputOnBlur function to elements custom event
+ * @param {Object} language Optional, will override $.formUtils.LANG
+ * @param {Object} settings Optional, will override the default settings
+ * * @return {jQuery}
+ */
+ $.fn.validateOnEvent = function(language, settings) {
+
this.find('input[data-validation][data-validation-event],textarea[data-validation][data-validation-event],select[data-validation][data-validation-event]')
+ .each(function(){
+ var $el = $(this),
+ etype = $el.attr("data-validation-event");
+ if (etype){
+ $el.bind(etype + ".validation",
function(){
+ $(this).validateInputOnBlur(language, settings,
true, etype);
+ });
+ }
+ });
+ return this;
+ };
+
+ /**
+ * fade in help message when input gains focus
+ * fade out when input loses focus
+ * <input data-help="The info that I want to display for the user when
input is focused" ... />
+ *
+ * @param {String} attrName - Optional, default is data-help
+ * @return {jQuery}
+ */
+ $.fn.showHelpOnFocus = function(attrName) {
+ if(!attrName) {
+ attrName = 'data-validation-help';
+ }
+
+ // Remove previously added event listeners
+ this.find('.has-help-txt')
+ .valAttr('has-keyup-event', false)
+ .removeClass('has-help-txt');
+
+ // Add help text listeners
+ this.find('textarea,input').each(function() {
+ var $elem = $(this),
+ className = 'jquery_form_help_' + ($elem.attr('name') ||
'').replace( /(:|\.|\[|\])/g, "" ),
+ help = $elem.attr(attrName);
+
+ if(help) {
+ $elem
+ .addClass('has-help-txt')
+ .unbind('focus.help')
+ .bind('focus.help', function() {
+ var $help = $elem.parent().find('.'+className);
+ if($help.length == 0) {
+ $help = $('<span />')
+ .addClass(className)
+ .addClass('help')
+ .addClass('help-block') // twitter bs
+ .text(help)
+ .hide();
+
+ $elem.after($help);
+
+ }
+ $help.fadeIn();
+ })
+ .unbind('blur.help')
+ .bind('blur.help', function() {
+ $(this)
+ .parent()
+ .find('.'+className)
+ .fadeOut('slow');
+ });
+ }
+ });
+
+ return this;
+ };
+
+ /**
+ * Validate single input when it loses focus
+ * shows error message in a span element
+ * that is appended to the parent element
+ *
+ * @param {Object} [language] Optional, will override $.formUtils.LANG
+ * @param {Object} [conf] Optional, will override the default settings
+ * @param {Boolean} attachKeyupEvent Optional
+ * @param {String} eventType
+ * @return {jQuery}
+ */
+ $.fn.validateInputOnBlur = function(language, conf, attachKeyupEvent,
eventType) {
+ $.formUtils.eventType = eventType;
+
+ if( (this.valAttr('suggestion-nr') || this.valAttr('postpone') ||
this.hasClass('hasDatepicker')) && !window.postponedValidation ) {
+ // This validation has to be postponed
+ var _self = this,
+ postponeTime = this.valAttr('postpone') || 200;
+
+ window.postponedValidation = function() {
+ _self.validateInputOnBlur(language, conf, attachKeyupEvent,
eventType);
+ window.postponedValidation = false;
+ };
+ setTimeout(function() {
+ if( window.postponedValidation ) {
+ window.postponedValidation();
+ }
+ }, postponeTime);
+
+ return this;
+ }
+
+ language = $.extend({}, $.formUtils.LANG, language || {});
+ _removeErrorStyle(this, conf);
+ var $elem = this,
+ $form = $elem.closest("form"),
+ validationRule = $elem.attr(conf.validationRuleAttribute),
+ validation = $.formUtils.validateInput(
+ $elem,
+ language,
+ $.extend({}, conf,
{errorMessagePosition:'element'}),
+ $form,
+ eventType
+ );
+
+ if(validation === true) {
+ $elem
+ .addClass('valid')
+ .parent()
+ .addClass('has-success'); // twitter bs
+ } else if(validation !== null) {
+
+ _applyErrorStyle($elem, conf);
+ _setInlineErrorMessage($elem, validation, conf,
conf.errorMessagePosition);
+
+ if(attachKeyupEvent) {
+ $elem
+ .unbind('keyup.validation')
+ .bind('keyup.validation', function() {
+ $(this).validateInputOnBlur(language, conf, false,
'keyup');
+ });
+ }
+ }
+
+ return this;
+ };
+
+ /**
+ * Short hand for fetching/adding/removing element attributes
+ * prefixed with 'data-validation-'
+ *
+ * @param {String} name
+ * @param {String|Boolean} [val]
+ * @return string|undefined
+ * @protected
+ */
+ $.fn.valAttr = function(name, val) {
+ if( val === undefined ) {
+ return this.attr('data-validation-'+name);
+ } else if( val === false || val === null ) {
+ return this.removeAttr('data-validation-'+name);
+ } else {
+ if(name.length > 0) name='-'+name;
+ return this.attr('data-validation'+name, val);
+ }
+ };
+
+ /**
+ * Function that validate all inputs in given element
+ *
+ * @param {Object} [language]
+ * @param {Object} [conf]
+ * @param {Boolean} [displayError] Defaults to true
+ */
+ $.fn.isValid = function(language, conf, displayError) {
+
+ if ($.formUtils.isLoadingModules) {
+ var $self = this;
+ setTimeout(function () {
+ $self.isValid(language, conf, displayError);
+ }, 200);
+ return null;
+ }
+
+ conf = $.extend({}, $.formUtils.defaultConfig(), conf || {});
+ language = $.extend({}, $.formUtils.LANG, language || {});
+ displayError = displayError !== false;
+
+ $.formUtils.isValidatingEntireForm = true;
+ $.formUtils.haltValidation = false;
+
+ /**
+ * Adds message to error message stack if not already in the message
stack
+ *
+ * @param {String} mess
+ * @para {jQuery} $elem
+ */
+ var addErrorMessage = function(mess, $elem) {
+ // validate server side will return null as error message before
the server is requested
+ if(mess !== null) {
+ if ($.inArray(mess, errorMessages) < 0) {
+ errorMessages.push(mess);
+ }
+ errorInputs.push($elem);
+ $elem.attr('current-error', mess);
+ if( displayError )
+ _applyErrorStyle($elem, conf);
+ }
+ },
+
+ /** Error messages for this validation */
+ errorMessages = [],
+
+ /** Input elements which value was not valid */
+ errorInputs = [],
+
+ /** Form instance */
+ $form = this,
+
+ /**
+ * Tells whether or not to validate element with this name and of this
type
+ *
+ * @param {String} name
+ * @param {String} type
+ * @return {Boolean}
+ */
+ ignoreInput = function(name, type) {
+ if (type === 'submit' || type === 'button' || type == 'reset') {
+ return true;
+ }
+ return $.inArray(name, conf.ignore || []) > -1;
+ };
+
+ // Reset style and remove error class
+ if( displayError ) {
+ $form.find('.'+conf.errorMessageClass+'.alert').remove();
+
_removeErrorStyle($form.find('.'+conf.errorElementClass+',.valid'), conf);
+ }
+
+ // Validate element values
+
$form.find('input,textarea,select').filter(':not([type="submit"],[type="button"])').each(function()
{
+ var $elem = $(this);
+ var elementType = $elem.attr('type');
+ if (!ignoreInput($elem.attr('name'), elementType)) {
+
+ var validation = $.formUtils.validateInput(
+ $elem,
+ language,
+ conf,
+ $form,
+ 'submit'
+ );
+
+ // Run element validation callback
+ if( typeof conf.onElementValidate == 'function' ) {
+ conf.onElementValidate((validation === true), $elem,
$form, validation);
+ }
+
+ if(validation !== true) {
+ addErrorMessage(validation, $elem);
+ } else {
+ $elem
+ .valAttr('current-error', false)
+ .addClass('valid')
+ .parent()
+ .addClass('has-success');
+ }
+ }
+
+ });
+
+ // Run validation callback
+ if( typeof conf.onValidate == 'function' ) {
+ var errors = conf.onValidate($form);
+ if( $.isArray(errors) ) {
+ $.each(errors, function(i, err) {
+ addErrorMessage(err.message, err.element);
+ });
+ }
+ else if( errors && errors.element && errors.message ) {
+ addErrorMessage(errors.message, errors.element);
+ }
+ }
+
+ // Reset form validation flag
+ $.formUtils.isValidatingEntireForm = false;
+
+ // Validation failed
+ if ( !$.formUtils.haltValidation && errorInputs.length > 0 ) {
+
+ if( displayError ) {
+ // display all error messages in top of form
+ if (conf.errorMessagePosition === 'top') {
+ _templateMessage($form, language.errorTitle,
errorMessages, conf);
+ }
+ // Customize display message
+ else if(conf.errorMessagePosition === 'custom') {
+ if( typeof conf.errorMessageCustom === 'function' ) {
+ conf.errorMessageCustom($form, language.errorTitle,
errorMessages, conf);
+ }
+ }
+ // Display error message below input field or in defined
container
+ else {
+ $.each(errorInputs, function(i, $input) {
+ _setInlineErrorMessage($input,
$input.attr('current-error'), conf, conf.errorMessagePosition);
+ });
+ }
+
+ if(conf.scrollToTopOnError) {
+ $window.scrollTop($form.offset().top - 20);
+ }
+ }
+
+ return false;
+ }
+
+ return !$.formUtils.haltValidation;
+ };
+
+ /**
+ * @deprecated
+ * @param language
+ * @param conf
+ */
+ $.fn.validateForm = function(language, conf) {
+ if( window.console && typeof window.console.warn == 'function' ) {
+ window.console.warn('Use of deprecated function $.validateForm,
use $.isValid instead');
+ }
+ return this.isValid(language, conf, true);
+ }
+
+ /**
+ * Plugin for displaying input length restriction
+ */
+ $.fn.restrictLength = function(maxLengthElement) {
+ new $.formUtils.lengthRestriction(this, maxLengthElement);
+ return this;
+ };
+
+ /**
+ * Add suggestion dropdown to inputs having data-suggestions with a comma
+ * separated string with suggestions
+ * @param {Array} [settings]
+ * @returns {jQuery}
+ */
+ $.fn.addSuggestions = function(settings) {
+ var sugs = false;
+ this.find('input').each(function() {
+ var $field = $(this);
+
+ sugs = $.split($field.attr('data-suggestions'));
+
+ if( sugs.length > 0 && !$field.hasClass('has-suggestions') ) {
+ $.formUtils.suggest($field, sugs, settings);
+ $field.addClass('has-suggestions');
+ }
+ });
+ return this;
+ };
+
+ /**
+ * A bit smarter split function
+ * @param {String} val
+ * @param {Function|String} [func]
+ * @param {String} [delim]
+ * @returns {Array|void}
+ */
+ $.split = function(val, func, delim) {
+ if( typeof func != 'function' ) {
+ // return string
+ if( !val )
+ return [];
+ var values = [];
+ $.each(val.split(func ? func:','), function(i,str) {
+ str = $.trim(str);
+ if( str.length )
+ values.push(str);
+ });
+ return values;
+ } else if( val ) {
+ // use callback on each
+ if( !delim )
+ delim = ',';
+ $.each(val.split(delim), function(i, str) {
+ str = $.trim(str);
+ if( str.length )
+ return func(str, i);
+ });
+ }
+ };
+
+ /**
+ * Short hand function that makes the validation setup require less code
+ * @param conf
+ */
+ $.validate = function(conf) {
+
+ var defaultConf = $.extend($.formUtils.defaultConfig(), {
+ form : 'form',
+ /*
+ * Enable custom event for validation
+ */
+ validateOnEvent : true,
+ validateOnBlur : true,
+ showHelpOnFocus : true,
+ addSuggestions : true,
+ modules : '',
+ onModulesLoaded : null,
+ language : false,
+ onSuccess : false,
+ onError : false,
+ onElementValidate : false
+ });
+
+ conf = $.extend(defaultConf, conf || {});
+
+ // Add validation to forms
+ $(conf.form).each(function(i, form) {
+
+ var $form = $(form);
+ $window.trigger('formValidationSetup', [$form]);
+
+ // Remove all event listeners previously added
+ $form.find('.has-help-txt')
+ .unbind('focus.validation')
+ .unbind('blur.validation');
+ $form
+ .removeClass('has-validation-callback')
+ .unbind('submit.validation')
+ .unbind('reset.validation')
+ .find('input[data-validation],textarea[data-validation]')
+ .unbind('blur.validation');
+
+ // Validate when submitted
+ $form.bind('submit.validation', function() {
+ var $form = $(this);
+
+ if($.formUtils.isLoadingModules) {
+ setTimeout(function() {
+ $form.trigger('submit.validation');
+ }, 200);
+ return false;
+ }
+ var valid = $form.isValid(conf.language, conf);
+ if( valid && typeof conf.onSuccess == 'function') {
+ var callbackResponse = conf.onSuccess($form);
+ if( callbackResponse === false )
+ return false;
+ } else if ( !valid && typeof conf.onError == 'function' ) {
+ conf.onError($form);
+ return false;
+ } else {
+ return valid;
+ }
+ })
+ .bind('reset.validation', function() {
+ // remove messages
+ $(this).find('.'+conf.errorMessageClass+'.alert').remove();
+
_removeErrorStyle($(this).find('.'+conf.errorElementClass+',.valid'), conf);
+ })
+ .addClass('has-validation-callback');
+
+ if( conf.showHelpOnFocus ) {
+ $form.showHelpOnFocus();
+ }
+ if( conf.addSuggestions ) {
+ $form.addSuggestions();
+ }
+ if( conf.validateOnBlur ) {
+ $form.validateOnBlur(conf.language, conf);
+ $form.bind('html5ValidationAttrsFound', function() {
+ $form.validateOnBlur(conf.language, conf);
+ })
+ }
+ if( conf.validateOnEvent ){
+ $form.validateOnEvent(conf.language, conf);
+ }
+
+ });
+
+ if( conf.modules != '' ) {
+ if( typeof conf.onModulesLoaded == 'function' ) {
+ $window.one('validatorsLoaded', conf.onModulesLoaded);
+ }
+ $.formUtils.loadModules(conf.modules);
+ }
+ };
+
+ /**
+ * Object containing utility methods for this plugin
+ */
+ $.formUtils = {
+
+ /**
+ * Default config for $(...).isValid();
+ */
+ defaultConfig : function() {
+ return {
+ ignore : [], // Names of inputs not to be validated even
though node attribute containing the validation rules tells us to
+ errorElementClass : 'error', // Class that will be put on
elements which value is invalid
+ borderColorOnError : 'red', // Border color of elements which
value is invalid, empty string to not change border color
+ errorMessageClass : 'form-error', // class name of div
containing error messages when validation fails
+ validationRuleAttribute : 'data-validation', // name of the
attribute holding the validation rules
+ validationErrorMsgAttribute : 'data-validation-error-msg', //
define custom err msg inline with element
+ errorMessagePosition : 'element', // Can be either "top" or
"element" or "custom"
+ errorMessageTemplate : {
+ container: '<div class="{errorMessageClass} alert
alert-danger">{messages}</div>',
+ messages: '<strong>{errorTitle}</strong><ul>{fields}</ul>',
+ field: '<li>{msg}</li>'
+ },
+ errorMessageCustom: _templateMessage,
+ scrollToTopOnError : true,
+ dateFormat : 'yyyy-mm-dd',
+ addValidClassOnAll : false, // whether or not to apply
class="valid" even if the input wasn't validated
+ decimalSeparator : '.'
+ }
+ },
+
+ /**
+ * Available validators
+ */
+ validators : {},
+
+ /**
+ * Events triggered by form validator
+ */
+ _events : {load : [], valid: [], invalid:[]},
+
+ /**
+ * Setting this property to true during validation will
+ * stop further validation from taking place and form will
+ * not be sent
+ */
+ haltValidation : false,
+
+ /**
+ * This variable will be true $.fn.isValid() is called
+ * and false when $.fn.validateOnBlur is called
+ */
+ isValidatingEntireForm : false,
+
+ /**
+ * Function for adding a validator
+ * @param {Object} validator
+ */
+ addValidator : function(validator) {
+ // prefix with "validate_" for backward compatibility reasons
+ var name = validator.name.indexOf('validate_') === 0 ?
validator.name : 'validate_'+validator.name;
+ if( validator.validateOnKeyUp === undefined )
+ validator.validateOnKeyUp = true;
+ this.validators[name] = validator;
+ },
+
+ /**
+ * @var {Boolean}
+ */
+ isLoadingModules : false,
+
+ /**
+ * @var {Object}
+ */
+ loadedModules : {},
+
+ /**
+ * @example
+ * $.formUtils.loadModules('date, security.dev');
+ *
+ * Will load the scripts date.js and security.dev.js from the
+ * directory where this script resides. If you want to load
+ * the modules from another directory you can use the
+ * path argument.
+ *
+ * The script will be cached by the browser unless the module
+ * name ends with .dev
+ *
+ * @param {String} modules - Comma separated string with module file
names (no directory nor file extension)
+ * @param {String} [path] - Optional, path where the module files is
located if their not in the same directory as the core modules
+ * @param {Boolean} [fireEvent] - Optional, whether or not to fire
event 'load' when modules finished loading
+ */
+ loadModules : function(modules, path, fireEvent) {
+
+ if( fireEvent === undefined )
+ fireEvent = true;
+
+ if( $.formUtils.isLoadingModules ) {
+ setTimeout(function() {
+ $.formUtils.loadModules(modules, path, fireEvent);
+ });
+ return;
+ }
+
+ var hasLoadedAnyModule = false,
+ loadModuleScripts = function(modules, path) {
+
+ var moduleList = $.split(modules),
+ numModules = moduleList.length,
+ moduleLoadedCallback = function() {
+ numModules--;
+ if( numModules == 0 ) {
+ $.formUtils.isLoadingModules = false;
+ if( fireEvent && hasLoadedAnyModule ) {
+ $window.trigger('validatorsLoaded');
+ }
+ }
+ };
+
+ if( numModules > 0 ) {
+ $.formUtils.isLoadingModules = true;
+ }
+
+ var cacheSuffix = '?__='+( new Date().getTime() ),
+ appendToElement =
document.getElementsByTagName('head')[0] ||
document.getElementsByTagName('body')[0];
+
+ $.each(moduleList, function(i, modName) {
+ modName = $.trim(modName);
+ if( modName.length == 0 ) {
+ moduleLoadedCallback();
+ }
+ else {
+ var scriptUrl = path + modName +
(modName.substr(-3) == '.js' ? '':'.js'),
+ script = document.createElement('SCRIPT');
+
+ if( scriptUrl in $.formUtils.loadedModules ) {
+ // already loaded
+ moduleLoadedCallback();
+ }
+ else {
+
+ // Remember that this script is loaded
+ $.formUtils.loadedModules[scriptUrl] = 1;
+ hasLoadedAnyModule = true;
+
+ // Load the script
+ script.type = 'text/javascript';
+ script.onload = moduleLoadedCallback;
+ script.src = scriptUrl + (
scriptUrl.substr(-7) == '.dev.js' ? cacheSuffix:'' );
+ script.onreadystatechange = function() {
+ // IE 7 fix
+ if( this.readyState == 'complete' ||
this.readyState == 'loaded' ) {
+ moduleLoadedCallback();
+ // Handle memory leak in IE
+ this.onload = null;
+ this.onreadystatechange = null;
+ }
+ };
+ appendToElement.appendChild( script );
+ }
+ }
+ });
+ };
+
+ if( path ) {
+ loadModuleScripts(modules, path);
+ } else {
+ var findScriptPathAndLoadModules = function() {
+ var foundPath = false;
+ $('script[src*="form-validator"]').each(function() {
+ foundPath = this.src.substr(0,
this.src.lastIndexOf('/')) + '/';
+ if( foundPath == '/' )
+ foundPath = '';
+ return false;
+ });
+
+ if( foundPath !== false) {
+ loadModuleScripts(modules, foundPath);
+ return true;
+ }
+ return false;
+ };
+
+ if( !findScriptPathAndLoadModules() ) {
+ $(findScriptPathAndLoadModules);
+ }
+ }
+ },
+
+ /**
+ * Validate the value of given element according to the validation rules
+ * found in the attribute data-validation. Will return null if no
validation
+ * should take place, returns true if valid or error message if not
valid
+ *
+ * @param {jQuery} $elem
+ * @param {Object} language ($.formUtils.LANG)
+ * @param {Object} conf
+ * @param {jQuery} $form
+ * @param {String} [eventContext]
+ * @return {String|Boolean}
+ */
+ validateInput : function($elem, language, conf, $form, eventContext) {
+
+ if( $elem.attr('disabled') )
+ return null; // returning null will prevent that the valid
class gets applied to the element
+
+ $elem.trigger('beforeValidation');
+
+ var value = $elem.val() || '',
+ optional = $elem.valAttr('optional'),
+
+ // test if a checkbox forces this element to be validated
+ validationDependsOnCheckedInput = false,
+ validationDependentInputIsChecked = false,
+ validateIfCheckedElement = false,
+
+ // get value of this element's attribute "... if-checked"
+ validateIfCheckedElementName = $elem.valAttr("if-checked");
+
+ // make sure we can proceed
+ if (validateIfCheckedElementName != null) {
+
+ // Set the boolean telling us that the validation depends
+ // on another input being checked
+ validationDependsOnCheckedInput = true;
+
+ // select the checkbox type element in this form
+ validateIfCheckedElement = $form.find('input[name="' +
validateIfCheckedElementName + '"]');
+
+ // test if it's property "checked" is checked
+ if ( validateIfCheckedElement.prop('checked') ) {
+ // set value for validation checkpoint
+ validationDependentInputIsChecked = true;
+ }
+ }
+
+ // validation checkpoint
+ // if empty AND optional attribute is present
+ // OR depending on a checkbox being checked AND checkbox is
checked, return true
+ if ((!value && optional === 'true') ||
(validationDependsOnCheckedInput && !validationDependentInputIsChecked)) {
+ return conf.addValidClassOnAll ? true:null;
+ }
+
+ var validationRules = $elem.attr(conf.validationRuleAttribute),
+
+ // see if form element has inline err msg attribute
+ validationErrorMsg = true;
+
+ if( !validationRules ) {
+ return conf.addValidClassOnAll ? true:null;
+ }
+
+ $.split(validationRules, function(rule) {
+ if( rule.indexOf('validate_') !== 0 ) {
+ rule = 'validate_' + rule;
+ }
+
+ var validator = $.formUtils.validators[rule];
+
+ if( validator && typeof validator['validatorFunction'] ==
'function' ) {
+ // special change of element for checkbox_group rule
+ if ( rule == 'validate_checkbox_group' ) {
+ // set element to first in group, so error msg is set
only once
+ $elem = $("[name='"+$elem.attr('name')+"']:eq(0)");
+ }
+
+ var isValid = null;
+ if( eventContext != 'keyup' || validator.validateOnKeyUp )
{
+ isValid = validator.validatorFunction(value, $elem,
conf, language, $form);
+ }
+
+ if(!isValid) {
+ validationErrorMsg = null;
+ if( isValid !== null ) {
+ validationErrorMsg =
$elem.attr(conf.validationErrorMsgAttribute+'-'+rule.replace('validate_', ''));
+ if( !validationErrorMsg ) {
+ validationErrorMsg =
$elem.attr(conf.validationErrorMsgAttribute);
+ if( !validationErrorMsg ) {
+ validationErrorMsg =
language[validator.errorMessageKey];
+ if( !validationErrorMsg )
+ validationErrorMsg =
validator.errorMessage;
+ }
+ }
+ }
+ return false; // breaks the iteration
+ }
+
+ } else {
+ throw new Error('Using undefined validator "'+rule+'"');
+ }
+
+ }, ' ');
+
+ if( typeof validationErrorMsg == 'string' ) {
+ $elem.trigger('validation', false);
+ return validationErrorMsg;
+ } else if( validationErrorMsg === null && !conf.addValidClassOnAll
) {
+ return null;
+ } else {
+ $elem.trigger('validation', true);
+ return true;
+ }
+ },
+
+ /**
+ * Is it a correct date according to given dateFormat. Will return
false if not, otherwise
+ * an array 0=>year 1=>month 2=>day
+ *
+ * @param {String} val
+ * @param {String} dateFormat
+ * @return {Array}|{Boolean}
+ */
+ parseDate : function(val, dateFormat) {
+ var divider = dateFormat.replace(/[a-zA-Z]/gi, '').substring(0,1),
+ regexp = '^',
+ formatParts = dateFormat.split(divider),
+ matches, day, month, year;
+
+ $.each(formatParts, function(i, part) {
+ regexp += (i > 0 ? '\\'+divider:'') + '(\\d{'+part.length+'})';
+ });
+
+ regexp += '$';
+
+ matches = val.match(new RegExp(regexp));
+ if (matches === null) {
+ return false;
+ }
+
+ var findDateUnit = function(unit, formatParts, matches) {
+ for(var i=0; i < formatParts.length; i++) {
+ if(formatParts[i].substring(0,1) === unit) {
+ return $.formUtils.parseDateInt(matches[i+1]);
+ }
+ }
+ return -1;
+ };
+
+ month = findDateUnit('m', formatParts, matches);
+ day = findDateUnit('d', formatParts, matches);
+ year = findDateUnit('y', formatParts, matches);
+
+ if ((month === 2 && day > 28 && (year % 4 !== 0 || year % 100 ===
0 && year % 400 !== 0))
+ || (month === 2 && day > 29 && (year % 4 === 0 || year % 100
!== 0 && year % 400 === 0))
+ || month > 12 || month === 0) {
+ return false;
+ }
+ if ((this.isShortMonth(month) && day > 30) ||
(!this.isShortMonth(month) && day > 31) || day === 0) {
+ return false;
+ }
+
+ return [year, month, day];
+ },
+
+ /**
+ * skum fix. är talet 05 eller lägre ger parseInt rätt int annars får
man 0 när man kör parseInt?
+ *
+ * @param {String} val
+ * @param {Number}
+ */
+ parseDateInt : function(val) {
+ if (val.indexOf('0') === 0) {
+ val = val.replace('0', '');
+ }
+ return parseInt(val,10);
+ },
+
+ /**
+ * Has month only 30 days?
+ *
+ * @param {Number} m
+ * @return {Boolean}
+ */
+ isShortMonth : function(m) {
+ return (m % 2 === 0 && m < 7) || (m % 2 !== 0 && m > 7);
+ },
+
+ /**
+ * Restrict input length
+ *
+ * @param {jQuery} $inputElement Jquery Html object
+ * @param {jQuery} $maxLengthElement jQuery Html Object
+ * @return void
+ */
+ lengthRestriction : function($inputElement, $maxLengthElement) {
+ // read maxChars from counter display initial text value
+ var maxChars = parseInt($maxLengthElement.text(),10),
+ charsLeft = 0,
+
+ // internal function does the counting and sets display value
+ countCharacters = function() {
+ var numChars = $inputElement.val().length;
+ if(numChars > maxChars) {
+ // get current scroll bar position
+ var currScrollTopPos = $inputElement.scrollTop();
+ // trim value to max length
+ $inputElement.val($inputElement.val().substring(0,
maxChars));
+ $inputElement.scrollTop(currScrollTopPos);
+ }
+ charsLeft = maxChars - numChars;
+ if( charsLeft < 0 )
+ charsLeft = 0;
+
+ // set counter text
+ $maxLengthElement.text(charsLeft);
+ };
+
+ // bind events to this element
+ // setTimeout is needed, cut or paste fires before val is available
+ $($inputElement).bind('keydown keyup keypress focus blur',
countCharacters )
+ .bind('cut paste', function(){ setTimeout(countCharacters,
100); } ) ;
+
+ // count chars on pageload, if there are prefilled input-values
+ $(document).bind("ready", countCharacters);
+ },
+
+ /**
+ * Test numeric against allowed range
+ *
+ * @param $value int
+ * @param $rangeAllowed str; (1-2, min1, max2)
+ * @return array
+ */
+ numericRangeCheck : function(value, rangeAllowed)
+ {
+ // split by dash
+ var range = $.split(rangeAllowed, '-');
+ // min or max
+ var minmax = parseInt(rangeAllowed.substr(3),10)
+ // range ?
+ if (range.length == 2 && (value < parseInt(range[0],10) || value >
parseInt(range[1],10) ) )
+ { return [ "out", range[0], range[1] ] ; } // value is out of
range
+ else if (rangeAllowed.indexOf('min') === 0 && (value < minmax ) )
// min
+ { return ["min", minmax]; } // value is below min
+ else if (rangeAllowed.indexOf('max') === 0 && (value > minmax ) )
// max
+ { return ["max", minmax]; } // value is above max
+ // since no other returns executed, value is in allowed range
+ return [ "ok" ] ;
+ },
+
+
+ _numSuggestionElements : 0,
+ _selectedSuggestion : null,
+ _previousTypedVal : null,
+
+ /**
+ * Utility function that can be used to create plugins that gives
+ * suggestions when inputs is typed into
+ * @param {jQuery} $elem
+ * @param {Array} suggestions
+ * @param {Object} settings - Optional
+ * @return {jQuery}
+ */
+ suggest : function($elem, suggestions, settings) {
+ var conf = {
+ css : {
+ maxHeight: '150px',
+ background: '#FFF',
+ lineHeight:'150%',
+ textDecoration : 'underline',
+ overflowX : 'hidden',
+ overflowY : 'auto',
+ border : '#CCC solid 1px',
+ borderTop : 'none',
+ cursor: 'pointer'
+ },
+ activeSuggestionCSS : {
+ background : '#E9E9E9'
+ }
+ },
+ setSuggsetionPosition = function($suggestionContainer, $input) {
+ var offset = $input.offset();
+ $suggestionContainer.css({
+ width : $input.outerWidth(),
+ left : offset.left + 'px',
+ top : (offset.top + $input.outerHeight()) +'px'
+ });
+ };
+
+ if(settings)
+ $.extend(conf, settings);
+
+ conf.css['position'] = 'absolute';
+ conf.css['z-index'] = 9999;
+ $elem.attr('autocomplete', 'off');
+
+ if( this._numSuggestionElements === 0 ) {
+ // Re-position suggestion container if window size changes
+ $window.bind('resize', function() {
+ $('.jquery-form-suggestions').each(function() {
+ var $container = $(this),
+ suggestID =
$container.attr('data-suggest-container');
+ setSuggsetionPosition($container,
$('.suggestions-'+suggestID).eq(0));
+ });
+ });
+ }
+
+ this._numSuggestionElements++;
+
+ var onSelectSuggestion = function($el) {
+ var suggestionId = $el.valAttr('suggestion-nr');
+ $.formUtils._selectedSuggestion = null;
+ $.formUtils._previousTypedVal = null;
+ $('.jquery-form-suggestion-'+suggestionId).fadeOut('fast');
+ };
+
+ $elem
+ .data('suggestions', suggestions)
+ .valAttr('suggestion-nr', this._numSuggestionElements)
+ .unbind('focus.suggest')
+ .bind('focus.suggest', function() {
+ $(this).trigger('keyup');
+ $.formUtils._selectedSuggestion = null;
+ })
+ .unbind('keyup.suggest')
+ .bind('keyup.suggest', function() {
+ var $input = $(this),
+ foundSuggestions = [],
+ val = $.trim($input.val()).toLocaleLowerCase();
+
+ if(val == $.formUtils._previousTypedVal) {
+ return;
+ }
+ else {
+ $.formUtils._previousTypedVal = val;
+ }
+
+ var hasTypedSuggestion = false,
+ suggestionId = $input.valAttr('suggestion-nr'),
+ $suggestionContainer =
$('.jquery-form-suggestion-'+suggestionId);
+
+ $suggestionContainer.scrollTop(0);
+
+ // Find the right suggestions
+ if(val != '') {
+ var findPartial = val.length > 2;
+ $.each($input.data('suggestions'), function(i,
suggestion) {
+ var lowerCaseVal = suggestion.toLocaleLowerCase();
+ if( lowerCaseVal == val ) {
+
foundSuggestions.push('<strong>'+suggestion+'</strong>');
+ hasTypedSuggestion = true;
+ return false;
+ } else if(lowerCaseVal.indexOf(val) === 0 ||
(findPartial && lowerCaseVal.indexOf(val) > -1)) {
+ foundSuggestions.push(suggestion.replace(new
RegExp(val, 'gi'), '<strong>$&</strong>'));
+ }
+ });
+ }
+
+ // Hide suggestion container
+ if(hasTypedSuggestion || (foundSuggestions.length == 0 &&
$suggestionContainer.length > 0)) {
+ $suggestionContainer.hide();
+ }
+
+ // Create suggestion container if not already exists
+ else if(foundSuggestions.length > 0 &&
$suggestionContainer.length == 0) {
+ $suggestionContainer =
$('<div></div>').css(conf.css).appendTo('body');
+ $elem.addClass('suggestions-'+suggestionId);
+ $suggestionContainer
+ .attr('data-suggest-container', suggestionId)
+ .addClass('jquery-form-suggestions')
+ .addClass('jquery-form-suggestion-'+suggestionId);
+ }
+
+ // Show hidden container
+ else if(foundSuggestions.length > 0 &&
!$suggestionContainer.is(':visible')) {
+ $suggestionContainer.show();
+ }
+
+ // add suggestions
+ if(foundSuggestions.length > 0 && val.length !=
foundSuggestions[0].length) {
+
+ // put container in place every time, just in case
+ setSuggsetionPosition($suggestionContainer, $input);
+
+ // Add suggestions HTML to container
+ $suggestionContainer.html('');
+ $.each(foundSuggestions, function(i, text) {
+ $('<div></div>')
+ .append(text)
+ .css({
+ overflow: 'hidden',
+ textOverflow : 'ellipsis',
+ whiteSpace : 'nowrap',
+ padding: '5px'
+ })
+ .addClass('form-suggest-element')
+ .appendTo($suggestionContainer)
+ .click(function() {
+ $input.focus();
+ $input.val( $(this).text() );
+ onSelectSuggestion($input);
+ });
+ });
+ }
+ })
+ .unbind('keydown.validation')
+ .bind('keydown.validation', function(e) {
+ var code = (e.keyCode ? e.keyCode : e.which),
+ suggestionId,
+ $suggestionContainer,
+ $input = $(this);
+
+ if(code == 13 && $.formUtils._selectedSuggestion !== null)
{
+ suggestionId = $input.valAttr('suggestion-nr');
+ $suggestionContainer =
$('.jquery-form-suggestion-'+suggestionId);
+ if($suggestionContainer.length > 0) {
+ var newText =
$suggestionContainer.find('div').eq($.formUtils._selectedSuggestion).text();
+ $input.val(newText);
+ onSelectSuggestion($input);
+ e.preventDefault();
+ }
+ }
+ else {
+ suggestionId = $input.valAttr('suggestion-nr');
+ $suggestionContainer =
$('.jquery-form-suggestion-'+suggestionId);
+ var $suggestions = $suggestionContainer.children();
+ if($suggestions.length > 0 && $.inArray(code, [38,40])
> -1) {
+ if(code == 38) { // key up
+ if($.formUtils._selectedSuggestion === null)
+ $.formUtils._selectedSuggestion =
$suggestions.length-1;
+ else
+ $.formUtils._selectedSuggestion--;
+ if($.formUtils._selectedSuggestion < 0)
+ $.formUtils._selectedSuggestion =
$suggestions.length-1;
+ }
+ else if(code == 40) { // key down
+ if($.formUtils._selectedSuggestion === null)
+ $.formUtils._selectedSuggestion = 0;
+ else
+ $.formUtils._selectedSuggestion++;
+ if($.formUtils._selectedSuggestion >
($suggestions.length-1))
+ $.formUtils._selectedSuggestion = 0;
+
+ }
+
+ // Scroll in suggestion window
+ var containerInnerHeight =
$suggestionContainer.innerHeight(),
+ containerScrollTop =
$suggestionContainer.scrollTop(),
+ suggestionHeight =
$suggestionContainer.children().eq(0).outerHeight(),
+ activeSuggestionPosY = suggestionHeight *
($.formUtils._selectedSuggestion);
+
+ if( activeSuggestionPosY < containerScrollTop ||
activeSuggestionPosY > (containerScrollTop+containerInnerHeight)) {
+ $suggestionContainer.scrollTop(
activeSuggestionPosY );
+ }
+
+ $suggestions
+ .removeClass('active-suggestion')
+ .css('background', 'none')
+ .eq($.formUtils._selectedSuggestion)
+ .addClass('active-suggestion')
+ .css(conf.activeSuggestionCSS);
+
+ e.preventDefault();
+ return false;
+ }
+ }
+ })
+ .unbind('blur.suggest')
+ .bind('blur.suggest', function() {
+ onSelectSuggestion($(this));
+ });
+
+ return $elem;
+ },
+
+ /**
+ * Error dialogs
+ *
+ * @var {Object}
+ */
+ LANG : {
+ errorTitle : 'Form submission failed!',
+ requiredFields : 'You have not answered all required fields',
+ badTime : 'You have not given a correct time',
+ badEmail : 'You have not given a correct e-mail address',
+ badTelephone : 'You have not given a correct phone number',
+ badSecurityAnswer : 'You have not given a correct answer to the
security question',
+ badDate : 'You have not given a correct date',
+ lengthBadStart : 'The input value must be between ',
+ lengthBadEnd : ' characters',
+ lengthTooLongStart : 'The input value is longer than ',
+ lengthTooShortStart : 'The input value is shorter than ',
+ notConfirmed : 'Input values could not be confirmed',
+ badDomain : 'Incorrect domain value',
+ badUrl : 'The input value is not a correct URL',
+ badCustomVal : 'The input value is incorrect',
+ badInt : 'The input value was not a correct number',
+ badSecurityNumber : 'Your social security number was incorrect',
+ badUKVatAnswer : 'Incorrect UK VAT Number',
+ badStrength : 'The password isn\'t strong enough',
+ badNumberOfSelectedOptionsStart : 'You have to choose at least ',
+ badNumberOfSelectedOptionsEnd : ' answers',
+ badAlphaNumeric : 'The input value can only contain alphanumeric
characters ',
+ badAlphaNumericExtra: ' and ',
+ wrongFileSize : 'The file you are trying to upload is too large',
+ wrongFileType : 'The file you are trying to upload is of wrong
type',
+ groupCheckedRangeStart : 'Please choose between ',
+ groupCheckedTooFewStart : 'Please choose at least ',
+ groupCheckedTooManyStart : 'Please choose a maximum of ',
+ groupCheckedEnd : ' item(s)',
+ badCreditCard : 'The credit card number is not correct',
+ badCVV : 'The CVV number was not correct'
+ }
+ };
+
+
+ /* * * * * * * * * * * * * * * * * * * * * *
+ CORE VALIDATORS
+ * * * * * * * * * * * * * * * * * * * * */
+
+
+ /*
+ * Validate email
+ */
+ $.formUtils.addValidator({
+ name : 'email',
+ validatorFunction : function(email) {
+
+ var emailParts = email.toLowerCase().split('@');
+ if( emailParts.length == 2 ) {
+ return
$.formUtils.validators.validate_domain.validatorFunction(emailParts[1]) &&
+ !(/[^\w\+\.\-]/.test(emailParts[0]));
+ }
+
+ return false;
+ },
+ errorMessage : '',
+ errorMessageKey : 'badEmail'
+ });
+
+ /*
+ * Validate domain name
+ */
+ $.formUtils.addValidator({
+ name : 'domain',
+ validatorFunction : function(val, $input) {
+
+ var topDomains = ['.ac', '.ad', '.ae', '.aero', '.af', '.ag',
'.ai', '.al', '.am', '.an', '.ao',
+ '.aq', '.ar', '.arpa', '.as', '.asia', '.at', '.au',
'.aw', '.ax', '.az', '.ba', '.bb',
+ '.bd', '.be', '.bf', '.bg', '.bh', '.bi', '.bike',
'.biz', '.bj', '.bm', '.bn', '.bo',
+ '.br', '.bs', '.bt', '.bv', '.bw', '.by', '.bz',
'.ca', '.camera', '.cat', '.cc', '.cd',
+ '.cf', '.cg', '.ch', '.ci', '.ck', '.cl', '.clothing',
'.cm', '.cn', '.co', '.com',
+ '.construction', '.contractors', '.coop', '.cr',
'.cu', '.cv', '.cw', '.cx', '.cy', '.cz',
+ '.de', '.diamonds', '.directory', '.dj', '.dk', '.dm',
'.do', '.dz', '.ec', '.edu', '.ee',
+ '.eg', '.enterprises', '.equipment', '.er', '.es',
'.estate', '.et', '.eu', '.fi', '.fj',
+ '.fk', '.fm', '.fo', '.fr', '.ga', '.gallery', '.gb',
'.gd', '.ge', '.gf', '.gg', '.gh',
+ '.gi', '.gl', '.gm', '.gn', '.gov', '.gp', '.gq',
'.gr', '.graphics', '.gs', '.gt', '.gu',
+ '.guru', '.gw', '.gy', '.hk', '.hm', '.hn',
'.holdings', '.hr', '.ht', '.hu', '.id', '.ie',
+ '.il', '.im', '.in', '.info', '.int', '.io', '.iq',
'.ir', '.is', '.it', '.je', '.jm', '.jo',
+ '.jobs', '.jp', '.ke', '.kg', '.kh', '.ki',
'.kitchen', '.km', '.kn', '.kp', '.kr', '.kw',
+ '.ky', '.kz', '.la', '.land', '.lb', '.lc', '.li',
'.lighting', '.lk', '.lr', '.ls', '.lt',
+ '.lu', '.lv', '.ly', '.ma', '.mc', '.md', '.me',
'.menu', '.mg', '.mh', '.mil', '.mk', '.ml',
+ '.mm', '.mn', '.mo', '.mobi', '.mp', '.mq', '.mr',
'.ms', '.mt', '.mu', '.museum', '.mv',
+ '.mw', '.mx', '.my', '.mz', '.na', '.name', '.nc',
'.ne', '.net', '.nf', '.ng', '.ni',
+ '.nl', '.no', '.np', '.nr', '.nu', '.nz', '.om',
'.org', '.pa', '.pe', '.pf', '.pg', '.ph',
+ '.photography', '.pk', '.pl', '.plumbing', '.pm',
'.pn', '.post', '.pr', '.pro', '.ps', '.pt',
+ '.pw', '.py', '.qa', '.re', '.ro', '.rs', '.ru',
'.rw', '.sa', '.sb', '.sc', '.sd', '.se',
+ '.sexy', '.sg', '.sh', '.si', '.singles', '.sj',
'.sk', '.sl', '.sm', '.sn', '.so', '.sr',
+ '.st', '.su', '.sv', '.sx', '.sy', '.sz', '.tattoo',
'.tc', '.td', '.technology', '.tel', '.tf',
+ '.tg', '.th', '.tips', '.tj', '.tk', '.tl', '.tm',
'.tn', '.to', '.today', '.tp', '.tr', '.travel',
+ '.tt', '.tv', '.tw', '.tz', '.ua', '.ug', '.uk',
'.uno', '.us', '.uy', '.uz', '.va', '.vc', '.ve',
+ '.ventures', '.vg', '.vi', '.vn', '.voyage', '.vu',
'.wf', '.ws', '.xn--3e0b707e', '.xn--45brj9c',
+ '.xn--80ao21a', '.xn--80asehdb', '.xn--80aswg',
'.xn--90a3ac', '.xn--clchc0ea0b2g2a9gcd', '.xn--fiqs8s',
+ '.xn--fiqz9s', '.xn--fpcrj9c3d', '.xn--fzc2c9e2c',
'.xn--gecrj9c', '.xn--h2brj9c', '.xn--j1amh',
+ '.xn--j6w193g', '.xn--kprw13d', '.xn--kpry57d',
'.xn--l1acc', '.xn--lgbbat1ad8j', '.xn--mgb9awbf',
+ '.xn--mgba3a4f16a', '.xn--mgbaam7a8h',
'.xn--mgbayh7gpa', '.xn--mgbbh1a71e', '.xn--mgbc0a9azcg',
+ '.xn--mgberp4a5d4ar', '.xn--mgbx4cd0ab',
'.xn--ngbc5azd', '.xn--o3cw4h', '.xn--ogbpf8fl', '.xn--p1ai',
+ '.xn--pgbs0dh', '.xn--q9jyb4c', '.xn--s9brj9c',
'.xn--unup4y', '.xn--wgbh1c', '.xn--wgbl6a',
+ '.xn--xkc2al3hye2a', '.xn--xkc2dl3a5ee0h',
'.xn--yfro4i67o', '.xn--ygbi2ammx', '.xxx', '.ye',
+ '.yt', '.za', '.zm', '.zw'],
+
+ ukTopDomains = ['co', 'me', 'ac', 'gov', 'judiciary','ltd',
'mod', 'net', 'nhs', 'nic',
+ 'org', 'parliament', 'plc', 'police', 'sch', 'bl',
'british-library', 'jet','nls'],
+
+ dot = val.lastIndexOf('.'),
+ domain = val.substring(0, dot),
+ ext = val.substring(dot, val.length),
+ hasTopDomain = false;
+
+ for (var i = 0; i < topDomains.length; i++) {
+ if (topDomains[i] === ext) {
+ if(ext==='.uk') {
+ //Run Extra Checks for UK Domain Names
+ var domainParts = val.split('.');
+ var tld2 = domainParts[domainParts.length-2];
+ for(var j = 0; j < ukTopDomains.length; j++) {
+ if(ukTopDomains[j] === tld2) {
+ hasTopDomain = true;
+ break;
+ }
+ }
+
+ if(hasTopDomain)
+ break;
+
+ } else {
+ hasTopDomain = true;
+ break;
+ }
+ }
+ }
+
+ if (!hasTopDomain) {
+ return false;
+ } else if (dot < 2 || dot > 57) {
+ return $.inArray(val, ['i.net', 'q.com', 'q.net', 'x.com',
'x.org', 'z.com', 'w.org']) > -1;
+ } else {
+ var firstChar = domain.substring(0, 1),
+ lastChar = domain.substring(domain.length - 1,
domain.length);
+
+ if (firstChar === '-' || firstChar === '.' || lastChar === '-'
|| lastChar === '.') {
+ return false;
+ }
+ if (domain.split('..').length > 1) {
+ return false;
+ }
+ if (domain.replace(/[-\da-z\.]/g, '') !== '') {
+ return false;
+ }
+ }
+
+ if(typeof $input !== 'undefined') {
+ $input.val(val);
+ }
+
+ return true;
+ },
+ errorMessage : '',
+ errorMessageKey: 'badDomain'
+ });
+
+ /*
+ * Validate required
+ */
+ $.formUtils.addValidator({
+ name : 'required',
+ validatorFunction : function(val, $el, config, language, $form) {
+ switch ( $el.attr('type') ) {
+ case 'checkbox':
+ return $el.is(':checked');
+ case 'radio':
+ return
$form.find('input[name="'+$el.attr('name')+'"]').filter(':checked').length > 0;
+ default:
+ return $.trim(val) !== '';
+ }
+ },
+ errorMessage : '',
+ errorMessageKey: 'requiredFields'
+ });
+
+ /*
+ * Validate length range
+ */
+ $.formUtils.addValidator({
+ name : 'length',
+ validatorFunction : function(val, $el, conf, lang) {
+ var lengthAllowed = $el.valAttr('length'),
+ type = $el.attr('type');
+
+ if(lengthAllowed == undefined) {
+ var elementType = $el.get(0).nodeName;
+ alert('Please add attribute "data-validation-length" to
'+elementType+' named '+$el.attr('name'));
+ return true;
+ }
+
+ // check if length is above min, below max or within range.
+ var len = type == 'file' && $el.get(0).files !== undefined ?
$el.get(0).files.length : val.length,
+ lengthCheckResults = $.formUtils.numericRangeCheck(len,
lengthAllowed),
+ checkResult;
+
+ switch(lengthCheckResults[0])
+ { // outside of allowed range
+ case "out":
+ this.errorMessage = lang.lengthBadStart + lengthAllowed +
lang.lengthBadEnd;
+ checkResult = false;
+ break;
+ // too short
+ case "min":
+ this.errorMessage = lang.lengthTooShortStart +
lengthCheckResults[1] + lang.lengthBadEnd;
+ checkResult = false;
+ break;
+ // too long
+ case "max":
+ this.errorMessage = lang.lengthTooLongStart +
lengthCheckResults[1] + lang.lengthBadEnd;
+ checkResult = false;
+ break;
+ // ok
+ default:
+ checkResult = true;
+ }
+
+ return checkResult;
+ },
+ errorMessage : '',
+ errorMessageKey: ''
+ });
+
+ /*
+ * Validate url
+ */
+ $.formUtils.addValidator({
+ name : 'url',
+ validatorFunction : function(url) {
+ // written by Scott Gonzalez:
http://projects.scottsplayground.com/iri/
+ // - Victor Jonsson added support for arrays in the url
?arg[]=sdfsdf
+ // - General improvements made by Stéphane Moureau
<https://github.com/TraderStf>
+ var urlFilter =
/^(https?|ftp):\/\/((((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])(\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|\[|\]|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#(((\w|-|\.|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
+ if( urlFilter.test(url) ) {
+ var domain = url.split('://')[1];
+ var domainSlashPos = domain.indexOf('/');
+ if(domainSlashPos > -1)
+ domain = domain.substr(0, domainSlashPos);
+
+ return
$.formUtils.validators.validate_domain.validatorFunction(domain); // todo: add
support for IP-addresses
+ }
+ return false;
+ },
+ errorMessage : '',
+ errorMessageKey: 'badUrl'
+ });
+
+ /*
+ * Validate number (floating or integer)
+ */
+ $.formUtils.addValidator({
+ name : 'number',
+ validatorFunction : function(val, $el, conf) {
+ if(val !== '') {
+ var allowing = $el.valAttr('allowing') || '',
+ decimalSeparator = $el.valAttr('decimal-separator') ||
conf.decimalSeparator,
+ allowsRange = false,
+ begin, end,
+ steps = $el.valAttr('step') || '',
+ allowsSteps = false;
+
+ if(allowing.indexOf('number') == -1)
+ allowing += ',number';
+
+ if(allowing.indexOf('negative') > -1 && val.indexOf('-') ===
0) {
+ val = val.substr(1);
+ }
+
+ if (allowing.indexOf('range') > -1)
+ {
+ begin =
parseFloat(allowing.substring(allowing.indexOf("[")+1, allowing.indexOf(";")));
+ end =
parseFloat(allowing.substring(allowing.indexOf(";")+1,allowing.indexOf("]")));
+ allowsRange = true;
+ }
+
+ if(steps != "")
+ {
+ allowsSteps = true;
+ }
+
+ if( decimalSeparator == ',' ) {
+ if( val.indexOf('.') > -1 ) {
+ return false;
+ }
+ // Fix for checking range with floats using ,
+ val = val.replace(',', '.');
+ }
+
+ if(allowing.indexOf('number') > -1 && val.replace(/[0-9]/g,
'') === '' && (!allowsRange || (val >= begin && val <= end)) && (!allowsSteps
|| (val%steps == 0)) ) {
+ return true;
+ }
+ if(allowing.indexOf('float') > -1 && val.match(new
RegExp('^([0-9]+)\\.([0-9]+)$')) !== null && (!allowsRange || (val >= begin &&
val <= end)) && (!allowsSteps || (val%steps == 0)) ) {
+ return true;
+ }
+ }
+ return false;
+ },
+ errorMessage : '',
+ errorMessageKey: 'badInt'
+ });
+
+ /*
+ * Validate alpha numeric
+ */
+ $.formUtils.addValidator({
+ name : 'alphanumeric',
+ validatorFunction : function(val, $el, conf, language) {
+ var patternStart = '^([a-zA-Z0-9',
+ patternEnd = ']+)$',
+ additionalChars = $el.attr('data-validation-allowing'),
+ pattern = '';
+
+ if( additionalChars ) {
+ pattern = patternStart + additionalChars + patternEnd;
+ var extra = additionalChars.replace(/\\/g, '');
+ if( extra.indexOf(' ') > -1 ) {
+ extra = extra.replace(' ', '');
+ extra += ' and spaces ';
+ }
+ this.errorMessage = language.badAlphaNumeric +
language.badAlphaNumericExtra + extra;
+ } else {
+ pattern = patternStart + patternEnd;
+ this.errorMessage = language.badAlphaNumeric;
+ }
+
+ return new RegExp(pattern).test(val);
+ },
+ errorMessage : '',
+ errorMessageKey: ''
+ });
+
+ /*
+ * Validate against regexp
+ */
+ $.formUtils.addValidator({
+ name : 'custom',
+ validatorFunction : function(val, $el, conf) {
+ var regexp = new RegExp($el.valAttr('regexp'));
+ return regexp.test(val);
+ },
+ errorMessage : '',
+ errorMessageKey: 'badCustomVal'
+ });
+
+ /*
+ * Validate date
+ */
+ $.formUtils.addValidator({
+ name : 'date',
+ validatorFunction : function(date, $el, conf) {
+ var dateFormat = 'yyyy-mm-dd';
+ if($el.valAttr('format')) {
+ dateFormat = $el.valAttr('format');
+ }
+ else if( conf.dateFormat ) {
+ dateFormat = conf.dateFormat;
+ }
+
+ return $.formUtils.parseDate(date, dateFormat) !== false;
+ },
+ errorMessage : '',
+ errorMessageKey: 'badDate'
+ });
+
+
+ /*
+ * Validate group of checkboxes, validate qty required is checked
+ * written by Steve Wasiura : http://stevewasiura.waztech.com
+ * element attrs
+ * data-validation="checkbox_group"
+ * data-validation-qty="1-2" // min 1 max 2
+ * data-validation-error-msg="chose min 1, max of 2 checkboxes"
+ */
+ $.formUtils.addValidator({
+ name : 'checkbox_group',
+ validatorFunction : function(val, $el, conf, lang, $form)
+ { // preset return var
+ var checkResult = true;
+ // get name of element. since it is a checkbox group, all
checkboxes will have same name
+ var elname = $el.attr('name');
+ // get count of checked checkboxes with this name
+ var checkedCount =
$("input[type=checkbox][name^='"+elname+"']:checked", $form).length;
+ // get el attr that specs qty required / allowed
+ var qtyAllowed = $el.valAttr('qty');
+ if (qtyAllowed == undefined) {
+ var elementType = $el.get(0).nodeName;
+ alert('Attribute "data-validation-qty" is missing from
'+elementType+' named '+$el.attr('name'));
+ }
+ // call Utility function to check if count is above min, below
max, within range etc.
+ var qtyCheckResults = $.formUtils.numericRangeCheck(checkedCount,
qtyAllowed) ;
+ // results will be array, [0]=result str, [1]=qty int
+ switch(qtyCheckResults[0] ) {
+ // outside allowed range
+ case "out":
+ this.errorMessage = lang.groupCheckedRangeStart +
qtyAllowed + lang.groupCheckedEnd;
+ checkResult = false;
+ break;
+ // below min qty
+ case "min":
+ this.errorMessage = lang.groupCheckedTooFewStart +
qtyCheckResults[1] + lang.groupCheckedEnd;
+ checkResult = false;
+ break;
+ // above max qty
+ case "max":
+ this.errorMessage = lang.groupCheckedTooManyStart +
qtyCheckResults[1] + lang.groupCheckedEnd;
+ checkResult = false;
+ break;
+ // ok
+ default:
+ checkResult = true;
+ }
+
+ return checkResult;
+
+ }
+ // errorMessage : '', // set above in switch statement
+ // errorMessageKey: '' // not used
+ });
+
+})(jQuery);
Added:
branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.min.js
===================================================================
---
branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.min.js
(rev 0)
+++
branches/dev-syncromind/phpgwapi/js/form-validator/jquery.form-validator.min.js
2014-10-09 19:00:00 UTC (rev 12129)
@@ -0,0 +1,11 @@
+/**
+* jQuery Form Validator
+* ------------------------------------------
+* Created by Victor Jonsson <http://www.victorjonsson.se>
+*
+* @website http://formvalidator.net/
+* @license Dual licensed under the MIT or GPL Version 2 licenses
+* @version 2.2.beta.13
+*/
@@ Diff output truncated at 153600 characters. @@
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Fmsystem-commits] [12129] Add form-validator,
Sigurd Nes <=