1var prevState // the last state of the application 2var reducer; 3document.addEventListener('DOMContentLoaded', function() { 4 /** 5 * The reducer 6 * 7 * @param {Object} state current state 8 * @param {type, ...any} action The action we are performing 9 * @return {Object} new state 10 */ 11 reducer = function reducer(state, action){ 12 prevState = state; 13 var newState = Object.assign({}, state); 14 newState.fields = Object.assign({}, newState.fields); 15 16 switch(action.type){ 17 case 'update' : 18 if(newState.fields[action.name]) { 19 newState.fields[action.name] = Object.assign( 20 {}, 21 newState.fields[action.name], 22 { 23 value: action.value, 24 serverErrors: false, 25 } 26 ); 27 } 28 else 29 console.warn('Trying to update field', action.name, 'that does not exist'); 30 break; 31 case 'validate': 32 newState = validateForm(clearAllErrors(newState)); 33 newState.canSubmitForm = checkIfFormReady(newState); 34 break; 35 case 'server-errors': 36 newState.fields[action.name] = Object.assign( 37 {}, 38 newState.fields[action.name], 39 { serverErrors: true } 40 ); 41 break; 42 case 'dirty': 43 newState.fields[action.name] = Object.assign( 44 {}, 45 newState.fields[action.name], 46 { dirty: true } 47 ); 48 break; 49 case 'dirty-all': 50 newState.formDirty = true; 51 break; 52 default: 53 break; 54 } 55 return newState; 56 } 57 58 /** 59 * Iterates through the state and finds all fields. Then it clears the errors 60 * in that state. 61 * 62 * @param {Object} state Current state 63 * @return {Object} Updated state 64 */ 65 function clearAllErrors(state){ 66 var keys = Object.keys(defaultState.fields); 67 keys.forEach(function(key) { 68 if(defaultState.fields[keys]) 69 state.fields[key].errors = defaultState.fields[key].errors; 70 }); 71 return state; 72 } 73 74 /** 75 * Iterate through the state and check all of the errors 76 * 77 * @param {Object} state Current state 78 * @return {Object} New State (with updated errors) 79 */ 80 function validateForm(state){ 81 var keys = Object.keys(state.fields); 82 keys.forEach(function(key){ 83 state.fields[key].errors = validateField(state, key); 84 85 if(state.fields[key].errors.length > 0 && !fieldHasErrors(state.fields[key])) { 86 state.fields[key].dirty = true; 87 } 88 }) 89 return state; 90 } 91 92 /** 93 * Runs validationFunc on a single field based on the errors that it is configured 94 * to look for 95 * 96 * @param {Object} state Current state 97 * @param {String} key The name of the field 98 * @return {Array} New value for errors 99 */ 100 function validateField(state, key) { 101 var fieldState = state.fields[key]; 102 var errors = fieldState.errors; 103 var field = d$('[data-name="' + key + '"]'); 104 var disabled = false; 105 if(field) 106 notDisabled = (field.getAttribute('data-disabled') !== 'true'); 107 errors.forEach(function(errorState, ndx){ 108 if(errorState.validationFunc !== '') { 109 errors[ndx].hasError = ( 110 notDisabled && 111 validators[errorState.validationFunc].apply(null, [fieldState.value].concat(errorState.args)) 112 ); 113 } 114 }); 115 return errors; 116 } 117 118 /** 119 * Given the state of the application, check to see if the form is ready to submit. 120 * It is ready to submit if there are no errors on the page. 121 * 122 * @param {Object} state The current state of the application 123 * @return {Bool} If the form is ready to submit, return true 124 */ 125 function checkIfFormReady(state) { 126 var formDirty = state.formDirty; 127 //get all fields we need to check 128 var fields = d$$('.js-form-element'); 129 var filteredFields = [].filter.call(fields, function(field) { 130 var name = field.getAttribute('data-name'); 131 return ( 132 state.fields[name] && 133 state.fields[name].errors.length > 0 && // has error fields 134 fieldIsVisible(field) 135 ); 136 }); 137 138 // if there are no fields to check, then we are good to go 139 if(filteredFields.length === 0) return true; 140 // We can submit if no fields have errors 141 var canSubmit = filteredFields.reduce(function(acc, field, ndx, arr) { 142 var name = field.getAttribute('data-name'); 143 var isDirty = formDirty || state.fields[name].dirty; 144 return (acc === false) ? acc : (isDirty && !fieldHasErrors(state.fields[name])); 145 }, true); 146 147 return canSubmit; 148 } 149 150 /** 151 * Checks to see if this field is visible 152 * 153 * @param {Node} field The field we are testing 154 * @return {Bool} True if the field is visible 155 */ 156 function fieldIsVisible(field) { 157 return (field.offsetParent !== null); 158 } 159 160 /** 161 * Given a field this function returns true if it has errors 162 * 163 * @param {Object} field A field (from state) 164 * @return {Bool} True if there are errors 165 */ 166 function fieldHasErrors(field) { 167 return field.errors.reduce(function(acc, error) { return acc ? acc : error.hasError }, false) 168 } 169 170 // These are functions used to validate particular error fields 171 // Each one is given the value of the field, and potentially a list of arguments 172 // 173 // These all return TRUE if there is an error FALSE if no error 174 //
175 var validators = { 176 // most pages 177 required : function(value){ 178 return (value === '' || value === null) ? true : false; 179 }, 180 email : function(value){ 181 if(value === ''){return false} 182 var regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 183 return (regex.test(value) ? false : true); 184 }, 185 } 186 187})
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.