// @todo find a better solution? function toggleCountry( sCountry, bKeepData ) { if( null === oValidator || !document.getElementById('l1b') ) { return; } if( 'boolean' === typeof( bKeepData ) ) { oValidator.bKeepCountryData = bKeepData; } for( pQuestionPointer in oValidator.aQuestions ) { if( 152 === oValidator.aQuestions[ pQuestionPointer ].iDataNameId ) { if( 2 === oValidator.aQuestions[ pQuestionPointer ].iInputTypeId ) { for( var i = 0; i < oValidator.aQuestions[ pQuestionPointer ].aHtmlObjects[0].options.length; i++ ) { if( sCountry === oValidator.aQuestions[ pQuestionPointer ].aHtmlObjects[0].options[ i ].value ) { oValidator.aQuestions[ pQuestionPointer ].aHtmlObjects[0].options[ i ].selected = 'selected'; oValidator.aQuestions[ pQuestionPointer ].aHtmlObjects[0].onchange(); } } } } } } function LgValidator( oFormObj ) { this.oForm = oFormObj this.aQuestions = new Array(); this.aQuestionGroups = new Array(); this.sDefaultCountry = 'nl'; this.sCurrentCountry = 'nl'; this.bKeepCountryData = false; this.aErrors = new Array(); this.bIsValid = true; this.sDefaultRowClassName = 'dai_campaign_table_tr'; this.sErrorRowClassName = 'dai_campaign_table_error_text'; } LgValidator.prototype.prepareForm = function() { var oSelfReference = this; this.oForm.onsubmit = function() { return oSelfReference.isValid(); } } LgValidator.prototype.prepareCountry = function( sCountry ) { if( typeof( sPortalCountry ) === 'undefined') { this.sCurrentCountry = this.sDefaultCountry; } else { this.sCurrentCountry = sPortalCountry; } if( this.sCurrentCountry !== this.sDefaultCountry ) { toggleCountry( this.sCurrentCountry, true ); } } LgValidator.prototype.addQuestion = function( iId, bIsRequired, iMin, iMax, iDataTypeId, iDataNameId, iInputTypeId, sValidationFunction, oHtmlObj, oExtraHtmlObj, iGroupId, sGroupName, sGroupType ) { // Create an LgQuestion object if not set yet. if( 'undefined' === typeof( this.aQuestions[ iId ] ) ) { this.aQuestions[ iId ] = new LgQuestion( iId, bIsRequired, iMin, iMax, iDataTypeId, iDataNameId, iInputTypeId, sValidationFunction, oHtmlObj, oExtraHtmlObj, iGroupId ); } // Add the (extra) HTML object this.aQuestions[ iId ].addHtmlObject( oHtmlObj ); this.aQuestions[ iId ].addHtmlObject( oExtraHtmlObj, true ); // If the question is part of a question group > // create an LgQuestionGroup object if not set yet. // @todo what if the question isnt part of a question group? if( 'undefined' === typeof( this.aQuestionGroups[ iGroupId ] ) ) { this.aQuestionGroups[ iGroupId ] = new LgQuestionGroup( iGroupId, sGroupName, sGroupType ); } // Add the LgQuestion object to the group this.aQuestionGroups[ iGroupId ].addQuestion( this.aQuestions[ iId ] ); // Reference objects var oSelfReference = this; var oQuestionReference = this.aQuestions[ iId ]; var oQuestionGroupReference = this.aQuestionGroups[ iGroupId ]; // Add some extra functionality to certain objects // For zipcode and housenumber, onkeyup check/update address details if( 5 === iDataTypeId || 10 === iDataTypeId && 'undefined' !== typeof( oQuestionGroupReference ) ) { oHtmlObj.onkeyup = function(e) { oSelfReference.validateAddress( oQuestionGroupReference, true ); } } // For country selection (NL/BE), onclick/onchange change country if( 152 === iDataNameId ) { oHtmlObj.onchange = function(e) { //oSelfReference.changeCountry( this.value, oQuestionReference.iId ); oSelfReference.changeCountry( this.options[ this.selectedIndex ].value, oQuestionReference.iId ); } } } LgValidator.prototype.resetValidator = function() { this.aErrors = new Array(); this.bIsValid = true; for( pPointer in this.aQuestions ) { this.resetQuestion( this.aQuestions[ pPointer ] ); } } LgValidator.prototype.resetQuestion = function( oLgQuestion ) { document.getElementById( 'dai_q_'+ oLgQuestion.iId +'_row' ).className = this.sDefaultRowClassName; for( pPointer in oLgQuestion.aHtmlObjects ) { if( ( oLgQuestion.aHtmlObjects[ pPointer ].type ) && ( 'radio' === oLgQuestion.aHtmlObjects[ pPointer ].type || 'checkbox' === oLgQuestion.aHtmlObjects[ pPointer ].type ) ) { continue; } oLgQuestion.aHtmlObjects[ pPointer ].value = ''; } } LgValidator.prototype.setQuestionIsRequired = function( oLgQuestion, bIsRequired ) { oLgQuestion.bIsRequired = bIsRequired; var aChildNodes = document.getElementById( 'dai_t_'+ oLgQuestion.iId ).childNodes; for( var pPointer = 0; pPointer < aChildNodes.length; pPointer++ ) { if( 'undefined' !== aChildNodes[ pPointer ].className && 'dai_question_is_required' === aChildNodes[ pPointer ].className ) { aChildNodes[ pPointer ].innerHTML = ( true === bIsRequired ? '*' : ' '); } } } LgValidator.prototype.changeCountry = function( sCountry, iQuestionId ) { this.sCurrentCountry = sCountry.toLowerCase(); var oLgQuestion = this.aQuestions[ iQuestionId ]; if( 'undefined' !== typeof( this.aQuestionGroups[ oLgQuestion.iGroupId ] ) ) { var oLgQuestionGroup = this.aQuestionGroups[ oLgQuestion.iGroupId ]; if( true === oLgQuestionGroup.bHasCountrySelection ) // extra check, which might not even be needed. { if( false === this.bKeepCountryData ) { // Reset questions in this group for( pPointer in oLgQuestionGroup.aQuestions ) { if( iQuestionId === oLgQuestionGroup.aQuestions[ pPointer ].iId ) { continue; } this.resetQuestion( oLgQuestionGroup.aQuestions[ pPointer ] ); } } switch( this.sCurrentCountry ) { case 'be': document.getElementById( 'dai_q_'+ oLgQuestionGroup.oStreetnameQuestion.iId +'_row' ).style.display = ''; document.getElementById( 'dai_q_'+ oLgQuestionGroup.oCityQuestion.iId +'_row' ).style.display = ''; // Streetname and city are required for belgium addresses this.setQuestionIsRequired( oLgQuestionGroup.oStreetnameQuestion, true ); this.setQuestionIsRequired( oLgQuestionGroup.oCityQuestion, true ); var oLgQuestionZipcode = oLgQuestionGroup.oZipcodeQuestion; oLgQuestionZipcode.aHtmlObjects[ 1 ].style.display = 'none'; break; default: case 'nl': if( null !== oLgQuestionGroup.oStreetnameQuestion ) { document.getElementById( 'dai_q_'+ oLgQuestionGroup.oStreetnameQuestion.iId +'_row' ).style.display = ''; this.setQuestionIsRequired( oLgQuestionGroup.oStreetnameQuestion, false ); } if( null !== oLgQuestionGroup.oCityQuestion ) { document.getElementById( 'dai_q_'+ oLgQuestionGroup.oCityQuestion.iId +'_row' ).style.display = ''; this.setQuestionIsRequired( oLgQuestionGroup.oCityQuestion, false ); } var oLgQuestionZipcode = oLgQuestionGroup.oZipcodeQuestion; for( pHtmlObjPointer in oLgQuestionZipcode.aHtmlObjects ) { oLgQuestionZipcode.aHtmlObjects[ pHtmlObjPointer ].style.display = ''; } break; } } } } LgValidator.prototype.validateAddress = function( oLgQuestionGroup, bIsDirectValidation ) { switch( this.sCurrentCountry ) { case 'nl': var bZipcodeOk = false; var bHousenumberOk = false; // If either one field is empty, we don't really have to continue this validation. // this only works of bIsDirectValidation = true. bIsDirectValidation = false when this function is triggered via // validateQuestionGroup, which is called before submitting the form. if( true === bIsDirectValidation && ( ( oLgQuestionGroup.oZipcodeQuestion && '' === this.getValues( oLgQuestionGroup.oZipcodeQuestion ) ) || ( oLgQuestionGroup.oHousenumberQuestion && '' === this.getValues( oLgQuestionGroup.oHousenumberQuestion ) ) ) ) { document.getElementById( 'dai_q_'+ oLgQuestionGroup.oZipcodeQuestion.iId +'_row').className = this.sDefaultRowClassName; document.getElementById( 'dai_q_'+ oLgQuestionGroup.oHousenumberQuestion.iId +'_row').className = this.sDefaultRowClassName; return true; } else { // If all values are given, we can validate if( oLgQuestionGroup.oZipcodeQuestion && this.validateZipcode( this, oLgQuestionGroup.oZipcodeQuestion ) ) { bZipcodeOk = true; } if( oLgQuestionGroup.oHousenumberQuestion && this.validateHousenumber( this, oLgQuestionGroup.oHousenumberQuestion ) ) { bHousenumberOk = true; } if( true === bZipcodeOk && true === bHousenumberOk ) { // Set street, city, etc if possible; // set proper classnames (no error) document.getElementById( 'dai_q_'+ oLgQuestionGroup.oZipcodeQuestion.iId +'_row').className = this.sDefaultRowClassName; document.getElementById( 'dai_q_'+ oLgQuestionGroup.oHousenumberQuestion.iId +'_row').className = this.sDefaultRowClassName; // Use our core zipcode check to validate the given data var goCoreAjax = new coreAjax(); var sUrl = '/ajax/checkZipCode/?zipcode='+ oLgQuestionGroup.oZipcodeQuestion.aHtmlObjects[ 0 ].value +'&zipcode_additive='+ oLgQuestionGroup.oZipcodeQuestion.aHtmlObjects[ 1 ].value +'&homenumber='+ oLgQuestionGroup.oHousenumberQuestion.aHtmlObjects[ 0 ].value +'&country_id=121'; goCoreAjax.bUseXRequestedWithHeader = true; goCoreAjax.setShowErrorMessage(true); var sResponse = goCoreAjax.requestGetTextSynchrone(sUrl); if( sResponse !== 'invalid' || sResponse !== 'not found' ) { var aResponse = sResponse.split( '|' ); if( aResponse[ 0 ] && aResponse[ 1 ] ) { // Set these values to their corresponding questions if( oLgQuestionGroup.oStreetnameQuestion ) { oLgQuestionGroup.oStreetnameQuestion.aHtmlObjects[ 0 ].value = aResponse[ 0 ]; } if( oLgQuestionGroup.oCityQuestion ) { oLgQuestionGroup.oCityQuestion.aHtmlObjects[ 0 ].value = aResponse[ 1 ]; } } else { this.setInvalidAddress( oLgQuestionGroup ); } } else { this.setInvalidAddress( oLgQuestionGroup ); } } else { this.setInvalidAddress( oLgQuestionGroup ); } } break; case 'be': default: return true; break; } } LgValidator.prototype.setInvalidAddress = function( oLgQuestionGroup ) { // Set error class for zipcode and housenumber document.getElementById( 'dai_q_'+ oLgQuestionGroup.oZipcodeQuestion.iId +'_row').className = this.sErrorRowClassName; document.getElementById( 'dai_q_'+ oLgQuestionGroup.oHousenumberQuestion.iId +'_row').className = this.sErrorRowClassName; // Reset streetname and city question if( null !== oLgQuestionGroup.oStreetnameQuestion ) { this.resetQuestion( oLgQuestionGroup.oStreetnameQuestion ); } if( null !== oLgQuestionGroup.oCityQuestion ) { this.resetQuestion( oLgQuestionGroup.oCityQuestion ); } } LgValidator.prototype.isValid = function() { var sReturnMessage = new String(); this.bIsValid = true; // We start off this validation by checking each single (required) question for( pPointer in this.aQuestions ) { var bIsValidQuestion = this.isValidQuestion( this.aQuestions[ pPointer ] ); if( false === bIsValidQuestion ) { this.bIsValid = false; } document.getElementById( 'dai_q_'+ this.aQuestions[ pPointer ].iId +'_row').className = ( true === bIsValidQuestion ? this.sDefaultRowClassName : this.sErrorRowClassName ); } // Followed by group question validation (which is all about the NL zipcode check, really) for( pPointer in this.aQuestionGroups ) { var bIsValidQuestionGroup = this.isValidQuestionGroup( this.aQuestionGroups[ pPointer ] ); if( false === bIsValidQuestionGroup ) { this.bIsValid = false; } } if( true === this.bIsValid ) { return true; } else { alert('U heeft niet alle vragen correct ingevuld.\n\nVul de ingevulde gegevens in of aan waar nodig en klik op verstuur om verder te gaan.'); return false; } } LgValidator.prototype.isValidQuestion = function( oLgQuestion ) { var bIsValidQuestion = false; // If the question if required, we'll check the data in the input(s) if( true === oLgQuestion.bIsRequired ) { if( 1 === oLgQuestion.aHtmlObjects.length ) { switch( oLgQuestion.aHtmlObjects[0].type ) { case 'radio': case 'checkbox': bIsValidQuestion = ( true === oLgQuestion.aHtmlObjects[0].checked ); break; case 'select-multiple': for( var pOptionPointer = 0; pOptionPointer < oLgQuestion.aHtmlObjects[0].options.length; pOptionPointer++ ) { if( oLgQuestion.aHtmlObjects[0].options[ pOptionPointer ].selected ) { bIsValidQuestion = true; } } break; default: bIsValidQuestion = ( '' !== this.trimString( oLgQuestion.aHtmlObjects[0].value ) ); break; } // If the question is already validated as invalid, return. if( false === bIsValidQuestion ) { return bIsValidQuestion } } else // more than one html object refers to radios, checkboxes or special fields like housenumber and addition. { switch( oLgQuestion.aHtmlObjects[0].type ) { case 'radio': for( pHtmlObjPointer in oLgQuestion.aHtmlObjects ) { if( oLgQuestion.aHtmlObjects[ pHtmlObjPointer ].checked ) { bIsValidQuestion = true; } } // If no radio is checked, it's already considered invalid. Let's return false right away. if( false === bIsValidQuestion ) { return bIsValidQuestion; } break; case 'checkbox': var iCheckedAnswers = 0; for( pHtmlObjPointer in oLgQuestion.aHtmlObjects ) { if( oLgQuestion.aHtmlObjects[ pHtmlObjPointer ].checked ) { iCheckedAnswers++; } } // Slightly more advanced check for checkboxes; we're taking in account that there might be a minimum OR maximum number of items that may be checked. if( 0 === iCheckedAnswers || ( 0!== oLgQuestion.iMin && iCheckedAnswers < oLgQuestion.iMin ) || ( 0 !== oLgQuestion.iMax && iCheckedAnswers > oLgQuestion.iMax ) ) { return bIsValidQuestion; } else { bIsValidQuestion = true; } break; case 'text': var iFilledObjects = 0; for( pHtmlObjectPointer in oLgQuestion.aHtmlObjects) { if( '' !== this.trimString( oLgQuestion.aHtmlObjects[ pHtmlObjectPointer ].value ) ) { iFilledObjects++; } } // Fix for required housenumber and addition where housenumber is required but addition isnt. if( 16 === oLgQuestion.iDataNameId && ( oLgQuestion.aHtmlObjects[ 1 ] && '' === this.trimString( oLgQuestion.aHtmlObjects[ 1 ].value ) ) ) { iFilledObjects++; } // Fix for required zipcode where zipcode letters arent required (country = be). if( 17 === oLgQuestion.iDataNameId && ( oLgQuestion.aHtmlObjects[ 1 ] && '' === this.trimString( oLgQuestion.aHtmlObjects[ 1 ].value ) && 'be' === this.sCurrentCountry ) ) { iFilledObjects++; } if( iFilledObjects < oLgQuestion.aHtmlObjects.length ) { return bIsValidQuestion; } else { bIsValidQuestion = true; } break; } } } // Questions with extra html objects (checkboxes or radios) have an additional check: if the base object is checked, // the extra object has to have a value as well. for( pHtmlObjectPointer in oLgQuestion.aHtmlObjects ) { if( 'undefined' !== typeof( oLgQuestion.aExtraHtmlObjects[ pHtmlObjectPointer ] ) && null !== oLgQuestion.aExtraHtmlObjects[ pHtmlObjectPointer ] ) { if( oLgQuestion.aHtmlObjects[ pHtmlObjectPointer ].checked && '' === this.trimString( oLgQuestion.aExtraHtmlObjects[ pHtmlObjectPointer ].value ) ) { return bIsValidQuestion = false; } } } // Required or not, if this question has value(s), it'll be validated by the given validation function if( 'function' !== typeof( oLgQuestion.sValidationFunction ) ) { alert( oLgQuestion.iId ); } bIsValidQuestion = oLgQuestion.sValidationFunction( this, oLgQuestion ); return bIsValidQuestion; } LgValidator.prototype.isValidQuestionGroup = function( oLgQuestionGroup ) { switch( oLgQuestionGroup.sType ) { case 'full_address': // @todo we might want to extend this function return this.validateAddress( oLgQuestionGroup, false ); break; default: return true; break; } } LgValidator.prototype.trimString = function( sString ) { var oString = new String( sString ); return oString.replace(/^\s+|\s+$/g,""); } LgValidator.prototype.isValidValueByCharset = function( sValue, sCharset ) { var iValueLength = sValue.length; if( 0 === iValueLength ) { return false; } for( var p = 0; p < iValueLength; p++) { if( sCharset.indexOf( sValue.substr( p, 1 ) ) < 0 ) { return false; } } return true; } LgValidator.prototype.getValues = function( oLgQuestion ) { var sValue = new String(); for( pHtmObjectPointer in oLgQuestion.aHtmlObjects ) { sValue += oLgQuestion.aHtmlObjects[ pHtmObjectPointer ].value; } return sValue; } LgValidator.prototype.validateNumber = function( oValidator, oLgQuestion ) { if( '' !== oValidator.trimString( oLgQuestion.aHtmlObjects[ 0 ].value ) ) { // Number validation is required only for and textarea fields if( 5 === oLgQuestion.iInputTypeId || 1 === oLgQuestion.iInputTypeId ) { // Basicly, a number is invalid only if not empty, less than or more than the minimum or maximum value or if it consits of characters. if( '' !== oValidator.trimString( oLgQuestion.aHtmlObjects[ 0 ].value ) ) { if( 0 !== oLgQuestion.iMin || 0 !== oLgQuestion.iMax ) { if( true === oValidator.isValidValueByCharset( oLgQuestion.aHtmlObjects[ 0 ].value, '0123456789,.' ) ) { if( oLgQuestion.aHtmlObjects[ 0 ].value < oLgQuestion.iMin || oLgQuestion.aHtmlObjects[ 0 ].value > oLgQuestion.iMax ) { return false; } } } } } } return true; } LgValidator.prototype.validateCurrency = function( oValidator, oLgQuestion ) { // Until we have a proper currency validation, validate this by using this.validateNumber() return this.validateNumber( oLgQuestion ); } LgValidator.prototype.validateString = function( oValidator, oLgQuestion ) { if( '' !== oValidator.trimString( oLgQuestion.aHtmlObjects[ 0 ].value ) ) { // A string (text) is invalid only if shorter than the given minimum value or longer than the maximum value of the question. // This check goes for and