Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

forms

Package Overview
Dependencies
Maintainers
2
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

forms - npm Package Compare versions

Comparing version 0.1.4 to 0.2.0

3

example/complex.js
/*jslint node: true */
'use strict';
var http = require('http'),

@@ -85,1 +85,2 @@ util = require('util'),

util.puts('Server running at http://127.0.0.1:8080/');

@@ -532,2 +532,3 @@ // Copyright (C) 2009 Andy Chu

// commonjs
for (var key in jsontemplate) exports[key] = jsontemplate[key];
for (var key in jsontemplate) exports[key] = jsontemplate[key];
/*jslint node: true */
'use strict';

@@ -72,1 +73,2 @@ /*

}
/*jslint node: true */
'use strict';

@@ -49,1 +50,2 @@ var http = require('http'),

util.puts('Server running at http://127.0.0.1:8080/');
// This file is just added for convenience so this repository can be
// directly checked out into a project's deps folder
module.exports = require('./lib/forms');
/*jslint node: true */
'use strict';
var forms = require('./forms'),
async = require('async'),
copy = function (original) {
return Object.keys(original).reduce(function (copy, key) {
copy[key] = original[key];
return copy;
}, {});
};
htmlEscape = require('./htmlEscape'),
coerceArray = function (arr) {
return Array.isArray(arr) && arr.length > 0 ? arr : [];
},
copy = function (original) {
return Object.keys(original).reduce(function (copy, key) {
copy[key] = original[key];
return copy;
}, {});
},
underscoreRegExp = /_/g;

@@ -52,15 +58,15 @@

f.errorHTML = function () {
return this.error ? '<p class="error_msg">' + this.error + '</p>' : '';
var classes = typeof this.cssClasses !== 'undefined' ? coerceArray(this.cssClasses.error) : [];
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('_', ' ');
return this.label || name[0].toUpperCase() + name.substr(1).replace(underscoreRegExp, ' ');
};
f.labelHTML = function (name, id) {
if (this.widget.type === 'hidden') { return ''; }
var label = '<label for="' + (id || 'id_' + name) + '"';
if (typeof this.cssClasses !== 'undefined' && Array.isArray(this.cssClasses.label) && this.cssClasses.label.length > 0) {
label += ' class="' + this.cssClasses.label.join(' ') + '"';
}
label += '>' + this.labelText(name, id) + '</label>'
return label;
var forID = id || 'id_' + name;
return forms.widgets.label({
classes: typeof this.cssClasses !== 'undefined' ? coerceArray(this.cssClasses.label) : [],
content: this.labelText(name, id)
}).toHTML(forID, f);
};

@@ -71,4 +77,4 @@ f.classes = function () {

if (this.required) { r.push('required'); }
if (typeof this.cssClasses !== 'undefined' && Array.isArray(this.cssClasses.field) && this.cssClasses.field.length > 0) {
r = r.concat(this.cssClasses.field);
if (typeof this.cssClasses !== 'undefined') {
r = r.concat(coerceArray(this.cssClasses.field));
}

@@ -78,3 +84,3 @@ return r;

f.toHTML = function (name, iterator) {
return (iterator || forms.render.div)(name || this.name, this);
return (iterator || forms.render.div)(name || this.name, this, opt);
};

@@ -148,1 +154,13 @@

};
exports.date = function (opt) {
if (!opt) { opt = {}; }
var f = exports.string(opt);
if (f.validators) {
f.validators.unshift(forms.validators.date());
} else {
f.validators = [forms.validators.date()];
}
return f;
};
/*jslint node: true */
'use strict';

@@ -93,1 +94,2 @@ var async = require('async'),

};
/*
from hogan https://github.com/twitter/hogan.js/blob/master/lib/template.js#L317-L327
*/
'use strict';

@@ -5,0 +6,0 @@ var rAmp = /&/g,

