/** * fullscreenForm.js v1.0.0 * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2014, Codrops * http://www.codrops.com */ ;( function( window ) { 'use strict'; var support = { animations : Modernizr.cssanimations }, animEndEventNames = { 'WebkitAnimation' : 'webkitAnimationEnd', 'OAnimation' : 'oAnimationEnd', 'msAnimation' : 'MSAnimationEnd', 'animation' : 'animationend' }, // animation end event name animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ]; /** * extend obj function */ function extend( a, b ) { for( var key in b ) { if( b.hasOwnProperty( key ) ) { a[key] = b[key]; } } return a; } /** * createElement function * creates an element with tag = tag, className = opt.cName, innerHTML = opt.inner and appends it to opt.appendTo */ function createElement( tag, opt ) { var el = document.createElement( tag ) if( opt ) { if( opt.cName ) { el.className = opt.cName; } if( opt.inner ) { el.innerHTML = opt.inner; } if( opt.appendTo ) { opt.appendTo.appendChild( el ); } } return el; } // finds no of occurances of substring function occurrences(string, subString, allowOverlapping) { string += ""; subString += ""; if (subString.length <= 0) return (string.length + 1); var n = 0, pos = 0, step = allowOverlapping ? 1 : subString.length; while (true) { pos = string.indexOf(subString, pos); if (pos >= 0) { ++n; pos += step; } else break; } return n; } function isTransfer(text){ var wordlist = ['transfer','send','give']; // keep list's content lowercase var textList = text.split(' '); for (var i=0; i1){ return 'too many'; } if (count==1 && !returnval) { returnval = operationList[i]; } } return returnval; } function extractAmount(text) { var count=0; var returnval; var splitText = text.split(/\W+/); for (var i=0; i1){ return 'Too many'; } } return returnval; } function extractInitTokens(text){ var base_units = {'thousand':10**3 , 'million':10**6 ,'billion':10**9, 'trillion':10**12}; var textList = text.split(' '); for (var i=0; i' : ''; } this.ctrlNav.innerHTML = dots; this._showCtrl( this.ctrlNav ); this.ctrlNavDots = [].slice.call( this.ctrlNav.children ); } // field number status if( this.options.ctrlNavPosition ) { this.ctrlFldStatus = createElement( 'span', { cName : 'fs-numbers', appendTo : this.ctrls } ); // current field placeholder this.ctrlFldStatusCurr = createElement( 'span', { cName : 'fs-number-current', inner : Number( this.current + 1 ) } ); this.ctrlFldStatus.appendChild( this.ctrlFldStatusCurr ); // total fields placeholder this.ctrlFldStatusTotal = createElement( 'span', { cName : 'fs-number-total', inner : this.fieldsCount } ); this.ctrlFldStatus.appendChild( this.ctrlFldStatusTotal ); this._showCtrl( this.ctrlFldStatus ); } // progress bar if( this.options.ctrlProgress ) { this.ctrlProgress = createElement( 'div', { cName : 'fs-progress', appendTo : this.ctrls } ); this._showCtrl( this.ctrlProgress ); } } /** * addErrorMsg function * create and insert the structure for the error message */ FForm.prototype._addErrorMsg = function() { // error message this.msgError = createElement( 'span', { cName : 'fs-message-error', appendTo : this.el } ); } /** * init events */ FForm.prototype._initEvents = function() { var self = this; // show next field this.ctrlContinue.addEventListener( 'click', function() { var flodata = document.getElementById('q1'); var result = parse_flodata(flodata.value); console.log(result); self._nextField(undefined,result); } ); // navigation dots if( this.options.ctrlNavDots ) { this.ctrlNavDots.forEach( function( dot, pos ) { dot.addEventListener( 'click', function() { self._showField( pos ); } ); } ); } // jump to next field without clicking the continue button (for fields/list items with the attribute "data-input-trigger") this.fields.forEach( function( fld ) { if( fld.hasAttribute( 'data-input-trigger' ) ) { var input = fld.querySelector( 'input[type="radio"]' ) || /*fld.querySelector( '.cs-select' ) ||*/ fld.querySelector( 'select' ); // assuming only radio and select elements (TODO: exclude multiple selects) if( !input ) return; switch( input.tagName.toLowerCase() ) { case 'select' : input.addEventListener( 'change', function() { self._nextField(); } ); break; case 'input' : [].slice.call( fld.querySelectorAll( 'input[type="radio"]' ) ).forEach( function( inp ) { inp.addEventListener( 'change', function(ev) { self._nextField(); } ); } ); break; /* // for our custom select we would do something like: case 'div' : [].slice.call( fld.querySelectorAll( 'ul > li' ) ).forEach( function( inp ) { inp.addEventListener( 'click', function(ev) { self._nextField(); } ); } ); break; */ } } } ); // keyboard navigation events - jump to next field when pressing enter document.addEventListener( 'keydown', function( ev ) { if( !self.isLastStep && ev.target.tagName.toLowerCase() !== 'textarea' ) { var keyCode = ev.keyCode || ev.which; if( keyCode === 13 ) { ev.preventDefault(); var flodata = document.getElementById('q1'); var result = parse_flodata(flodata.value); console.log(result); self._nextField(undefined,result); } } } ); }; /** * nextField function * jumps to the next field */ FForm.prototype._nextField = function( backto, result ) { if( this.isLastStep || !this._validade() || this.isAnimating ) { return false; } this.isAnimating = true; // check if on last step this.isLastStep = this.current === this.fieldsCount - 1 && backto === undefined ? true : false; // clear any previous error messages this._clearError(); // current field var currentFld = this.fields[ this.current ]; // save the navigation direction this.navdir = backto !== undefined ? backto < this.current ? 'prev' : 'next' : 'next'; // update current field this.current = backto !== undefined ? backto : this.current + 1; if( backto === undefined ) { // update progress bar (unless we navigate backwards) this._progress(); // save farthest position so far this.farthest = this.current; } // add class "fs-display-next" or "fs-display-prev" to the list of fields classie.add( this.fieldsList, 'fs-display-' + this.navdir ); // remove class "fs-current" from current field and add it to the next one // also add class "fs-show" to the next field and the class "fs-hide" to the current one classie.remove( currentFld, 'fs-current' ); classie.add( currentFld, 'fs-hide' ); if( !this.isLastStep ) { // update nav this._updateNav(); // change the current field number/status this._updateFieldNumber(); var nextField = this.fields[ this.current ]; classie.add( nextField, 'fs-current' ); classie.add( nextField, 'fs-show' ); } // after animation ends remove added classes from fields var self = this, onEndAnimationFn = function( ev ) { if( support.animations ) { this.removeEventListener( animEndEventName, onEndAnimationFn ); } classie.remove( self.fieldsList, 'fs-display-' + self.navdir ); classie.remove( currentFld, 'fs-hide' ); if( self.isLastStep ) { // show the complete form and hide the controls self._hideCtrl( self.ctrlNav ); self._hideCtrl( self.ctrlProgress ); self._hideCtrl( self.ctrlContinue ); self._hideCtrl( self.ctrlFldStatus ); // replace class fs-form-full with fs-form-overview classie.remove( self.formEl, 'fs-form-full' ); classie.add( self.formEl, 'fs-form-overview' ); classie.add( self.formEl, 'fs-show' ); classie.add( self.formEl, 'hideElement' ); // Result display page var div = document.createElement("div"); div.setAttribute("id", "resultPage"); div.setAttribute("class", "fs-form fs-form-overview fs-show"); var ol = document.createElement('ol'); ol.setAttribute("class","fs-fields"); if (result['type'] == 'transfer'){ var fieldnames = [{'FLO data':result['flodata']},{'Type':'Transfer'},{'Identification':result['marker']},{'Amount':result['amount']}] }else if (result['type'] == 'incorporation'){ var fieldnames = [{'FLO data':result['flodata']},{'Type':'Incorporation'},{'Identification':result['marker']},{'Amount':result['initTokens']}] }else{ var fieldnames = [{'FLO data':result['flodata']},{'Type':'Noise'}] } for (var i=0; i this.fieldsCount - 1 ) { return false; } this._nextField( pos ); } /** * updateFieldNumber function * changes the current field number */ FForm.prototype._updateFieldNumber = function() { if( this.options.ctrlNavPosition ) { // first, create next field number placeholder this.ctrlFldStatusNew = document.createElement( 'span' ); this.ctrlFldStatusNew.className = 'fs-number-new'; this.ctrlFldStatusNew.innerHTML = Number( this.current + 1 ); // insert it in the DOM this.ctrlFldStatus.appendChild( this.ctrlFldStatusNew ); // add class "fs-show-next" or "fs-show-prev" depending on the navigation direction var self = this; setTimeout( function() { classie.add( self.ctrlFldStatus, self.navdir === 'next' ? 'fs-show-next' : 'fs-show-prev' ); }, 25 ); } } /** * progress function * updates the progress bar by setting its width */ FForm.prototype._progress = function() { if( this.options.ctrlProgress ) { this.ctrlProgress.style.width = this.current * ( 100 / this.fieldsCount ) + '%'; } } /** * updateNav function * updates the navigation dots */ FForm.prototype._updateNav = function() { if( this.options.ctrlNavDots ) { classie.remove( this.ctrlNav.querySelector( 'button.fs-dot-current' ), 'fs-dot-current' ); classie.add( this.ctrlNavDots[ this.current ], 'fs-dot-current' ); this.ctrlNavDots[ this.current ].disabled = false; } } /** * showCtrl function * shows a control */ FForm.prototype._showCtrl = function( ctrl ) { classie.add( ctrl, 'fs-show' ); } /** * hideCtrl function * hides a control */ FForm.prototype._hideCtrl = function( ctrl ) { classie.remove( ctrl, 'fs-show' ); } // TODO: this is a very basic validation function. Only checks for required fields.. FForm.prototype._validade = function() { var fld = this.fields[ this.current ], input = fld.querySelector( 'input[required]' ) || fld.querySelector( 'textarea[required]' ) || fld.querySelector( 'select[required]' ), error; if( !input ) return true; switch( input.tagName.toLowerCase() ) { case 'input' : if( input.type === 'radio' || input.type === 'checkbox' ) { var checked = 0; [].slice.call( fld.querySelectorAll( 'input[type="' + input.type + '"]' ) ).forEach( function( inp ) { if( inp.checked ) { ++checked; } } ); if( !checked ) { error = 'NOVAL'; } } else if( input.value === '' ) { error = 'NOVAL'; } break; case 'select' : // assuming here '' or '-1' only if( input.value === '' || input.value === '-1' ) { error = 'NOVAL'; } break; case 'textarea' : if( input.value === '' ) { error = 'NOVAL'; } break; } if( error != undefined ) { this._showError( error ); return false; } return true; } // TODO FForm.prototype._showError = function( err ) { var message = ''; switch( err ) { case 'NOVAL' : message = 'Please fill the field before continuing'; break; case 'INVALIDEMAIL' : message = 'Please fill a valid email address'; break; // ... }; this.msgError.innerHTML = message; this._showCtrl( this.msgError ); } // clears/hides the current error message FForm.prototype._clearError = function() { this._hideCtrl( this.msgError ); } // add to global namespace window.FForm = FForm; })( window );