1(function (global) { 2 'use strict'; 3 4 var RULES = { 5 name: { min: 2, max: 70 }, 6 subject: { min: 10, max: 100 }, 7 message: { min: 20, max: 1500 } 8 }; 9 10 var FIELD_LABELS = { 11 name: 'Name', 12 subject: 'Subject', 13 message: 'Message' 14 }; 15 16 var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 17 18 function getRule(fieldName, overrides) { 19 var baseRule = RULES[fieldName] || {}; 20 var overrideRule = overrides && overrides[fieldName] ? overrides[fieldName] : {}; 21 22 return { 23 min: typeof overrideRule.min === 'number' ? overrideRule.min : baseRule.min, 24 max: typeof overrideRule.max === 'number' ? overrideRule.max : baseRule.max 25 }; 26 } 27 28 function toText(value) { 29 if (value === null || value === undefined) { 30 return ''; 31 } 32 return String(value).trim(); 33 } 34 35 function inRange(value, min, max) { 36 var len = toText(value).length; 37 return len >= min && len <= max; 38 } 39 40 function validateName(value, ruleOverrides, required) { 41 var text = toText(value); 42 var rule = getRule('name', ruleOverrides); 43 44 if (required !== false && !text.length) { 45 return 'Please enter your name.'; 46 } 47 48 if (text.length && !inRange(text, rule.min, rule.max)) { 49 return 'Limit ' + rule.min + ' to ' + rule.max + ' characters.'; 50 } 51 return ''; 52 } 53 54 function validateEmail(value, required) { 55 var text = toText(value); 56 57 if (required !== false && !text.length) { 58 return 'Please enter your email.'; 59 } 60 61 if (text.length && !EMAIL_REGEX.test(text)) { 62 return 'Please enter a valid email address.'; 63 } 64 return ''; 65 } 66 67 function validateRequired(value, fieldLabel) { 68 var text = toText(value); 69 if (!text.length) { 70 return 'Please enter your ' + fieldLabel + '.'; 71 } 72 return ''; 73 } 74 75 function validateSubject(value, required, ruleOverrides) { 76 var text = toText(value); 77 var rule = getRule('subject', ruleOverrides); 78 79 if (!required && text.length === 0) { 80 return ''; 81 } 82 83 if (required && !text.length) { 84 return 'Please enter your subject.'; 85 } 86 87 if (text.length && !inRange(text, rule.min, rule.max)) { 88 return 'Limit ' + rule.min + ' to ' + rule.max + ' characters.'; 89 } 90 return ''; 91 } 92 93 function validateMessage(value, ruleOverrides, required) { 94 var text = toText(value); 95 var rule = getRule('message', ruleOverrides); 96 97 if (required !== false && !text.length) { 98 return 'Please enter your message.'; 99 } 100 101 if (text.length && !inRange(text, rule.min, rule.max)) { 102 return 'Limit ' + rule.min + ' to ' + rule.max + ' characters.'; 103 } 104 return ''; 105 } 106 107 function getLimitMessage(fieldName, value, ruleOverrides) { 108 var fieldRule = getRule(fieldName, ruleOverrides); 109 var fieldLabel = FIELD_LABELS[fieldName]; 110 var text = toText(value); 111 112 if (!fieldRule || !fieldRule.max || !fieldLabel) { 113 return ''; 114 } 115 116 if (text.length >= fieldRule.max) { 117 return fieldLabel + ' character limit reached (' + fieldRule.max + ').'; 118 } 119 120 return ''; 121 } 122 123 function validateForm(values, options) { 124 var opts = options || {}; 125 var subjectRequired = !!opts.subjectRequired; 126 var nameRequired = opts.nameRequired !== false; 127 var emailRequired = opts.emailRequired !== false; 128 var messageRequired = opts.messageRequired !== false; 129 var ruleOverrides = opts.ruleOverrides || {}; 130 131 var errors = { 132 name: validateName(values && values.name, ruleOverrides, nameRequired), 133 email: validateEmail(values && values.email, emailRequired), 134 subject: validateSubject(values && values.subject, subjectRequired, ruleOverrides), 135 message: validateMessage(values && values.message, ruleOverrides, messageRequired) 136 }; 137 138 var isValid = !errors.name && !errors.email && !errors.subject && !errors.message; 139 140 return { 141 isValid: isValid, 142 errors: errors, 143 rules: { 144 name: getRule('name', ruleOverrides), 145 subject: getRule('subject', ruleOverrides), 146 message: getRule('message', ruleOverrides) 147 } 148 }; 149 } 150 151 function autoResizeTextarea(element) { 152 if (!element) return; 153 154 element.style.minHeight = '70px'; 155 element.style.height = 'auto'; 156 element.style.height = Math.max(element.scrollHeight, 70) + 'px'; 157 } 158 159 function initTextareaAutoResize(selector) { 160 var textareas = document.querySelectorAll(selector); 161 162 textareas.forEach(function(textarea) { 163 textarea.style.minHeight = '70px'; 164 textarea.style.overflowY = 'hidden'; 165 textarea.style.resize = 'none'; 166 167 // Auto-resize on input 168 textarea.addEventListener('input', function() { 169 autoResizeTextarea(this); 170 }); 171 172 // Initial resize 173 autoResizeTextarea(textarea); 174 }); 175 } 176 177 function toJQueryElement(target) { 178 if (!global.jQuery) { 179 return null; 180 } 181 182 if (target && target.jquery) { 183 return target; 184 } 185 186 if (target && target.nodeType) { 187 return global.jQuery(target); 188 } 189 190 return global.jQuery(target); 191 } 192 193 function ensureErrorElement(fieldSelector, errSelector) { 194 var $field = toJQueryElement(fieldSelector); 195 var $error = toJQueryElement(errSelector); 196 197 if ($error && $error.length) { 198 return $error; 199 } 200 201 $error = global.jQuery('<div class="field-error-message" style="display:none;color:red;font-size:14px;margin-top:4px;"></div>'); 202 203 if (typeof errSelector === 'string' && errSelector.charAt(0) === '#') { 204 $error.attr('id', errSelector.substring(1)); 205 } else if (typeof errSelector === 'string' && errSelector.charAt(0) === '.') { 206 $error.addClass(errSelector.substring(1)); 207 } 208 209 var $wrapper = $field && $field.length ? $field.closest('.iti') : null; 210 if ($wrapper && $wrapper.length) { 211 $wrapper.after($error); 212 } else if ($field && $field.length) { 213 $field.after($error); 214 } 215 216 return $error; 217 } 218 219 function setFieldError(fieldSelector, errSelector, message) { 220 if (!global.jQuery) { 221 return; 222 } 223 224 var $field = toJQueryElement(fieldSelector); 225 var $error = ensureErrorElement(fieldSelector, errSelector); 226 var $wrapper = $field && $field.length ? $field.closest('.iti') : global.jQuery(); 227 228 if (message) { 229 $field.addClass('field-error'); 230 $wrapper.addClass('field-error-wrapper'); 231 $error.html(message).show(); 232 } else { 233 $field.removeClass('field-error'); 234 $wrapper.removeClass('field-error-wrapper'); 235 $error.html('').hide(); 236 } 237 } 238 239 function focusField(fieldSelector) { 240 var element = null; 241 242 if (global.jQuery) { 243 var $target = toJQueryElement(fieldSelector); 244 element = $target && $target.length ? $target.get(0) : null; 245 } 246 247 if (!element && global.document) { 248 element = global.document.querySelector(fieldSelector); 249 } 250 251 if (!element) { 252 return; 253 } 254 255 if (typeof element.scrollIntoView === 'function') { 256 element.scrollIntoView({ behavior: 'smooth', block: 'center' }); 257 } 258 259 if (typeof element.focus === 'function') { 260 element.focus(); 261 } 262 263 if (typeof element.setSelectionRange === 'function' && typeof element.value === 'string') { 264 var cursorPosition = element.value.length; 265 element.setSelectionRange(cursorPosition, cursorPosition); 266 } 267 } 268 269 function focusFirstInvalidField(fieldOrder, errors) { 270 if (!fieldOrder || !errors) { 271 return; 272 } 273 274 fieldOrder.some(function(fieldConfig) { 275 if (!fieldConfig || !errors[fieldConfig.key]) { 276 return false;
277 } 278 279 focusField(fieldConfig.selector); 280 return true; 281 }); 282 } 283 284 function bindFieldClearOnInput(fieldErrorMap) { 285 if (!global.jQuery || !fieldErrorMap) { 286 return; 287 } 288 289 Object.keys(fieldErrorMap).forEach(function(fieldSelector) { 290 var errSelector = fieldErrorMap[fieldSelector]; 291 global.jQuery(fieldSelector).on('input', function() { 292 setFieldError(fieldSelector, errSelector, ''); 293 }); 294 }); 295 } 296 297 global.CommonFormValidation = { 298 rules: RULES, 299 validateName: validateName, 300 validateEmail: validateEmail, 301 validateRequired: validateRequired, 302 validateSubject: validateSubject, 303 validateMessage: validateMessage, 304 getLimitMessage: getLimitMessage, 305 validateForm: validateForm, 306 autoResizeTextarea: autoResizeTextarea, 307 initTextareaAutoResize: initTextareaAutoResize, 308 setFieldError: setFieldError, 309 focusField: focusField, 310 focusFirstInvalidField: focusFirstInvalidField, 311 bindFieldClearOnInput: bindFieldClearOnInput 312 }; 313})(window);
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.