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

compose-form-up

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

compose-form-up - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

lib/progressive.js

190

index.js

@@ -1,189 +0,9 @@

// Dependencies
var toolbox = require( 'compose-toolbox' ),
Event = toolbox.event,
matches = toolbox.matches,
getClosest = toolbox.getClosest,
wordCount = toolbox.wordCount,
textSelectors = '[required]';
var validation = require( './lib/validation' )
var progressive = require( './lib/progressive' )
// Does this browser support HTML5 validation?
function supported() {
module.exports = {
return typeof document.createElement( 'input' ).checkValidity === 'function'
validate: validation.validate,
next: progressive.next,
}
// Watch for events ( if validation is suported )
function watch() {
if ( !supported() ) { return false }
Event.bubbleFormEvents()
Event.on( document.body, {
invalid: function( event ) { event.preventDefault() }, // Suppress default message bubbles
submit: submit
})
// Watch input events
Event.on( document, 'blur', '[required]', checkValidation )
Event.on( document, 'keydown', '[required]', Event.debounce( checkValidation, 200 ) )
}
function validateForm( form ) {
// Scoped variables
var invalidInput = form.querySelector( 'input:invalid, textarea:invalid' )
// The form is valid, skip it
if ( !invalidInput ) {
return true
}
else {
// Set validity state on element
checkInput( invalidInput )
// Show validation message
showMessage( invalidInput )
focus( invalidInput )
return false
}
}
// Handler for validation events
var checkValidation = Event.callback.new( function( event ) {
// Remove any pre-existing validation message
hideMessage( event.target )
checkInput( event.target, event.type )
})
function checkInput( input, event ) {
var el = statusEl( input ),
valid = isValid( input ),
neutral = !valid && event == 'keydown';
// Don't trigger invalid style while typing
if ( neutral && input == document.activeElement ) {
el.classList.remove( 'invalid', 'valid' )
} else {
el.classList.toggle( 'invalid', !valid )
el.classList.toggle( 'valid', valid )
}
}
// Is an input valid?
function isValid( input ) {
// If element only contains whitespace, strip value
if ( !input.value.replace( /\s/g, '' ).length )
input.value = ''
// Set a custom validation message for word count
if ( input.dataset.minWords ) checkCount( input, 'min' )
if ( input.dataset.maxWords ) checkCount( input, 'max' )
return input.checkValidity()
}
// Test custom validation for maximum or minimum words present
function checkCount( input, limit ) {
var goal = input.dataset[ limit + 'Words' ],
lessThanGoal = wordCount( input.value ) < goal
var phrasing = ( limit == 'min' ) ? 'at least ' : 'no more than ',
valid = ( limit == 'min' ) ? !lessThanGoal : lessThanGoal,
message = '';
// Set a custom error message
if ( input.value && !valid )
message = 'Please write ' + phrasing + goal + ' words.'
input.setCustomValidity( message )
}
// If input is nested in a label, treat the label as the
// target for assigning status (class names and messages).
function statusEl( input ) {
return getClosest( input, 'label' ) || input
}
// Focus() if invalid element is not hidden
// or Focus its immediate sibling (mostly used for upload buttons)
function focus( el ) {
el = ( el.style.display !== 'none' ) ? el : el.nextSibling
el.focus()
}
// Submission validation handler function
function submit( event ) {
// Skip validation if no invalid inputs found
if ( !validateForm( event.target ) ) {
// Pause keydown/blur triggers for the next second to avoid neutral empty style
checkValidation.stop()
Event.delay( checkValidation.start, 1000 )
// Stop the submission event
event.preventDefault()
}
}
function hideMessage( el ) {
var form = getClosest( el, 'form' ),
msg = form.querySelector( '.validation-message' )
if (msg ) msg.parentNode.removeChild( msg )
}
// Validation message handler function
function showMessage( el ) {
hideMessage( el )
var label = getClosest( el, 'label' ),
message = el.dataset.message || el.validationMessage
if ( label )
label.insertAdjacentHTML( 'beforeend', '<aside class="validation-message"><p>' + message + '</p></aside>' )
}
// Public API
module.exports = {
watch: watch,
validate: validateForm
}
{
"name": "compose-form-up",
"version": "1.0.0",
"version": "1.1.0",
"description": "A lightweight HTML5 form validation utility",

@@ -33,4 +33,4 @@ "main": "index.js",

"chai": "^3.5.0",
"mochify": "^2.17.0"
"mochify": "^2.18.1"
}
}
# FormUp
A lightwight HTML5 form validation module.
A lightwight form utlitiy module.
### `watch()` - Automatic
## Validation
FormUp enhances HTML5's form validation, adding `valid` and `invalid` classes as the form is completed, and handling custom messages with a bit more finesse.
### Automatic validation
FormUp can watch for form submission events and stop them and style invalid

@@ -15,7 +19,9 @@ inputs, and add messages if the form is invalid. This will also watch for

var formUp = require( 'compose-form-up' )
formUp.watch()
```
### `validate( form )` - Manual
Whenever `submit` is triggered on a form, validation will
automatically run, handling messages and styles.
### `validate( form )` - Manual Validation
This component works best automatically, but if for some reason you have to

@@ -38,1 +44,57 @@ manually trigger validation, you'd do this.

invalid styles you'll need to run this any time a form element is updated.
## Progressive Forms
A progressive form will show one fieldset at a time. Each time a submit event is triggered, the active fieldset will transition away (assuming there are no
validation errors), and the next fieldset will appear. Once all fieldsets are complete, the form will submit as usual. You can also register a callback to be
triggered at the point of each transition, to call some scrip before continuing (like an ajax call or whatever).
Here's what a simple progressive form may look like.
```html
<form id="some-form" class="progressive">
<fieldset class="form-step">
<!-- Some inputs -->
<button type='submit'>Submit</button>
</fieldset>
<fieldset class="form-step">
<!-- Some more inputs -->
<button type='submit'>Submit</button>
</fieldset>
</form>
```
### Handling the next event
```js
var formUp = require( 'compose-form-up' )
var form = document.querySelector( '#some-form' )
formUp.next( form, function( event, step ) {
// event is the submission event
// step.forward() - go to the next step
// step.back() - return to this step
// step.fieldset - reference the current fieldset element
// step.form - reference to the current form element
// step.complete - true/false - is this the last step?
// step.formData - formData object for the current fieldset ( handy for ajax )
// Example ajax
ajax.post( '/users' )
.send( step.formData )
.end( function( err, response ) {
if (!err) step.forward() // go to the next fielset
else step.back() // return to current fieldset
})
})
```

@@ -15,4 +15,17 @@ var assert = require('chai').assert

container: function() {
var div = document.querySelector('.container')
if ( !div ){
div = Utils.injectHTML( document.body, '<div class="container"></div>' )
} else {
div.innerHTML = ''
}
return div
},
addInput: function( form, options ) {
options = options || {}
defaults = {

@@ -24,3 +37,3 @@ required: true,

var label = Utils.injectHTML( form, '<label></label>' )
var input = Utils.injectHTML( label, '<input />' )
var input = Utils.injectHTML( label, '<input>' )

@@ -38,2 +51,3 @@ for ( var attr in defaults ) { input.setAttribute( attr, defaults[attr] ) }

setValue: function( input, value ) {
input.setAttribute( 'value', value )
input.value = value

@@ -40,0 +54,0 @@ Event.fire( input, 'blur' )

@@ -1,74 +0,159 @@

var assert = require( 'chai' ).assert
var formUp = require( '../' )
var utils = require( './_utils' )
var isValid = utils.isValid
var isInvalid = utils.isInvalid
var setValue = utils.setValue
formUp.watch()
var assert = require( 'chai' ).assert,
formUp = require( '../' ),
utils = require( './_utils' ),
isValid = utils.isValid,
isInvalid = utils.isInvalid,
setValue = utils.setValue,
Event = require( 'compose-event' )
describe( 'validate', function() {
describe( 'formup', function() {
var form = utils.injectHTML( document.body, '<form></form>' )
var form = utils.injectHTML( utils.container(), '<form class="progressive"></form>' )
form.innerHTML = '<fieldset id="fieldsetOne" class="form-step"></fieldset>\
<fieldset id="fieldsetTwo" class="form-step"></fieldset>\
<fieldset class="form-step"></fieldset>'
beforeEach( function() {
form.innerHTML = ""
})
var fieldsetOne = form.querySelector('#fieldsetOne')
var fieldsetTwo = form.querySelector('#fieldsetTwo')
it( 'required inputs', function() {
Event.fire( document, 'DOMContentLoaded' )
Event.fire( document, 'page:change' )
var input = utils.addInput( form, {})
describe( 'validate', function() {
setValue( input, '' )
isInvalid( input )
it( 'styles valid and invalid inputs', function() {
setValue( input, 'test' )
isValid( input )
var input = utils.addInput( fieldsetOne )
})
setValue( input, '' )
isInvalid( input )
it( 'maximum words', function() {
setValue( input, 'test' )
isValid( input )
var input = utils.addInput( form, { 'data-max-words': '3' })
fieldsetOne.removeChild( fieldsetOne.lastChild )
})
setValue( input, 'two words' )
isValid( input )
it( 'tests maximum words', function() {
})
var input = utils.addInput( fieldsetOne, { 'data-max-words': '3' })
it( 'minimum words', function() {
setValue( input, 'two words' )
isValid( input )
var input = utils.addInput( form, { 'data-min-words': '3' })
setValue( input, 'too many words here' )
isInvalid( input )
setValue( input, 'two words' )
isInvalid( input )
fieldsetOne.removeChild( fieldsetOne.lastChild )
})
})
it( 'sets custom validation messages', function() {
it( 'tests minimum words', function() {
var input = utils.addInput( form, { 'data-min-words': '3' })
var input = utils.addInput( fieldsetOne, { 'data-min-words': '3' })
setValue( input, 'two words' )
formUp.validate( form )
setValue( input, 'two words' )
isInvalid( input )
// Check custom validation message
assert.equal( input.parentNode.textContent, 'Please write at least 3 words.' )
setValue( input, 'three words here' )
isValid( input )
setValue( input, 'here are three' )
fieldsetOne.removeChild( fieldsetOne.lastChild )
// Check that messages are hidden when input is valid
assert.equal( input.parentNode.textContent, '' )
})
it( 'sets custom validation messages', function() {
var input = utils.addInput( fieldsetOne, { 'data-min-words': '3' })
setValue( input, 'two words' )
formUp.validate( form )
// Check custom validation message
assert.equal( input.parentNode.textContent, 'Please write at least 3 words.' )
setValue( input, 'here are three' )
// Check that messages are hidden when input is valid
assert.equal( input.parentNode.textContent, '' )
fieldsetOne.removeChild( fieldsetOne.lastChild )
})
it( 'traps form submissions', function() {
var input = utils.addInput( fieldsetOne, { 'data-min-words': '3' })
setValue( input, 'two words' )
utils.submit( form )
assert.equal( input.parentNode.textContent, 'Please write at least 3 words.' )
fieldsetOne.removeChild( fieldsetOne.lastChild )
})
})
it( 'traps form submissions', function() {
describe( 'progressive form', function() {
var input = utils.addInput( form, { 'data-min-words': '3' })
formUp.next( form, function( event, step ) {
setValue( input, 'two words' )
utils.submit( form )
// Manufacture a reason to go back
if ( step.fieldset.classList.contains('back') )
step.back()
else
step.forward()
assert.equal( input.parentNode.textContent, 'Please write at least 3 words.' )
})
it( 'hides all but the first fieldset', function() {
assert.isTrue( !fieldsetOne.disabled )
assert.isTrue( fieldsetTwo.disabled )
})
it( 'does not progress if an input is invalid', function() {
// Add an invalid input (no value)
var input = utils.addInput( fieldsetOne )
utils.submit( form )
assert.isTrue( !fieldsetOne.disabled )
assert.isTrue( fieldsetTwo.disabled )
fieldsetOne.removeChild( fieldsetOne.lastChild )
})
it( 'progresses if an input is valid', function( ) {
// Add a valid input
var input = utils.addInput( fieldsetOne, { value: 'true' } )
utils.submit( form )
assert.isTrue( fieldsetOne.disabled )
assert.isTrue( !fieldsetTwo.disabled )
fieldsetOne.removeChild( fieldsetOne.lastChild )
})
it( 'can step back', function( ) {
// Add a valid input
var input = utils.addInput( fieldsetTwo, { value: 'true' } )
fieldsetTwo.classList.add( 'back' )
utils.submit( form )
assert.isTrue( !fieldsetTwo.disabled )
})
})
})

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