compose-form-up
Advanced tools
Comparing version 1.3.4 to 1.4.0
@@ -7,3 +7,3 @@ var toolbox = require( 'compose-toolbox' ), | ||
formCallbacks, | ||
registerdForms | ||
registeredForms | ||
@@ -14,3 +14,3 @@ // Remove any existing callbacks and registered forms | ||
formCallbacks = { next: [] } | ||
registerdForms = [] | ||
registeredForms = [] | ||
@@ -24,48 +24,80 @@ } | ||
var steps = toolbox.slice( form.querySelectorAll( '.form-step' ) ), | ||
stepIndex = -1; | ||
stepIndex = 0, | ||
navItems = '' | ||
if ( steps.length == 0 ) return | ||
steps.forEach( function( step ) { step.disabled = true }) | ||
forward() | ||
steps.forEach( function( step, index ) { | ||
function previousStep () { return steps[ stepIndex - 1] } | ||
function currentStep () { return steps[ stepIndex ] } | ||
function nextStep () { return steps[ stepIndex + 1] } | ||
function active () { return currentStep() && !currentStep().disabled } | ||
// disable all steps but the current step | ||
step.disabled = step != currentStep() | ||
step.dataset.step = index | ||
// Move to next fieldset | ||
function forward ( timer ) { | ||
}) | ||
// Hide current step before advancing to the next one | ||
if ( active() ) { | ||
return dismiss( function() { forward( timer ) } ) | ||
} | ||
if ( form.dataset.nav ) { | ||
var nav = '<nav class="progressive-form-nav">' | ||
if ( nextStep() ) { | ||
stepIndex += 1 | ||
steps.forEach( function( step, index ) { | ||
nav += '<a href="#" class="progressive-form-nav-item" data-step="'+( index + 1 )+'">' | ||
nav += step.dataset.nav || "Step " + ( index + 1 ) | ||
nav += '</a> ' | ||
}) | ||
if ( timer ) { Event.delay( show, timer ) } | ||
else { show() } | ||
} | ||
nav += '</nav>' | ||
form.insertAdjacentHTML( 'afterbegin', nav ) | ||
} | ||
// Move to previous fieldset // Show the current step again | ||
function back ( timer ) { | ||
show() | ||
if ( timer ) { Event.delay( show, timer ) } | ||
else { show() } | ||
Event.afterAnimation( currentStep(), function() { | ||
Event.fire( toolbox.getClosest(currentStep(), 'form'), 'validate' ) | ||
}) | ||
function previousStep () { return steps[ stepIndex - 1] } | ||
function currentStep () { return steps[ stepIndex ] } | ||
function nextStep () { return steps[ stepIndex + 1] } | ||
function active () { return currentStep() && !currentStep().disabled } | ||
// Move to next fieldset | ||
function forward () { | ||
showStep( stepIndex + 1 ) | ||
} | ||
// Move to next fieldset | ||
function back () { | ||
showStep( stepIndex - 1 ) | ||
} | ||
// Accepts a step index | ||
function showStep ( index ) { | ||
index = Number( index ) | ||
// Get the step from the index | ||
var step = steps[ index ] | ||
// Don't go to a non-existant step, or the current step | ||
if ( step && step != currentStep() ) { | ||
var direction = ( stepIndex < index ) ? 'forward' : 'reverse' | ||
// If a step is currently active | ||
// dismiss it before going to the specified step | ||
if ( active() ) { | ||
return dismiss( function() { showStep( index ) }, direction ) | ||
} | ||
stepIndex = index | ||
show( direction ) | ||
} | ||
} | ||
// Hide a completed step and move to the next | ||
function dismiss ( callback ) { | ||
function dismiss ( callback, direction ) { | ||
direction = direction || 'forward' | ||
currentStep().classList.remove( 'step-visited', 'arrived' ) | ||
currentStep().classList.add( 'departed' ) | ||
currentStep().classList.remove( 'active', 'enter' ) | ||
currentStep().classList.add( 'exit' ) | ||
currentStep().dataset.direction = direction | ||
@@ -81,11 +113,29 @@ Event.afterAnimation( currentStep(), function() { | ||
function revisit ( callback, direction ) { | ||
if ( !active() ) { | ||
direction = direction || 'reverse' | ||
currentStep().classList.remove( 'exit', 'completed' ) | ||
currentStep().classList.add( 'active', 'enter' ) | ||
currentStep().dataset.direction = direction | ||
disableOtherFieldsets() | ||
Event.afterAnimation( currentStep(), function() { | ||
if ( typeof callback === 'function' ) callback() | ||
}) | ||
} | ||
} | ||
// Show the form-step | ||
function show () { | ||
function show ( direction ) { | ||
currentStep().disabled = false | ||
disableOtherFieldsets() | ||
currentStep().classList.remove( 'completed' ) | ||
currentStep().classList.add( 'arrived' ) | ||
currentStep().dataset.direction = direction | ||
currentStep().classList.add( 'active', 'enter' ) | ||
// focus on the first input | ||
var firstInput = currentStep().querySelector( 'input:not([hidden])' ) | ||
var firstInput = currentStep().querySelector( 'input:not([hidden]), textarea, select' ) | ||
if ( firstInput ) firstInput.focus() | ||
@@ -99,4 +149,4 @@ | ||
currentStep().disabled = true | ||
currentStep().classList.add( 'step-visited', 'completed' ) | ||
currentStep().classList.remove( 'departed', 'arrived' ) | ||
currentStep().classList.add( 'completed' ) | ||
currentStep().classList.remove( 'enter', 'exit' ) | ||
@@ -109,27 +159,38 @@ } | ||
}) | ||
} | ||
function disableOtherFieldsets ( ) { | ||
steps.forEach( function( fieldset ) { | ||
fieldset.disabled = fieldset != currentStep() | ||
}) | ||
} | ||
registerdForms.push( function( event ) { | ||
registeredForms.push( function( event, trigger ) { | ||
// Continue if submit was triggered on this form | ||
// and no invalid fields are found | ||
if ( trigger === 'show-step' ) { | ||
var formEl = ( event.target.tagName == "FORM" ) ? event.target : toolbox.getClosest( event.target, 'form') | ||
showStep( event.currentTarget.dataset.step - 1 ) | ||
if ( form == formEl && !currentStep().querySelector( ':invalid' ) ) { | ||
} else if ( trigger === 'next' ) { | ||
// Get the function which triggers callbacks | ||
var fireCallbacks = getCallbacks( form ) | ||
// Continue if submit was triggered on this form | ||
// and no invalid fields are found | ||
// This is the last stop, be sure all fieldsets are enabled! | ||
if ( !nextStep() ) enableFieldsets( form ) | ||
var formEl = ( event.target.tagName == "FORM" ) ? event.target : toolbox.getClosest( event.target, 'form') | ||
// If there are callbacks, let them handle this! | ||
if ( fireCallbacks ) { | ||
if ( form == formEl && !currentStep().querySelector( ':invalid' ) ) { | ||
// Since there are callbacks, stop the submission event | ||
event.preventDefault() | ||
// Get the function which triggers callbacks | ||
var fireCallbacks = getCallbacks( form ) | ||
dismiss( function(){ | ||
// This is the last stop, be sure all fieldsets are enabled! | ||
if ( !nextStep() ) enableFieldsets( form ) | ||
else disableOtherFieldsets( form ) | ||
// If there are callbacks, let them handle this! | ||
if ( fireCallbacks ) { | ||
// Since there are callbacks, stop the submission event | ||
event.preventDefault() | ||
fireCallbacks( event, { | ||
@@ -139,13 +200,15 @@ fieldset: currentStep(), // Valid fieldset element | ||
forward: forward, // Call forward() to move to the next fieldset | ||
back: back, // Call back() to revisit a fieldset ( perhaps because of an ajax error ) | ||
dismiss: dismiss, // Hide and disable current step | ||
revisit: revisit, // Revisit current disabled step | ||
showStep: showStep, // Show a specific step by index (0 based) | ||
complete: !nextStep(), // is this is the final form step? | ||
formData: toolbox.formData( currentStep() ) // pass FormData for current fieldset | ||
}) | ||
}) | ||
} | ||
} | ||
// No callbacks? If there's a next step, stop submission and proceed | ||
else if ( nextStep() ) { | ||
event.preventDefault() | ||
forward() | ||
// No callbacks? If there's a next step, stop submission and proceed | ||
else if ( nextStep() ) { | ||
event.preventDefault() | ||
forward() | ||
} | ||
} | ||
@@ -156,4 +219,4 @@ } | ||
function fire ( event ) { | ||
registerdForms.forEach( function( fn ) { fn( event ) }) | ||
function fire ( event, type ) { | ||
registeredForms.forEach( function( fn ) { fn( event, type ) }) | ||
} | ||
@@ -218,4 +281,19 @@ | ||
Event.on( document, 'click', formSelector + ' [type=submit]', fire ) | ||
var nextSelector = formSelector + ' [type=submit], ' + formSelector + ' .next-step' | ||
var backSelector = formSelector + ' .back-step' | ||
var navSelector = '.progressive-form-nav-item[data-step]' | ||
Event.on( document, 'click', nextSelector , fire, 'next' ) | ||
Event.on( document, 'click', backSelector , fire, 'back' ) | ||
Event.on( document, 'click', navSelector , fire, 'show-step' ) | ||
// insert core styling for hiding disabled and completed form-steps | ||
document.head.insertAdjacentHTML( 'beforeend', "<style>\ | ||
.form-step[disabled], .form-step.completed {\ | ||
position: absolute !important;\ | ||
top: -9999px !important;\ | ||
left: -9999px !important;\ | ||
left: 0 !important;\ | ||
right: 0 !important; }\ | ||
</style>" ) | ||
Event.change( function() { | ||
@@ -222,0 +300,0 @@ reset() |
{ | ||
"name": "compose-form-up", | ||
"version": "1.3.4", | ||
"version": "1.4.0", | ||
"description": "A lightweight HTML5 form validation utility", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -1,2 +0,1 @@ | ||
var assert = require( 'chai' ).assert, | ||
@@ -13,6 +12,6 @@ formUp = require( '../' ), | ||
var form = utils.injectHTML( utils.container(), '<form class="progressive"></form>' ) | ||
var form = utils.injectHTML( utils.container(), '<form class="progressive" data-nav="true"></form>' ) | ||
form.innerHTML = '<button type="submit">Submit</button>\ | ||
<fieldset id="fieldsetOne" class="form-step"></fieldset>\ | ||
<fieldset id="fieldsetTwo" class="form-step"></fieldset>\ | ||
<fieldset id="fieldsetTwo" class="form-step" data-nav="Step Two"></fieldset>\ | ||
<fieldset class="form-step"></fieldset>' | ||
@@ -139,6 +138,4 @@ | ||
// Manufacture a reason to go back | ||
if ( step.fieldset.classList.contains('back') ) | ||
step.back() | ||
else | ||
// Manufacture a reason to prevent moving forward | ||
if ( !form.classList.contains('fake-error') ) | ||
step.forward() | ||
@@ -148,5 +145,14 @@ | ||
it( 'hides all but the first fieldset', function() { | ||
it( 'can generate form navigation', function( ) { | ||
assert.isDefined( form.querySelector( '.progressive-form-nav' ) ) | ||
}) | ||
assert.isTrue( !fieldsetOne.disabled ) | ||
it( 'customizes nav labels for form navigation', function( ) { | ||
var step = form.querySelector( '.progressive-form-nav-item[data-step="2"]' ) | ||
assert.equal( step.textContent, 'Step Two' ) | ||
}) | ||
it( 'disables all but the first fieldset', function() { | ||
assert.isFalse( fieldsetOne.disabled ) | ||
assert.isTrue( fieldsetTwo.disabled ) | ||
@@ -163,3 +169,3 @@ | ||
assert.isTrue( !fieldsetOne.disabled ) | ||
assert.isFalse( fieldsetOne.disabled ) | ||
assert.isTrue( fieldsetTwo.disabled ) | ||
@@ -185,15 +191,31 @@ | ||
it( 'can step back', function( ) { | ||
it( 'can revisit a fieldset after submission', function( ) { | ||
// Add a valid input | ||
var input = utils.addInput( fieldsetTwo, { value: 'true' } ) | ||
fieldsetTwo.classList.add( 'back' ) | ||
form.classList.add( 'fake-error' ) | ||
utils.submit( form ) | ||
assert.isTrue( !fieldsetTwo.disabled ) | ||
assert.isFalse( fieldsetTwo.disabled ) | ||
assert.isTrue( fieldsetTwo.classList.contains( 'active' ) ) | ||
}) | ||
it( 'can go to a specific step', function( ) { | ||
assert.isTrue( fieldsetOne.disabled ) | ||
var nav = document.querySelector( 'nav' ) | ||
Event.fire( nav.firstChild, 'click' ) | ||
assert.isFalse( fieldsetOne.disabled ) | ||
assert.isTrue( fieldsetTwo.disabled ) | ||
Event.fire( nav.querySelector( '[data-step="2"]' ), 'click' ) | ||
assert.isTrue( fieldsetOne.disabled ) | ||
assert.isFalse( fieldsetTwo.disabled ) | ||
}) | ||
}) | ||
}) |
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
26777
571