Created
June 6, 2018 18:53
-
-
Save jzaefferer/07a5ea0675d2f92ccc87ce69a354d8fd to your computer and use it in GitHub Desktop.
React with jQuery Validation Plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable prefer-arrow-callback */ | |
import $ from 'jquery' | |
import 'jquery-validation' | |
import PropTypes from 'prop-types' | |
import React from 'react' | |
import env from '../env' | |
import validateImage from '../lib/image' | |
const sharedHostDomain = env.npm_package_config_shared_host_domain | |
export const identifierRegex = /^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$/ | |
export const containerPathRegex = /^(?:\/\.?[a-zA-Z0-9_\\-]*)+$/ | |
export const domainRegex = /^(?:\s?(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))+$/ | |
export const basicAuthRegex = /.+:.+:\$1\$[A-Za-z0-9./]{1,16}\$[A-Za-z0-9./]{21,31}$|\$2\$[A-Za-z0-9]{1,16}\$[A-Za-z0-9./]{40,55}$/ | |
// app-settings.jsx | |
$.validator.addMethod('image', validateImage, 'Please enter a valid Docker image, like \'wordpress\' or \'sloppy/apache-php\'') | |
$.validator.addMethod('tag', function (value, element) { | |
return this.optional(element) || /^[\w][\w.-]{0,127}$/.test(value) | |
}, "Please enter a valid Docker image tag, like 'latest' or '1.10.0'") | |
$.validator.addMethod('domain', function (value, element) { | |
return this.optional(element) || domainRegex.test(value) | |
}, `Please enter a valid hostname, like 'git${sharedHostDomain}' or 'coffee-to-go.com'.`) | |
$.validator.addMethod('reserved_domain', function (value, element) { | |
return this.optional(element) || !/^.+\.(?:sloppy\.io)$/.test(value) | |
}, `*.sloppy.io subdomains aren't available, did you mean *${sharedHostDomain}?`) | |
$.validator.addMethod('container_path', function (value, element) { | |
return this.optional(element) || containerPathRegex.test(value) | |
}, "Try something like '/var/www' or '/data/db'") | |
$.validator.addMethod('env_key', function (value, element) { | |
return this.optional(element) || /^(?!(SLOPPY|MARATHON|MESOS|WEAVE_CIDR))([a-zA-Z_]?[a-zA-Z0-9_.]{0,41})$/.test(value) | |
}, "Try something like 'DATABASE_URI' or 'MYSQL_USER'") | |
// new-project.jsx | |
$.validator.addMethod('identifier', function (value) { | |
return identifierRegex.test(value) | |
}, "Please stick to 'a-z', '0-9', and '-' (no '-' at start or end)") | |
$.validator.addMethod('unique', function (value, element, existing) { | |
return existing.split(',').indexOf(value) < 0 | |
}, 'Please use a unique name') | |
$.validator.addMethod('basic_auth', function (value, element) { | |
return this.optional(element) || basicAuthRegex.test(value) | |
}, 'Check the Basic Auth format, must be in the form \'Authentication:[username]:[password hash]\'') | |
// https://jqueryvalidation.org/creditcard-method/ | |
// based on https://en.wikipedia.org/wiki/Luhn_algorithm | |
$.validator.addMethod('creditcard', function (value) { | |
// Accept only spaces, digits and dashes | |
if (/[^0-9 -]+/.test(value)) { | |
return false | |
} | |
let nCheck = 0 | |
let nDigit = 0 | |
let bEven = false | |
let n | |
let cDigit | |
value = value.replace(/\D/g, '') | |
// Basing min and max length on | |
// https://developer.ean.com/general_info/Valid_Credit_Card_Types | |
if (value.length < 13 || value.length > 19) { | |
return false | |
} | |
/* eslint-disable no-plusplus,no-cond-assign */ | |
for (n = value.length - 1; n >= 0; n--) { | |
cDigit = value.charAt(n) | |
nDigit = parseInt(cDigit, 10) | |
if (bEven) { | |
if ((nDigit *= 2) > 9) { | |
nDigit -= 9 | |
} | |
} | |
nCheck += nDigit | |
bEven = !bEven | |
} | |
/* eslint-enable */ | |
return (nCheck % 10) === 0 | |
}, 'Please enter a valid credit card number.') | |
$.validator.addMethod('syslogaddress', function (value, element) { | |
return this.optional(element) || /^udp:\/\/[a-zA-Z0-9][a-zA-Z0-9-.]*(?::\d{2,5})?$/.test(value) | |
}, 'Must use udp protocol with hostname, port is optional') | |
export default class Validator extends React.Component { | |
static propTypes = { | |
children: PropTypes.node, | |
className: PropTypes.string, | |
onChange: PropTypes.func, | |
onSubmit: PropTypes.func, | |
validateOnMount: PropTypes.bool, | |
} | |
static childContextTypes = { | |
processing: PropTypes.bool, | |
} | |
getChildContext() { | |
return { | |
processing: this.state.processing, | |
} | |
} | |
componentWillMount() { | |
this.setState({ | |
processing: false, | |
}) | |
} | |
componentDidMount() { | |
this.validator = $(this.form).validate({ | |
submitHandler: () => { | |
if (this.props.onSubmit) { | |
this.setState({ processing: true }) | |
Promise.resolve() | |
.then(() => this.props.onSubmit()) | |
.then(() => this.setState({ processing: false })) | |
.catch((error) => { | |
this.setState({ processing: false }) | |
throw error | |
}) | |
} | |
return false | |
}, | |
errorElement: 'div', | |
errorClass: 'Input__error', | |
highlight: (element) => { | |
// add data so that React component can keep the extra class intact | |
$(element).parents('.Input, .EditableInput').addClass('has__error').data('has-error', true) | |
}, | |
unhighlight: (element) => { | |
$(element).parents('.Input, .EditableInput').removeClass('has__error').data('has-error', false) | |
}, | |
errorPlacement: (errorElement, element) => { | |
element.parents('.Input, .EditableInput').append(errorElement) | |
}, | |
}) | |
if (this.props.validateOnMount) { | |
this.setIsValid() | |
} | |
} | |
componentDidUpdate() { | |
if (this.props.validateOnMount) { | |
this.setIsValid() | |
} | |
} | |
setIsValid() { | |
const { onChange } = this.props | |
const isValid = $(this.form).valid() | |
if (onChange && isValid !== this.isValid) { | |
this.isValid = isValid | |
onChange(isValid) | |
} | |
} | |
resetForm() { | |
this.validator.resetForm() | |
} | |
render() { | |
const { children, className } = this.props | |
return <form ref={(el) => { this.form = el }} className={className}> | |
{children} | |
</form> | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment