Comparing version 0.2.2 to 0.2.3
@@ -34,2 +34,8 @@ /*jslint node: true */ | ||
}), | ||
phone_1: fields.string({ | ||
validators: [validators.requiresFieldIfEmpty('phone_2')] | ||
}), | ||
phone_2: fields.string({ | ||
validators: [validators.requiresFieldIfEmpty('phone_1')] | ||
}), | ||
options: fields.string({ | ||
@@ -36,0 +42,0 @@ choices: { |
@@ -36,3 +36,6 @@ /*jslint node: true */ | ||
b.validate = function (form, callback) { | ||
if (raw_data === '' || raw_data === null || typeof raw_data === 'undefined') { | ||
var forceValidation = (b.validators || []).some(function (validator) { | ||
return validator.forceValidation; | ||
}); | ||
if (!forceValidation && (raw_data === '' || raw_data === null || typeof raw_data === 'undefined')) { | ||
// don't validate empty fields, but check if required | ||
@@ -60,6 +63,6 @@ if (b.required) { b.error = 'This field is required.'; } | ||
var classes = typeof this.cssClasses !== 'undefined' ? coerceArray(this.cssClasses.error) : []; | ||
return this.error ? '<p class="' + htmlEscape(['error_msg'].concat(classes).join('')) + '">' + this.error + '</p>' : ''; | ||
return this.error ? '<p class="' + htmlEscape(['error_msg'].concat(classes).join(' ')) + '">' + this.error + '</p>' : ''; | ||
}; | ||
f.labelText = function (name) { | ||
return this.label || name[0].toUpperCase() + name.substr(1).replace(underscoreRegExp, ' '); | ||
return this.label || (name ? name[0].toUpperCase() + name.substr(1).replace(underscoreRegExp, ' ') : ''); | ||
}; | ||
@@ -116,4 +119,5 @@ f.labelHTML = function (name, id) { | ||
exports.email = function (opt) { | ||
if (!opt) { opt = {}; } | ||
var f = exports.string(opt); | ||
var opts = opt ? copy(opt) : {}; | ||
if (!opts.widget) { opts.widget = forms.widgets.email(opts.attrs || {}); } | ||
var f = exports.string(opts); | ||
if (f.validators) { | ||
@@ -127,2 +131,8 @@ f.validators.unshift(forms.validators.email()); | ||
exports.tel = function (opt) { | ||
var opts = opt ? copy(opt) : {}; | ||
if (!opts.widget) { opts.widget = forms.widgets.tel(opts.attrs || {}); } | ||
return exports.string(opts); | ||
}; | ||
exports.password = function (opt) { | ||
@@ -129,0 +139,0 @@ if (!opt) { opt = {}; } |
/* | ||
from hogan https://github.com/twitter/hogan.js/blob/master/lib/template.js#L317-L327 | ||
*/ | ||
'use strict'; | ||
module.exports = (function () { | ||
'use strict'; | ||
var rAmp = /&/g, | ||
rLt = /</g, | ||
rGt = />/g, | ||
rApos = /\'/g, | ||
rQuot = /\"/g, | ||
hChars = /[&<>\"\']/; | ||
var rAmp = /&/g, | ||
rLt = /</g, | ||
rGt = />/g, | ||
rApos = /\'/g, | ||
rQuot = /\"/g, | ||
hChars = /[&<>\"\']/; | ||
var coerceToString = function (val) { | ||
return String(val || ''); | ||
}; | ||
var coerceToString = function (val) { | ||
return String(val || ''); | ||
}; | ||
var htmlEscape = function (str) { | ||
str = coerceToString(str); | ||
return hChars.test(str) ? | ||
str.replace(rAmp, '&') | ||
.replace(rLt, '<') | ||
.replace(rGt, '>') | ||
.replace(rApos, ''') | ||
.replace(rQuot, '"') : | ||
str; | ||
}; | ||
var htmlEscape = function (str) { | ||
str = coerceToString(str); | ||
return hChars.test(str) ? | ||
str.replace(rAmp, '&') | ||
.replace(rLt, '<') | ||
.replace(rGt, '>') | ||
.replace(rApos, ''') | ||
.replace(rQuot, '"') : | ||
str; | ||
}; | ||
module.exports = htmlEscape; | ||
return htmlEscape; | ||
}()); | ||
/*jslint node: true */ | ||
'use strict'; | ||
exports.matchField = function (match_field) { | ||
var util = require('util'); | ||
// From https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L1238-L1257 | ||
var trim = (function () { | ||
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF", | ||
wsChars = '[' + ws + ']', | ||
trimBeginRegexp = new RegExp("^" + wsChars + wsChars + "*"), | ||
trimEndRegexp = new RegExp(wsChars + wsChars + "*$"), | ||
useES5 = function (str) { return String(str || '').trim(); }; | ||
return String.prototype.trim && !ws.trim() ? useES5 : function (str) { | ||
return String(str || '').replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); | ||
}; | ||
}()); | ||
exports.matchField = function (match_field, message) { | ||
if (!message) { message = 'Does not match %s.'; } | ||
return function (form, field, callback) { | ||
if (form.fields[match_field].data !== field.data) { | ||
callback('Does not match ' + match_field + '.'); | ||
callback(util.format(message, match_field)); | ||
} else { | ||
@@ -14,3 +29,19 @@ callback(); | ||
exports.min = function (val) { | ||
exports.requiresFieldIfEmpty = function (alternate_field, message) { | ||
if (!message) { message = 'One of %s or %s is required.'; } | ||
var validator = function (form, field, callback) { | ||
var alternateBlank = trim(form.fields[alternate_field].data).length === 0, | ||
fieldBlank = trim(field.data).length === 0; | ||
if (alternateBlank && fieldBlank) { | ||
callback(util.format(message, field.name, alternate_field)); | ||
} else { | ||
callback(); | ||
} | ||
}; | ||
validator.forceValidation = true; | ||
return validator; | ||
}; | ||
exports.min = function (val, message) { | ||
if (!message) { message = 'Please enter a value greater than or equal to %s.'; } | ||
return function (form, field, callback) { | ||
@@ -20,3 +51,3 @@ if (field.data >= val) { | ||
} else { | ||
callback('Please enter a value greater than or equal to ' + val + '.'); | ||
callback(util.format(message, val)); | ||
} | ||
@@ -26,3 +57,4 @@ }; | ||
exports.max = function (val) { | ||
exports.max = function (val, message) { | ||
if (!message) { message = 'Please enter a value less than or equal to %s.'; } | ||
return function (form, field, callback) { | ||
@@ -32,3 +64,3 @@ if (field.data <= val) { | ||
} else { | ||
callback('Please enter a value less than or equal to ' + val + '.'); | ||
callback(util.format(message, val)); | ||
} | ||
@@ -38,3 +70,4 @@ }; | ||
exports.range = function (min, max) { | ||
exports.range = function (min, max, message) { | ||
if (!message) { message = 'Please enter a value between %s and %s.'; } | ||
return function (form, field, callback) { | ||
@@ -44,3 +77,3 @@ if (field.data >= min && field.data <= max) { | ||
} else { | ||
callback('Please enter a value between ' + min + ' and ' + max + '.'); | ||
callback(util.format(message, min, max)); | ||
} | ||
@@ -50,3 +83,4 @@ }; | ||
exports.minlength = function (val) { | ||
exports.minlength = function (val, message) { | ||
if (!message) { message = 'Please enter at least %s characters.'; } | ||
return function (form, field, callback) { | ||
@@ -56,3 +90,3 @@ if (field.data.length >= val) { | ||
} else { | ||
callback('Please enter at least ' + val + ' characters.'); | ||
callback(util.format(message, val)); | ||
} | ||
@@ -62,3 +96,4 @@ }; | ||
exports.maxlength = function (val) { | ||
exports.maxlength = function (val, message) { | ||
if (!message) { message = 'Please enter no more than %s characters.'; } | ||
return function (form, field, callback) { | ||
@@ -68,3 +103,3 @@ if (field.data.length <= val) { | ||
} else { | ||
callback('Please enter no more than ' + val + ' characters.'); | ||
callback(util.format(message, val)); | ||
} | ||
@@ -74,3 +109,4 @@ }; | ||
exports.rangelength = function (min, max) { | ||
exports.rangelength = function (min, max, message) { | ||
if (!message) { message = 'Please enter a value between %s and %s characters long.'; } | ||
return function (form, field, callback) { | ||
@@ -80,3 +116,3 @@ if (field.data.length >= min && field.data.length <= max) { | ||
} else { | ||
callback('Please enter a value between ' + min + ' and ' + max + ' characters long.'); | ||
callback(util.format(message, min, max)); | ||
} | ||
@@ -87,2 +123,3 @@ }; | ||
exports.regexp = function (re, message) { | ||
if (!message) { message = 'Invalid format.'; } | ||
re = (typeof re === 'string') ? new RegExp(re) : re; | ||
@@ -93,3 +130,3 @@ return function (form, field, callback) { | ||
} else { | ||
callback(message || 'Invalid format.'); | ||
callback(message); | ||
} | ||
@@ -99,3 +136,4 @@ }; | ||
exports.color = function () { | ||
exports.color = function (message) { | ||
if (!message) { message = 'Inputs of type "color" require hex notation, e.g. #FFF or #ABC123.'; } | ||
var re = /^#([0-9A-F]{8}|[0-9A-F]{6}|[0-9A-F]{3})$/i; | ||
@@ -106,3 +144,3 @@ return function (form, field, callback) { | ||
} else { | ||
callback('Inputs of type "color" require hex notation, e.g. #FFF or #ABC123.'); | ||
callback(message); | ||
} | ||
@@ -113,9 +151,11 @@ }; | ||
exports.email = function () { | ||
exports.email = function (message) { | ||
if (!message) { message = 'Please enter a valid email address.'; } | ||
// regular expression by Scott Gonzalez: | ||
// http://projects.scottsplayground.com/email_address_validation/ | ||
return exports.regexp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\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])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, 'Please enter a valid email address.'); | ||
return exports.regexp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\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])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, message); | ||
}; | ||
exports.url = function (include_localhost) { | ||
exports.url = function (include_localhost, message) { | ||
if (!message) { message = 'Please enter a valid URL.'; } | ||
// regular expression by Scott Gonzalez: | ||
@@ -125,6 +165,7 @@ // http://projects.scottsplayground.com/iri/ | ||
with_localhost_regex = /^(https?|ftp):\/\/(localhost|((([a-z]|\d|-|\.|_|~|[\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])([a-z]|\d|-|\.|_|~|[\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])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i; | ||
return exports.regexp(include_localhost ? with_localhost_regex : external_regex, 'Please enter a valid URL.'); | ||
return exports.regexp(include_localhost ? with_localhost_regex : external_regex, message); | ||
}; | ||
exports.date = function () { | ||
exports.date = function (message) { | ||
if (!message) { message = 'Inputs of type "date" must be valid dates in the format "yyyy-mm-dd"'; } | ||
var numberRegex = /^[0-9]+$/, | ||
@@ -139,3 +180,3 @@ invalidDate = new Date('z'); | ||
} else { | ||
callback('Inputs of type "date" must be valid dates in the format "yyyy-mm-dd"'); | ||
callback(message); | ||
} | ||
@@ -142,0 +183,0 @@ }; |
@@ -33,6 +33,5 @@ /*jslint node: true */ | ||
tagName = htmlEscape(tagName); | ||
var attrsHTML = !Array.isArray(attrsMap) ? attrs(attrsMap) : | ||
attrsMap.reduce(function (html, attrsMap) { | ||
return html + attrs(attrsMap); | ||
}, ''); | ||
var attrsHTML = !Array.isArray(attrsMap) ? attrs(attrsMap) : attrsMap.reduce(function (html, attrsMap) { | ||
return html + attrs(attrsMap); | ||
}, ''); | ||
return '<' + tagName + attrsHTML + '>' + content + '</' + tagName + '>'; | ||
@@ -43,6 +42,5 @@ }; | ||
tagName = htmlEscape(tagName); | ||
var attrsHTML = !Array.isArray(attrsMap) ? attrs(attrsMap) : | ||
attrsMap.reduce(function (html, attrsMap) { | ||
return html + attrs(attrsMap); | ||
}, ''); | ||
var attrsHTML = !Array.isArray(attrsMap) ? attrs(attrsMap) : attrsMap.reduce(function (html, attrsMap) { | ||
return html + attrs(attrsMap); | ||
}, ''); | ||
return '<' + tagName + attrsHTML + ' />'; | ||
@@ -56,17 +54,20 @@ }; | ||
legalAttrs = ['autocomplete', 'autocorrect', 'autofocus', 'autosuggest', 'checked', 'dirname', 'disabled', 'list', 'max', 'maxlength', 'min', 'multiple', 'novalidate', 'pattern', 'placeholder', 'readonly', 'required', 'size', 'step'], | ||
ignoreAttrs = ['id', 'name', 'class', 'classes', 'type', 'value']; | ||
ignoreAttrs = ['id', 'name', 'class', 'classes', 'type', 'value'], | ||
getUserAttrs = function (opt) { | ||
return Object.keys(opt).reduce(function (attrs, k) { | ||
if ((ignoreAttrs.indexOf(k) === -1 && legalAttrs.indexOf(k) > -1) || dataRegExp.test(k) || ariaRegExp.test(k)) { | ||
attrs[k] = opt[k]; | ||
} | ||
return attrs; | ||
}, {}); | ||
}; | ||
return function (opt) { | ||
if (!opt) { opt = {}; } | ||
var userAttrs = getUserAttrs(opt); | ||
var w = { | ||
classes: opt.classes, | ||
type: type | ||
}; | ||
var userAttrs = Object.keys(opt).reduce(function (attrs, k) { | ||
if ((ignoreAttrs.indexOf(k) === -1 && legalAttrs.indexOf(k) > -1) || dataRegExp.test(k) || ariaRegExp.test(k)) { | ||
attrs[k] = opt[k]; | ||
type: type, | ||
formatValue: function (value) { | ||
return value || null; | ||
} | ||
return attrs; | ||
}, {}); | ||
w.formatValue = function (value) { | ||
return value || null; | ||
}; | ||
@@ -94,6 +95,15 @@ w.toHTML = function (name, f) { | ||
exports.text = input('text'); | ||
exports.password = input('password'); | ||
exports.email = input('email'); | ||
exports.hidden = input('hidden'); | ||
exports.color = input('color'); | ||
exports.tel = input('tel'); | ||
var passwordWidget = input('password'); | ||
var passwordFormatValue = function (value) { return null; }; | ||
exports.password = function (opt) { | ||
var w = passwordWidget(opt); | ||
w.formatValue = passwordFormatValue; | ||
return w; | ||
}; | ||
var dateWidget = input('date'); | ||
@@ -190,4 +200,4 @@ exports.date = function (opt) { | ||
// input element | ||
var id = f.id ? f.id + '_' + k : 'id_' + name + '_' + k; | ||
var checked = Array.isArray(f.value) ? f.value.some(function (v) { return v === k; }) : f.value === k; | ||
var id = f.id ? f.id + '_' + k : 'id_' + name + '_' + k, | ||
checked = Array.isArray(f.value) ? f.value.some(function (v) { return v === k; }) : f.value === k; | ||
@@ -237,4 +247,4 @@ html += singleTag('input', { | ||
// input element | ||
var id = f.id ? f.id + '_' + k : 'id_' + name + '_' + k; | ||
var checked = Array.isArray(f.value) ? f.value.some(function (v) { return v === k; }) : f.value === k; | ||
var id = f.id ? f.id + '_' + k : 'id_' + name + '_' + k, | ||
checked = Array.isArray(f.value) ? f.value.some(function (v) { return v === k; }) : f.value === k; | ||
@@ -241,0 +251,0 @@ html += singleTag('input', { |
@@ -6,3 +6,3 @@ { | ||
"author": "Caolan McMahon", | ||
"version": "0.2.2", | ||
"version": "0.2.3", | ||
"repository": { | ||
@@ -16,6 +16,7 @@ "type": "git", | ||
"scripts": { | ||
"test": "node test.js" | ||
"test": "node test.js", | ||
"test-browser": "./node_modules/.bin/browserify test-browser.js | ./node_modules/.bin/testling" | ||
}, | ||
"dependencies": { | ||
"async": "~0.2.6" | ||
"async": "~0.2.9" | ||
}, | ||
@@ -29,22 +30,27 @@ "licenses": [ | ||
"testling": { | ||
"files": "index.js", | ||
"scripts": "node_modules/nodeunit-browser-tap/lib/nodeunit.js", | ||
"files": "test-browser.js", | ||
"browsers": [ | ||
"iexplore/6.0..latest", | ||
"firefox/3.0", | ||
"firefox/15.0..latest", | ||
"iexplore/6..latest", | ||
"firefox/3..10", | ||
"firefox/15..latest", | ||
"firefox/nightly", | ||
"chrome/4.0", | ||
"chrome/23.0..latest", | ||
"chrome/4..10", | ||
"chrome/23..latest", | ||
"chrome/canary", | ||
"opera/10.0..latest", | ||
"opera/10..latest", | ||
"opera/next", | ||
"safari/5.0.5..latest", | ||
"ipad/6.0..latest", | ||
"iphone/6.0..latest" | ||
"iphone/6.0..latest", | ||
"android-browser/4.2" | ||
] | ||
}, | ||
"devDependencies": { | ||
"nodeunit": "~0.8.0" | ||
"nodeunit": "~0.8.1", | ||
"testling": "~1.2.2", | ||
"browserify": "~2.25.0", | ||
"nodeunit-browser-tap": "~0.0.3" | ||
} | ||
} | ||
@@ -0,1 +1,3 @@ | ||
[![Build Status][1]][2] [![dependency status][3]][4] | ||
# Forms | ||
@@ -99,2 +101,35 @@ | ||
### Bootstrap compatible output | ||
For integrating with Twitter bootstrap 3 (horizontal form), this is what you need to do: | ||
var my_form = forms.create({ | ||
title: fields.string({ | ||
required: true, | ||
widget: widgets.text({ classes: ['input-with-feedback'] }), | ||
errorAfterField: true, | ||
cssClasses: { | ||
label: ['control-label col col-lg-3'] | ||
} | ||
}), | ||
description: fields.string({ | ||
errorAfterField: true, | ||
widget: widgets.text({ classes: ['input-with-feedback'] }), | ||
cssClasses: { | ||
label: ['control-label col col-lg-3'] | ||
} | ||
}) | ||
}); | ||
var bootstrap_field = function (name, object) { | ||
var label = object.labelHTML(name); | ||
var error = object.error ? '<p class="form-error-tooltip">' + object.error + '</p>' : ''; | ||
var widget = '<div class="controls col col-lg-9">' + object.widget.toHTML(name, object) + error + '</div>'; | ||
return '<div class="field row control-group ' + (error !== '' ? 'has-error' : '') + '">' + label + widget + '</div>'; | ||
} | ||
And while rendering it: | ||
form.toHTML(function (name, object) { return bootstrap_field(name, object); }); | ||
## Available types | ||
@@ -114,2 +149,3 @@ | ||
* tel | ||
* url | ||
@@ -121,5 +157,7 @@ * date | ||
* text | ||
* password | ||
* hidden | ||
* color | ||
* tel | ||
* date | ||
@@ -137,2 +175,3 @@ * checkbox | ||
* matchField | ||
* requiresFieldIfEmpty | ||
* min | ||
@@ -306,1 +345,6 @@ * max | ||
[1]: https://travis-ci.org/caolan/forms.png | ||
[2]: https://travis-ci.org/caolan/forms | ||
[3]: https://david-dm.org/caolan/forms.png | ||
[4]: https://david-dm.org/caolan/forms | ||
/*jslint node: true */ | ||
'use strict'; | ||
var forms = require('../lib/forms'), | ||
fields = forms.fields; | ||
fields = forms.fields, | ||
stringField = fields.string(), | ||
stringHTML = stringField.toHTML().toString(), | ||
fn1 = function () { return 'one'; }, | ||
fn2 = function () { return 'two'; }; | ||
var testField = function (field) { | ||
exports[field + ' options'] = function (test) { | ||
var fn1 = function () { return 'one'; }; | ||
@@ -164,7 +166,7 @@ var f = fields[field]({ | ||
exports['string parse'] = function (test) { | ||
test.equals(fields.string().parse(), ''); | ||
test.equals(fields.string().parse(null), ''); | ||
test.equals(fields.string().parse(0), '0'); | ||
test.equals(fields.string().parse(''), ''); | ||
test.equals(fields.string().parse('some string'), 'some string'); | ||
test.equals(stringField.parse(), ''); | ||
test.equals(stringField.parse(null), ''); | ||
test.equals(stringField.parse(0), '0'); | ||
test.equals(stringField.parse(''), ''); | ||
test.equals(stringField.parse('some string'), 'some string'); | ||
test.done(); | ||
@@ -176,3 +178,3 @@ }; | ||
test.equals( | ||
fields.string().toHTML('fieldname'), | ||
stringField.toHTML('fieldname'), | ||
'<div class="field">' + | ||
@@ -212,7 +214,8 @@ '<label for="id_fieldname">Fieldname</label>' + | ||
exports['number parse'] = function (test) { | ||
test.ok(isNaN(fields.number().parse())); | ||
test.ok(isNaN(fields.number().parse(null))); | ||
test.equals(fields.number().parse(0), 0); | ||
test.ok(isNaN(fields.number().parse(''))); | ||
test.equals(fields.number().parse('123'), 123); | ||
var field = fields.number(); | ||
test.ok(isNaN(field.parse())); | ||
test.ok(isNaN(field.parse(null))); | ||
test.equals(field.parse(0), 0); | ||
test.ok(isNaN(field.parse(''))); | ||
test.equals(field.parse('123'), 123); | ||
test.done(); | ||
@@ -235,8 +238,9 @@ }; | ||
exports['boolean parse'] = function (test) { | ||
test.equals(fields.boolean().parse(), false); | ||
test.equals(fields.boolean().parse(null), false); | ||
test.equals(fields.boolean().parse(0), false); | ||
test.equals(fields.boolean().parse(''), false); | ||
test.equals(fields.boolean().parse('on'), true); | ||
test.equals(fields.boolean().parse('true'), true); | ||
var field = fields.boolean(); | ||
test.equals(field.parse(), false); | ||
test.equals(field.parse(null), false); | ||
test.equals(field.parse(0), false); | ||
test.equals(field.parse(''), false); | ||
test.equals(field.parse('on'), true); | ||
test.equals(field.parse('true'), true); | ||
test.done(); | ||
@@ -260,4 +264,4 @@ }; | ||
test.equals( | ||
fields.email().parse.toString(), | ||
fields.string().parse.toString() | ||
fields.email().parse().toString(), | ||
stringField.parse().toString() | ||
); | ||
@@ -269,4 +273,4 @@ test.done(); | ||
test.equals( | ||
fields.email().toHTML.toString(), | ||
fields.string().toHTML.toString() | ||
fields.email().toHTML().toString(), | ||
stringHTML.replace(/type="text"/, 'type="email"') | ||
); | ||
@@ -281,5 +285,3 @@ test.done(); | ||
); | ||
var fn1 = function () { return 'one'; }, | ||
fn2 = function () { return 'two'; }, | ||
f = fields.email({validators: [fn1, fn2]}); | ||
var f = fields.email({validators: [fn1, fn2]}); | ||
test.equals( | ||
@@ -293,2 +295,12 @@ f.validators[0].toString(), | ||
testField('tel'); | ||
exports['tel toHTML'] = function (test) { | ||
test.equals( | ||
fields.tel().toHTML().toString(), | ||
stringHTML.replace(/type="text"/, 'type="tel"') | ||
); | ||
test.done(); | ||
}; | ||
testField('password'); | ||
@@ -298,4 +310,4 @@ | ||
test.equals( | ||
fields.password().parse.toString(), | ||
fields.string().parse.toString() | ||
fields.password().parse().toString(), | ||
stringField.parse().toString() | ||
); | ||
@@ -307,4 +319,4 @@ test.done(); | ||
test.equals( | ||
fields.password().toHTML.toString(), | ||
fields.string().toHTML.toString() | ||
fields.password().toHTML().toString(), | ||
stringHTML.replace(/type="text"/, 'type="password"') | ||
); | ||
@@ -318,4 +330,4 @@ test.done(); | ||
test.equals( | ||
fields.url().parse.toString(), | ||
fields.string().parse.toString() | ||
fields.url().parse().toString(), | ||
stringField.parse().toString() | ||
); | ||
@@ -327,4 +339,4 @@ test.done(); | ||
test.equals( | ||
fields.url().toHTML.toString(), | ||
fields.string().toHTML.toString() | ||
fields.url().toHTML().toString(), | ||
stringHTML | ||
); | ||
@@ -339,5 +351,3 @@ test.done(); | ||
); | ||
var fn1 = function () { return 'one'; }, | ||
fn2 = function () { return 'two'; }, | ||
f = fields.url({validators: [fn1, fn2]}); | ||
var f = fields.url({validators: [fn1, fn2]}); | ||
test.equals( | ||
@@ -355,4 +365,4 @@ f.validators[0].toString(), | ||
test.equals( | ||
fields.date().parse.toString(), | ||
fields.string().parse.toString() | ||
fields.date().parse().toString(), | ||
stringField.parse().toString() | ||
); | ||
@@ -364,4 +374,4 @@ test.done(); | ||
test.equals( | ||
fields.date().toHTML.toString(), | ||
fields.string().toHTML.toString() | ||
fields.date().toHTML().toString(), | ||
stringHTML | ||
); | ||
@@ -376,5 +386,3 @@ test.done(); | ||
); | ||
var fn1 = function () { return 'one'; }, | ||
fn2 = function () { return 'two'; }, | ||
f = fields.date({validators: [fn1, fn2]}); | ||
var f = fields.date({validators: [fn1, fn2]}); | ||
test.equals( | ||
@@ -391,8 +399,9 @@ f.validators[0].toString(), | ||
exports['array parse'] = function (test) { | ||
test.same(fields.array().parse(), []); | ||
test.same(fields.array().parse(null), [null]); | ||
test.same(fields.array().parse(0), [0]); | ||
test.same(fields.array().parse(''), ['']); | ||
test.same(fields.array().parse('abc'), ['abc']); | ||
test.same(fields.array().parse(['one', 'two', 'three']), ['one', 'two', 'three']); | ||
var field = fields.array(); | ||
test.same(field.parse(), []); | ||
test.same(field.parse(null), [null]); | ||
test.same(field.parse(0), [0]); | ||
test.same(field.parse(''), ['']); | ||
test.same(field.parse('abc'), ['abc']); | ||
test.same(field.parse(['one', 'two', 'three']), ['one', 'two', 'three']); | ||
test.done(); | ||
@@ -403,4 +412,4 @@ }; | ||
test.equals( | ||
fields.array().toHTML.toString(), | ||
fields.string().toHTML.toString() | ||
fields.array().toHTML().toString(), | ||
stringHTML | ||
); | ||
@@ -407,0 +416,0 @@ test.done(); |
@@ -212,6 +212,6 @@ /*jslint node: true */ | ||
field_name_error_after: forms.fields.string({ | ||
errorAfterField: true, | ||
validators: [function (form, field, callback) { | ||
callback('validation error after field'); | ||
}] | ||
errorAfterField: true, | ||
validators: [function (form, field, callback) { | ||
callback('validation error after field'); | ||
}] | ||
}) | ||
@@ -218,0 +218,0 @@ }); |
@@ -7,3 +7,3 @@ /*jslint node: true */ | ||
exports.matchField = function (test) { | ||
var v = validators.matchField('field1'), | ||
var v = validators.matchField('field1', 'f2 dnm %s'), | ||
data = { | ||
@@ -16,3 +16,3 @@ fields: { | ||
v(data, data.fields.field2, function (err) { | ||
test.equals(err, 'Does not match field1.'); | ||
test.equals(err, 'f2 dnm field1'); | ||
data.fields.field2.data = 'one'; | ||
@@ -26,5 +26,38 @@ v(data, data.fields.field2, function (err) { | ||
exports.requiresFieldIfEmpty = function (test) { | ||
var v = validators.requiresFieldIfEmpty('alternate_field', 'field 1: %s field2: %s'), | ||
empty_fields = { | ||
field: {name: 'field', data: ' '}, | ||
alternate_field: {name: 'alternate_field', data: ''} | ||
}, | ||
filled_fields = { | ||
field: {name: 'field', data: 'filled'}, | ||
alternate_field: {name: 'alternate_field', data: 'also filled'} | ||
}, | ||
first_filled = { | ||
field: {name: 'field', data: 'filled'}, | ||
alternate_field: {name: 'alternate_field', data: ''} | ||
}, | ||
second_filled = { | ||
field: {name: 'field', data: ''}, | ||
alternate_field: {name: 'alternate_field', data: 'filled'} | ||
}; | ||
v({ fields: empty_fields }, empty_fields.field, function (err) { | ||
test.equals(err, 'field 1: field field2: alternate_field'); | ||
v({ fields: filled_fields }, filled_fields.field, function (err) { | ||
test.equals(err, undefined); | ||
v({ fields: first_filled }, first_filled.field, function (err) { | ||
test.equals(err, undefined); | ||
v({ fields: second_filled }, second_filled.field, function (err) { | ||
test.equals(err, undefined); | ||
test.done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}; | ||
exports.min = function (test) { | ||
validators.min(100)('form', {data: 50}, function (err) { | ||
test.equals(err, 'Please enter a value greater than or equal to 100.'); | ||
validators.min(100, 'Value must be greater than or equal to %s.')('form', {data: 50}, function (err) { | ||
test.equals(err, 'Value must be greater than or equal to 100.'); | ||
validators.min(100)('form', {data: 100}, function (err) { | ||
@@ -38,4 +71,4 @@ test.equals(err, undefined); | ||
exports.max = function (test) { | ||
validators.max(100)('form', {data: 150}, function (err) { | ||
test.equals(err, 'Please enter a value less than or equal to 100.'); | ||
validators.max(100, 'Value must be less than or equal to %s.')('form', {data: 150}, function (err) { | ||
test.equals(err, 'Value must be less than or equal to 100.'); | ||
validators.max(100)('form', {data: 100}, function (err) { | ||
@@ -49,4 +82,4 @@ test.equals(err, undefined); | ||
exports.range = function (test) { | ||
validators.range(10, 20)('form', {data: 50}, function (err) { | ||
test.equals(err, 'Please enter a value between 10 and 20.'); | ||
validators.range(10, 20, 'Value must be between %s and %s.')('form', {data: 50}, function (err) { | ||
test.equals(err, 'Value must be between 10 and 20.'); | ||
validators.range(10, 20)('form', {data: 15}, function (err) { | ||
@@ -74,4 +107,4 @@ test.equals(err, undefined); | ||
exports.email = function (test) { | ||
validators.email()('form', {data: 'asdf'}, function (err) { | ||
test.equals(err, 'Please enter a valid email address.'); | ||
validators.email('Email was invalid.')('form', {data: 'asdf'}, function (err) { | ||
test.equals(err, 'Email was invalid.'); | ||
validators.email()('form', {data: 'asdf@asdf.com'}, function (err) { | ||
@@ -90,4 +123,4 @@ test.equals(err, undefined); | ||
function (callback) { | ||
validators.url()('form', {data: 'asdf.com'}, function (err) { | ||
test.equals(err, 'Please enter a valid URL.'); | ||
validators.url(false, 'URL was invalid.')('form', {data: 'asdf.com'}, function (err) { | ||
test.equals(err, 'URL was invalid.'); | ||
validators.url()('form', {data: 'http://asdf.com'}, function (err) { | ||
@@ -112,7 +145,6 @@ test.equals(err, undefined); | ||
exports.date = function (test) { | ||
var msg = 'Inputs of type "date" must be valid dates in the format "yyyy-mm-dd"'; | ||
async.parallel([ | ||
function (callback) { | ||
validators.date()('form', {data: '02/28/2012'}, function (err) { | ||
test.equals(err, msg); | ||
validators.date('Date input must contain a valid date.')('form', {data: '02/28/2012'}, function (err) { | ||
test.equals(err, 'Date input must contain a valid date.'); | ||
validators.date()('form', {data: '2012-02-28'}, function (err) { | ||
@@ -125,5 +157,5 @@ test.equals(err, undefined); | ||
function (callback) { | ||
validators.date(true)('form', {data: '2012.02.30'}, function (err) { | ||
test.equals(err, msg); | ||
validators.date(true)('form', {data: '2012-02-30'}, function (err) { | ||
validators.date()('form', {data: '2012.02.30'}, function (err) { | ||
test.equals(err, 'Inputs of type "date" must be valid dates in the format "yyyy-mm-dd"'); | ||
validators.date()('form', {data: '2012-02-30'}, function (err) { | ||
test.equals(err, undefined); | ||
@@ -138,4 +170,4 @@ callback(); | ||
exports.minlength = function (test) { | ||
validators.minlength(5)('form', {data: '1234'}, function (err) { | ||
test.equals(err, 'Please enter at least 5 characters.'); | ||
validators.minlength(5, 'Enter at least %s characters.')('form', {data: '1234'}, function (err) { | ||
test.equals(err, 'Enter at least 5 characters.'); | ||
validators.minlength(5)('form', {data: '12345'}, function (err) { | ||
@@ -161,4 +193,4 @@ test.equals(err, undefined); | ||
function (callback) { | ||
validators.rangelength(2, 4)('form', {data: '12345'}, function (err) { | ||
test.equals(err, 'Please enter a value between 2 and 4 characters long.'); | ||
validators.rangelength(2, 4, 'Enter between %s and %s characters.')('form', {data: '12345'}, function (err) { | ||
test.equals(err, 'Enter between 2 and 4 characters.'); | ||
callback(); | ||
@@ -202,4 +234,4 @@ }); | ||
return function (callback) { | ||
validators.color()('form', {data: data}, function (err) { | ||
test.equals(err, 'Inputs of type "color" require hex notation, e.g. #FFF or #ABC123.'); | ||
validators.color('Color inputs require hex notation.')('form', {data: data}, function (err) { | ||
test.equals(err, 'Color inputs require hex notation.'); | ||
callback(); | ||
@@ -206,0 +238,0 @@ }); |
@@ -16,8 +16,14 @@ /*jslint node: true */ | ||
); | ||
test.equals( | ||
forms.widgets[type]().toHTML('field1', {value: 'some value'}), | ||
'<input type="' + type + '" name="field1" id="id_field1" value="some value" />' | ||
); | ||
var expectedHTML = '<input type="' + type + '" name="field1" id="id_field1" value="some value" />'; | ||
if (type === 'password') { | ||
expectedHTML = '<input type="' + type + '" name="field1" id="id_field1" />'; | ||
} | ||
test.equals(forms.widgets[type]().toHTML('field1', {value: 'some value'}), expectedHTML); | ||
test.equals(forms.widgets[type]().type, type); | ||
test.equals(forms.widgets[type]().formatValue('hello'), 'hello'); | ||
var expectedValues = { password: null }; | ||
var expectedValue = typeof expectedValues[type] !== 'undefined' ? expectedValues[type] : 'hello'; | ||
test.equals(forms.widgets[type]().formatValue('hello'), expectedValue); | ||
test.strictEqual(forms.widgets[type]().formatValue(false), null); | ||
@@ -29,5 +35,7 @@ test.done(); | ||
exports.text = test_input('text'); | ||
exports.email = test_input('email'); | ||
exports.password = test_input('password'); | ||
exports.hidden = test_input('hidden'); | ||
exports.color = test_input('color'); | ||
exports.tel = test_input('tel'); | ||
@@ -34,0 +42,0 @@ exports.date = function (test) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
114850
27
2822
346
4
Updatedasync@~0.2.9