/*jslint node: true */
'use strict';
var htmlEscape = require('./htmlEscape');
var wrapWith = function (tag) {
return function (name, field) {
var html = ['<' + tag + ' class="' + field.classes().join(' ') + '">'];
return function (name, field, opt) {
if (!opt) { opt = {}; }
var html = ['<' + tag + ' class="' + htmlEscape(field.classes().join(' ')) + '">'],
errorHTML = field.errorHTML();
if (field.widget.type === 'multipleCheckbox' || field.widget.type === 'multipleRadio') {

@@ -10,8 +14,14 @@ html = html.concat([

'<legend>', field.labelText(name), '</legend>',
field.errorHTML(),
opt.errorAfterField ? '' : errorHTML,
field.widget.toHTML(name, field),
opt.errorAfterField ? errorHTML : '',
'</fieldset>'
]);
} else {
html.push(field.errorHTML() + field.labelHTML(name, field.id) + field.widget.toHTML(name, field));
html = html.concat([
opt.errorAfterField ? '' : errorHTML,
field.labelHTML(name, field.id),
field.widget.toHTML(name, field),
opt.errorAfterField ? errorHTML : '',
]);
}

@@ -25,9 +35,12 @@ return html.join('') + '</' + tag + '>';

exports.table = function (name, field) {
exports.table = function (name, field, opt) {
if (!opt) { opt = {}; }
var errorHTML = field.errorHTML();
return [
'<tr class="', field.classes().join(' '), '">',
'<tr class="', htmlEscape(field.classes().join(' ')), '">',
'<th>', field.labelHTML(name, field.id), '</th>',
'<td>',
field.errorHTML(),
opt.errorAfterField ? '' : errorHTML,
field.widget.toHTML(name, field),
opt.errorAfterField ? errorHTML : '',
'</td>',

@@ -37,1 +50,2 @@ '</tr>'

};
/*jslint node: true */
'use strict';

@@ -110,1 +111,16 @@ exports.matchField = function (match_field) {

exports.date = function () {
var numberRegex = /^[0-9]+$/,
invalidDate = new Date('z');
return function (form, field, callback) {
var parts = field.data ? field.data.split('-') : [],
allNumbers = parts.every(function (part) { return numberRegex.test(part); }),
date = allNumbers && parts.length === 3 ? new Date(parts[0], parts[1] - 1, parts[2]) : invalidDate;
if (!isNaN(date.getTime())) {
callback();
} else {
callback('Inputs of type "date" must be valid dates in the format "yyyy-mm-dd"');
}
};
};
/*jslint node: true */
'use strict';
var htmlEscape = require('./htmlEscape');
// generates a string for common widget attributes
var attrs = function (a, needsID) {
if (!a.id && needsID) {
a.id = 'id_' + a.name;
var attrs = function (a) {
if (typeof a.id === 'boolean') {
a.id = a.id ? 'id_' + a.name : null;
}
if (Array.isArray(a.classes) && a.classes.length > 0) {
a['class'] = a.classes.join(' ');
a.classes = null;
}
a.classes = null;
var pairs = [];

@@ -30,2 +31,20 @@ Object.keys(a).map(function (field) {

var tag = function tag(tagName, attrsMap, content) {
tagName = htmlEscape(tagName);
var attrsHTML = !Array.isArray(attrsMap) ? attrs(attrsMap) :
attrsMap.reduce(function (html, attrsMap) {
return html + attrs(attrsMap);
}, '');
return '<' + tagName + attrsHTML + '>' + content + '</' + tagName + '>';
};
var singleTag = function tag(tagName, attrsMap) {
tagName = htmlEscape(tagName);
var attrsHTML = !Array.isArray(attrsMap) ? attrs(attrsMap) :
attrsMap.reduce(function (html, attrsMap) {
return html + attrs(attrsMap);
}, '');
return '<' + tagName + attrsHTML + ' />';
};
// used to generate different input elements varying only by type attribute

@@ -44,3 +63,3 @@ var input = function (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)) {
if ((ignoreAttrs.indexOf(k) === -1 && legalAttrs.indexOf(k) > -1) || dataRegExp.test(k) || ariaRegExp.test(k)) {
attrs[k] = opt[k];

@@ -50,14 +69,14 @@ }

}, {});
w.formatValue = function (value) {
return value || null;
};
w.toHTML = function (name, f) {
if (!f) { f = {}; }
var html = '<input';
html += attrs({
return singleTag('input', [{
type: type,
name: name,
id: f.id,
id: f.id || true,
classes: w.classes,
value: f.value || null
}, true);
html += attrs(userAttrs);
return html + ' />';
value: w.formatValue(f.value)
}, userAttrs]);
};

@@ -79,2 +98,21 @@ w.getDataRegExp = function () {

var dateWidget = input('date');
exports.date = function (opt) {
var w = dateWidget(opt);
w.formatValue = function (value) {
if (!value) {
return null;
}
var date = value instanceof Date ? value : new Date(value);
if (isNaN(date.getTime())) {
return null;
}
return date.toISOString().slice(0, 10);
};
return w;
};
exports.checkbox = function (opt) {

@@ -88,12 +126,10 @@ if (!opt) { opt = {}; }

if (!f) { f = {}; }
var html = '<input';
html += attrs({
return singleTag('input', {
type: 'checkbox',
name: name,
id: f.id,
id: f.id || true,
classes: w.classes,
checked: !!f.value,
value: 'on'
}, true);
return html + ' />';
});
};

@@ -111,14 +147,13 @@ return w;

if (!f) { f = {}; }
var html = '<select' + attrs({
name: name,
id: f.id,
classes: w.classes
}, true) + '>';
html += Object.keys(f.choices).reduce(function (html, k) {
return html + '<option' + attrs({
var optionsHTML = Object.keys(f.choices).reduce(function (html, k) {
return html + tag('option', {
value: k,
selected: !!(f.value && f.value === k)
}) + '>' + f.choices[k] + '</option>';
}, f.choices[k]);
}, '');
return html + '</select>';
return tag('select', {
name: name,
id: f.id || true,
classes: w.classes
}, optionsHTML);
};

@@ -136,15 +171,9 @@ return w;

if (!f) { f = {}; }
return [
'<textarea',
attrs({
name: name,
id: f.id,
classes: w.classes,
rows: opt.rows || null,
cols: opt.cols || null
}, true),
'>',
f.value || '',
'</textarea>'
].join('');
return tag('textarea', {
name: name,
id: f.id || true,
classes: w.classes,
rows: opt.rows || null,
cols: opt.cols || null
}, f.value || '');
};

@@ -167,4 +196,3 @@ return w;

html += '<input';
html += attrs({
html += singleTag('input', {
type: 'checkbox',

@@ -177,6 +205,5 @@ name: name,

});
html += ' />';
// label element
html += '<label' + attrs({for: id}) + '>' + f.choices[k] + '</label>';
html += tag('label', {for: id}, f.choices[k]);

@@ -189,2 +216,17 @@ return html;

exports.label = function (opt) {
if (!opt) { opt = {}; }
var w = {
classes: opt.classes || []
};
w.toHTML = function (forID, f) {
var labelAttrs = {
for: forID,
classes: w.classes
};
return tag('label', labelAttrs, opt.content);
};
return w;
};
exports.multipleRadio = function (opt) {

@@ -203,4 +245,3 @@ if (!opt) { opt = {}; }

html += '<input';
html += attrs({
html += singleTag('input', {
type: 'radio',

@@ -213,6 +254,4 @@ name: name,

});
html += '>';
// label element
html += '<label' + attrs({for: id}) + '>' + f.choices[k] + '</label>';
html += tag('label', {for: id}, f.choices[k]);

@@ -233,19 +272,15 @@ return html;

if (!f) { f = {}; }
var html = '<select' + attrs({
multiple: true,
name: name,
id: f.id,
classes: w.classes
}, true) + '>';
html += Object.keys(f.choices).reduce(function (html, k) {
var optionsHTML = Object.keys(f.choices).reduce(function (html, k) {
var selected = Array.isArray(f.value) ? f.value.some(function (v) { return v === k; }) : (f.value && f.value === k);
html += '<option';
html += attrs({
return html + tag('option', {
value: k,
selected: !!selected
});
html += '>' + f.choices[k] + '</option>';
return html;
}, f.choices[k]);
}, '');
return html + '</select>';
return tag('select', {
multiple: true,
name: name,
id: f.id || true,
classes: w.classes
}, optionsHTML);
};

@@ -252,0 +287,0 @@ return w;

@@ -6,3 +6,3 @@ {

"author": "Caolan McMahon",
"version": "0.1.4",
"version": "0.2.0",
"repository": {

@@ -19,3 +19,3 @@ "type": "git",

"dependencies": {
"async": "~0.1.22"
"async": "~0.2.6"
},

@@ -29,4 +29,5 @@ "licenses": [

"devDependencies": {
"nodeunit": "~0.7.4"
"nodeunit": "~0.8.0"
}
}

@@ -23,9 +23,9 @@ # Forms

module would integrate well with projects using any of the popular frameworks.
### Contributors
### [Contributors](https://github.com/caolan/forms/contributors)
* [ljharb](https://github.com/ljharb)
* [richardngn](https://github.com/richardngn)
* [caulagi](https://github.com/caulagi)
* [luddep](http://github.com/luddep)
* [jedp](https://github.com/jedp)
* [ljharb](https://github.com/ljharb)
## Example

@@ -115,2 +115,3 @@

* url
* date

@@ -123,2 +124,3 @@ ### Widgets

* color
* date
* checkbox

@@ -130,2 +132,3 @@ * select

* multipleSelect
* label

@@ -145,2 +148,3 @@ ### Validators

* url
* date

@@ -221,2 +225,3 @@ ### Renderers

* cssClasses - A list of CSS classes for label and field wrapper
* errorAfterField - if true, the error message will be displayed after the field, rather than before.

@@ -302,1 +307,2 @@ #### field.parse(rawdata)

containing a HTML representation of the field.

@@ -5,1 +5,2 @@ #!/usr/local/bin/node

reporter.run(['test']);

@@ -338,2 +338,36 @@ /*jslint node: true */

testField('date');
exports['date parse'] = function (test) {
test.equals(
fields.date().parse.toString(),
fields.string().parse.toString()
);
test.done();
};
exports['date toHTML'] = function (test) {
test.equals(
fields.date().toHTML.toString(),
fields.string().toHTML.toString()
);
test.done();
};
exports['date validators'] = function (test) {
test.equals(
fields.date().validators[0].toString(),
forms.validators.date().toString()
);
var fn1 = function () { return 'one'; },
fn2 = function () { return 'two'; },
f = fields.date({validators: [fn1, fn2]});
test.equals(
f.validators[0].toString(),
forms.validators.date().toString()
);
test.same(f.validators.slice(1), [fn1, fn2]);
test.done();
};
testField('array');

@@ -358,1 +392,2 @@

};

@@ -264,2 +264,3 @@ /*jslint node: true */

req.url = '/?field1=test';
req.resume();
f.handle(req, {

@@ -277,2 +278,3 @@ success: function (form) {

req.method = 'POST';
req.resume();
f.handle(req, {

@@ -284,2 +286,3 @@ success: function (form) {

});
req.setEncoding('utf8');
req.emit('data', 'field1=test');

@@ -294,2 +297,3 @@ req.emit('end');

req.method = 'POST';
req.resume();
f.handle(req, {

@@ -366,1 +370,2 @@ success: function (form) {

};

@@ -23,1 +23,2 @@ /*jslint node: true */

};

@@ -54,5 +54,11 @@ /*jslint node: true */

}]
}),
field_name_error_after: forms.fields.string({
errorAfterField: true,
validators: [function (form, field, callback) {
callback('validation error after field');
}]
})
});
f.bind({field_name: 'val'}).validate(function (err, f) {
f.bind({field_name: 'val', field_name_error_after: 'foo'}).validate(function (err, f) {
test.equals(

@@ -63,4 +69,8 @@ f.toHTML(forms.render[tag]),

'<label for="id_field_name">Field name</label>' +
'<input type="text" name="field_name" id="id_field_name" ' +
'value="val" />' +
'<input type="text" name="field_name" id="id_field_name" value="val" />' +
'</' + tag + '>' +
'<' + tag + ' class="field error">' +
'<label for="id_field_name_error_after">Field name error after</label>' +
'<input type="text" name="field_name_error_after" id="id_field_name_error_after" value="foo" />' +
'<p class="error_msg">validation error after field</p>' +
'</' + tag + '>'

@@ -84,4 +94,3 @@ );

'<legend>Fieldname</legend>' +
'<input type="checkbox" name="fieldname" id="id_fieldname_one"' +
' value="one" />' +
'<input type="checkbox" name="fieldname" id="id_fieldname_one" value="one" />' +
'<label for="id_fieldname_one">item one</label>' +

@@ -106,4 +115,3 @@ '</fieldset>' +

'<legend>Fieldname</legend>' +
'<input type="radio" name="fieldname" id="id_fieldname_one"' +
' value="one">' +
'<input type="radio" name="fieldname" id="id_fieldname_one" value="one" />' +
'<label for="id_fieldname_one">item one</label>' +

@@ -191,4 +199,3 @@ '</fieldset>' +

'<td>' +
'<input type="text" name="name" id="id_name"' +
' value="val" />' +
'<input type="text" name="name" id="id_name" value="val" />' +
'</td>' +

@@ -208,5 +215,11 @@ '</tr>'

}]
}),
field_name_error_after: forms.fields.string({
errorAfterField: true,
validators: [function (form, field, callback) {
callback('validation error after field');
}]
})
});
f.bind({field_name: 'val'}).validate(function (err, f) {
f.bind({field_name: 'val', field_name_error_after: 'foo'}).validate(function (err, f) {
test.equals(

@@ -218,5 +231,11 @@ f.toHTML(forms.render.table),

'<p class="error_msg">validation error</p>' +
'<input type="text" name="field_name"' +
' id="id_field_name" value="val" />' +
'<input type="text" name="field_name" id="id_field_name" value="val" />' +
'</td>' +
'</tr>' +
'<tr class="field error">' +
'<th><label for="id_field_name_error_after">Field name error after</label></th>' +
'<td>' +
'<input type="text" name="field_name_error_after" id="id_field_name_error_after" value="foo" />' +
'<p class="error_msg">validation error after field</p>' +
'</td>' +
'</tr>'

@@ -227,1 +246,2 @@ );

};

@@ -104,2 +104,26 @@ /*jslint node: true */

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()('form', {data: '2012-02-28'}, function (err) {
test.equals(err, undefined);
callback();
});
});
},
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) {
test.equals(err, undefined);
callback();
});
});
}
], test.done);
};
exports.minlength = function (test) {

@@ -175,1 +199,2 @@ validators.minlength(5)('form', {data: '1234'}, function (err) {

};

@@ -21,2 +21,4 @@ /*jslint node: true */

test.equals(forms.widgets[type]().type, type);
test.equals(forms.widgets[type]().formatValue('hello'), 'hello');
test.strictEqual(forms.widgets[type]().formatValue(false), null);
test.done();

@@ -31,2 +33,24 @@ };

exports.date = function (test) {
var w = forms.widgets.date();
test.equals(w.formatValue(new Date(Date.UTC(2013, 2, 1))), '2013-03-01');
test.equals(w.formatValue('2013-03-02'), '2013-03-02');
test.strictEqual(w.formatValue('invalid'), null);
test.equals(w.type, 'date');
test.equals(
w.toHTML('field1'),
'<input type="date" name="field1" id="id_field1" />'
);
test.equals(
w.toHTML('field1', {value: '2013-03-03'}),
'<input type="date" name="field1" id="id_field1" value="2013-03-03" />'
);
test.done();
};
exports.checkbox = function (test) {

@@ -57,7 +81,7 @@ test.equals(

forms.widgets.select().toHTML('name', {
choices: {
choices: {
val1: 'text1',
val2: 'text2'
}
}),
}),
'<select name="name" id="id_name">' +

@@ -149,7 +173,7 @@ '<option value="val1">text1</option>' +

w.toHTML('name', field),
'<input type="radio" name="name" id="id_name_one" value="one">' +
'<input type="radio" name="name" id="id_name_one" value="one" />' +
'<label for="id_name_one">Item one</label>' +
'<input type="radio" name="name" id="id_name_two" value="two" checked="checked">' +
'<input type="radio" name="name" id="id_name_two" value="two" checked="checked" />' +
'<label for="id_name_two">Item two</label>' +
'<input type="radio" name="name" id="id_name_three" value="three">' +
'<input type="radio" name="name" id="id_name_three" value="three" />' +
'<label for="id_name_three">Item three</label>'

@@ -163,3 +187,3 @@ );

var w = forms.widgets.multipleRadio(),
field = {
field = {
choices: {one: 'Item one', two: 'Item two', three: 'Item three'},

@@ -170,7 +194,7 @@ value: ['two', 'three']

w.toHTML('name', field),
'<input type="radio" name="name" id="id_name_one" value="one">' +
'<input type="radio" name="name" id="id_name_one" value="one" />' +
'<label for="id_name_one">Item one</label>' +
'<input type="radio" name="name" id="id_name_two" value="two" checked="checked">' +
'<input type="radio" name="name" id="id_name_two" value="two" checked="checked" />' +
'<label for="id_name_two">Item two</label>' +
'<input type="radio" name="name" id="id_name_three" value="three" checked="checked">' +
'<input type="radio" name="name" id="id_name_three" value="three" checked="checked" />' +
'<label for="id_name_three">Item three</label>'

@@ -264,1 +288,20 @@ );

};
exports.label = function (test) {
test.equals(
forms.widgets.label({
classes: ['foo', 'bar', 'quux'],
content: 'Foobar'
}).toHTML('field1'),
'<label for="field1" class="foo bar quux">Foobar</label>'
);
test.equals(
forms.widgets.label({
classes: [],
content: 'Foobar'
}).toHTML('field1'),
'<label for="field1">Foobar</label>'
);
test.done();
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc