PageSourceSearch

https://egypt-eta.com/js/common-form-validation.js

js egypt-eta.com collected 2026-09-26 03:59:33 UTC 6,629 bytes, 249 lines download raw bytes

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) {
41    var text = toText(value);
42    var rule = getRule('name', ruleOverrides);
43
44    if (!inRange(text, rule.min, rule.max)) {
45      return 'Name: ' + rule.min + ' and ' + rule.max + ' characters.';
46    }
47    return '';
48  }
49
50  function validateEmail(value) {
51    var text = toText(value);
52    if (!EMAIL_REGEX.test(text)) {
53      return 'Please enter a valid email address.';
54    }
55    return '';
56  }
57
58  function validateSubject(value, required, ruleOverrides) {
59    var text = toText(value);
60    var rule = getRule('subject', ruleOverrides);
61
62    if (!required && text.length === 0) {
63      return '';
64    }
65    if (!inRange(text, rule.min, rule.max)) {
66      return 'Subject: ' + rule.min + ' and ' + rule.max + ' characters.';
67    }
68    return '';
69  }
70
71  function validateMessage(value, ruleOverrides) {
72    var text = toText(value);
73    var rule = getRule('message', ruleOverrides);
74
75    if (!inRange(text, rule.min, rule.max)) {
76      return 'Message: ' + rule.min + ' and ' + rule.max + ' characters.';
77    }
78    return '';
79  }
80
81  function getLimitMessage(fieldName, value, ruleOverrides) {
82    var fieldRule = getRule(fieldName, ruleOverrides);
83    var fieldLabel = FIELD_LABELS[fieldName];
84    var text = toText(value);
85
86    if (!fieldRule || !fieldRule.max || !fieldLabel) {
87      return '';
88    }
89
90    if (text.length >= fieldRule.max) {
91      return fieldLabel + ' character limit reached (' + fieldRule.max + ').';
92    }
93
94    return '';
95  }
96
97  function validateForm(values, options) {
98    var opts = options || {};
99    var subjectRequired = !!opts.subjectRequired;
100    var ruleOverrides = opts.ruleOverrides || {};
101
102    var errors = {
103      name: validateName(values && values.name, ruleOverrides),
104      email: validateEmail(values && values.email),
105      subject: validateSubject(values && values.subject, subjectRequired, ruleOverrides),
106      message: validateMessage(values && values.message, ruleOverrides)
107    };
108
109    var isValid = !errors.name && !errors.email && !errors.subject && !errors.message;
110
111    return {
112      isValid: isValid,
113      errors: errors,
114      rules: {
115        name: getRule('name', ruleOverrides),
116        subject: getRule('subject', ruleOverrides),
117        message: getRule('message', ruleOverrides)
118      }
119    };
120  }
121
122  function getElement(selectorOrElement) {
123    if (!selectorOrElement) {
124      return null;
125    }
126
127    if (typeof selectorOrElement === 'string') {
128      return document.querySelector(selectorOrElement);
129    }
130
131    return selectorOrElement;
132  }
133
134  function setFieldError(fieldSelector, errorSelector, message) {
135    var field = getElement(fieldSelector);
136    var error = getElement(errorSelector);
137
138    if (field) {
139      field.classList.add('field-error');
140    }
141
142    if (error) {
143      error.textContent = message || '';
144      error.style.display = message ? 'block' : 'none';
145    }
146  }
147
148  function clearFieldError(fieldSelector, errorSelector) {
149    var field = getElement(fieldSelector);
150    var error = getElement(errorSelector);
151
152    if (field) {
153      field.classList.remove('field-error');
154    }
155
156    if (error) {
157      error.textContent = '';
158      error.style.display = 'none';
159    }
160  }
161
162  function clearErrors(fieldMap) {
163    Object.keys(fieldMap || {}
163).forEach(function (key) {
164      clearFieldError(fieldMap[key].field, fieldMap[key].error);
165    });
166  }
167
168  function hasErrors(errors) {
169    return Object.keys(errors || {}).some(function (key) {
170      return !!errors[key];
171    });
172  }
173
174  function focusFirstInvalidField(fieldOrder, fieldMap, errors) {
175    var order = fieldOrder || [];
176
177    for (var index = 0; index < order.length; index += 1) {
178      var key = order[index];
179      if (errors && errors[key]) {
180        var field = fieldMap && fieldMap[key] ? getElement(fieldMap[key].field) : null;
181        if (field && typeof field.focus === 'function') {
182          field.focus();
183        }
184        return;
185      }
186    }
187  }
188
189  function bindFieldClearOnInput(fieldMap) {
190    Object.keys(fieldMap || {}).forEach(function (key) {
191      var config = fieldMap[key];
192      var field = getElement(config.field);
193
194      if (!field) {
195        return;
196      }
197
198      ['input', 'change', 'keydown'].forEach(function (eventName) {
199        field.addEventListener(eventName, function () {
200          clearFieldError(config.field, config.error);
201        });
202      });
203    });
204  }
205
206  function autoResizeTextarea(element) {
207    if (!element) return;
208    
209    element.style.minHeight = '70px';
210    element.style.height = 'auto';
211    element.style.height = Math.max(element.scrollHeight, 70) + 'px';
212  }
213
214  function initTextareaAutoResize(selector) {
215    var textareas = document.querySelectorAll(selector);
216    
217    textareas.forEach(function(textarea) {
218      textarea.style.minHeight = '70px';
219      textarea.style.overflowY = 'hidden';
220      textarea.style.resize = 'none';
221      
222      // Auto-resize on input
223      textarea.addEventListener('input', function() {
224        autoResizeTextarea(this);
225      });
226      
227      // Initial resize
228      autoResizeTextarea(textarea);
229    });
230  }
231
232  global.CommonFormValidation = {
233    rules: RULES,
234    validateName: validateName,
235    validateEmail: validateEmail,
236    validateSubject: validateSubject,
237    validateMessage: validateMessage,
238    getLimitMessage: getLimitMessage,
239    validateForm: validateForm,
240    setFieldError: setFieldError,
241    clearFieldError: clearFieldError,
242    clearErrors: clearErrors,
243    hasErrors: hasErrors,
244    focusFirstInvalidField: focusFirstInvalidField,
245    bindFieldClearOnInput: bindFieldClearOnInput,
246    autoResizeTextarea: autoResizeTextarea,
247    initTextareaAutoResize: initTextareaAutoResize
248  };
249})(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.