PageSourceSearch

https://www.iidh.ed.cr/media/system/js/fields/validate.js?75ac5d

js iidh.ed.cr collected 2026-09-24 09:35:06 UTC 23,480 bytes, 714 lines download raw bytes

vendor: 6,042 bytes, lines 1-189
1/** Highest positive signed 32-bit float value */
2const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
3
4/** Bootstring parameters */
5const base = 36;
6const tMin = 1;
7const tMax = 26;
8const skew = 38;
9const damp = 700;
10const initialBias = 72;
11const initialN = 128; // 0x80
12const delimiter = '-'; // '\x2D'
13
14/** Regular expressions */
15const regexPunycode = /^xn--/;
16const regexNonASCII = /[^\0-\x7F]/; // Note: U+007F DEL is excluded too.
17const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
18
19/** Error messages */
20const errors = {
21  'overflow': 'Overflow: input needs wider integers to process',
22  'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
23  'invalid-input': 'Invalid input'
24};
25
26/** Convenience shortcuts */
27const baseMinusTMin = base - tMin;
28const floor = Math.floor;
29const stringFromCharCode = String.fromCharCode;
30
31/*--------------------------------------------------------------------------*/
32
33/**
34 * A generic error utility function.
35 * @private
36 * @param {String} type The error type.
37 * @returns {Error} Throws a `RangeError` with the applicable error message.
38 */
39function error(type) {
40  throw new RangeError(errors[type]);
41}
42
43/**
44 * A generic `Array#map` utility function.
45 * @private
46 * @param {Array} array The array to iterate over.
47 * @param {Function} callback The function that gets called for every array
48 * item.
49 * @returns {Array} A new array of values returned by the callback function.
50 */
51function map(array, callback) {
52  const result = [];
53  let length = array.length;
54  while (length--) {
55    result[length] = callback(array[length]);
56  }
57  return result;
58}
59
60/**
61 * A simple `Array#map`-like wrapper to work with domain name strings or email
62 * addresses.
63 * @private
64 * @param {String} domain The domain name or email address.
65 * @param {Function} callback The function that gets called for every
66 * character.
67 * @returns {String} A new string of characters returned by the callback
68 * function.
69 */
70function mapDomain(domain, callback) {
71  const parts = domain.split('@');
72  let result = '';
73  if (parts.length > 1) {
74    // In email addresses, only the domain name should be punycoded. Leave
75    // the local part (i.e. everything up to `@`) intact.
76    result = parts[0] + '@';
77    domain = parts[1];
78  }
79  // Avoid `split(regex)` for IE8 compatibility. See #17.
80  domain = domain.replace(regexSeparators, '\x2E');
81  const labels = domain.split('.');
82  const encoded = map(labels, callback).join('.');
83  return result + encoded;
84}
85
86/**
87 * Creates an array containing the numeric code points of each Unicode
88 * character in the string. While JavaScript uses UCS-2 internally,
89 * this function will convert a pair of surrogate halves (each of which
90 * UCS-2 exposes as separate characters) into a single code point,
91 * matching UTF-16.
92 * @see `punycode.ucs2.encode`
93 * @see <https://mathiasbynens.be/notes/javascript-encoding>
94 * @memberOf punycode.ucs2
95 * @name decode
96 * @param {String} string The Unicode input string (UCS-2).
97 * @returns {Array} The new array of code points.
98 */
99function ucs2decode(string) {
100  const output = [];
101  let counter = 0;
102  const length = string.length;
103  while (counter < length) {
104    const value = string.charCodeAt(counter++);
105    if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
106      // It's a high surrogate, and there is a next character.
107      const extra = string.charCodeAt(counter++);
108      if ((extra & 0xFC00) == 0xDC00) {
109        // Low surrogate.
110        output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
111      } else {
112        // It's an unmatched surrogate; only append this code unit, in case the
113        // next code unit is the high surrogate of a surrogate pair.
114        output.push(value);
115        counter--;
116      }
117    } else {
118      output.push(value);
119    }
120  }
121  return output;
122}
123
124/**
125 * Creates a string based on an array of numeric code points.
126 * @see `punycode.ucs2.decode`
127 * @memberOf punycode.ucs2
128 * @name encode
129 * @param {Array} codePoints The array of numeric code points.
130 * @returns {String} The new Unicode string (UCS-2).
131 */
132const ucs2encode = codePoints => String.fromCodePoint(...codePoints);
133
134/**
135 * Converts a basic code point into a digit/integer.
136 * @see `digitToBasic()`
137 * @private
138 * @param {Number} codePoint The basic numeric code point value.
139 * @returns {Number} The numeric value of a basic code point (for use in
140 * representing integers) in the range `0` to `base - 1`, or `base` if
141 * the code point does not represent a value.
142 */
143const basicToDigit = function basicToDigit(codePoint) {
144  if (codePoint >= 0x30 && codePoint < 0x3A) {
145    return 26 + (codePoint - 0x30);
146  }
147  if (codePoint >= 0x41 && codePoint < 0x5B) {
148    return codePoint - 0x41;
149  }
150  if (codePoint >= 0x61 && codePoint < 0x7B) {
151    return codePoint - 0x61;
152  }
153  return base;
154};
155
156/**
157 * Converts a digit/integer into a basic code point.
158 * @see `basicToDigit()`
159 * @private
160 * @param {Number} digit The numeric value of a basic code point.
161 * @returns {Number} The basic code point whose value (when used for
162 * representing integers) is `digit`, which needs to be in the range
163 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
164 * used; else, the lowercase form is used. The behavior is undefined
165 * if `flag` is non-zero and `digit` has no uppercase form.
166 */
167const digitToBasic = function digitToBasic(digit, flag) {
168  //  0..25 map to ASCII a..z or A..Z
169  // 26..35 map to ASCII 0..9
170  return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
171};
172
173/**
174 * Bias adaptation function as per section 3.4 of RFC 3492.
175 * https://tools.ietf.org/html/rfc3492#section-3.4
176 * @private
177 */
178const adapt = function adapt(delta, numPoints, firstTime) {
179  let k = 0;
180  delta = firstTime ? floor(delta / damp) : delta >> 1;
181  delta += floor(delta / numPoints);
182  for /* no initialization */
183  (; delta > baseMinusTMin * tMax >> 1; k += base) {
184    delta = floor(delta / baseMinusTMin);
185  }
186  return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
187};
188
189/**
190 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
191 * symbols.
192 * @memberOf punycode
193 * @param {String} input The Punycode string of ASCII-only symbols.
194 * @returns {String} The resulting string of Unicode symbols.
195 */
196const decode = function decode(input) {
197  // Don't use UCS-2.
198  const output = [];
199  const inputLength = input.length;
200  let i = 0;
201  let n = initialN;
202  let bias = initialBias;
203
204  // Handle the basic code points: let `basic` be the number of input code
205  // points before the last delimiter, or `0` if there is none, then copy
206  // the first basic code points to the output.
207
208  let basic = input.lastIndexOf(delimiter);
209  if (basic < 0) {
210    basic = 0;
211  }
212  for (let j = 0; j < basic; ++j) {
213    // if it's not a basic code point
214    if (input.charCodeAt(j) >= 0x80) {
215      error('not-basic');
216    }
217    output.push(input.charCodeAt(j));
218  }
219
220  // Main decoding loop: start just after the last delimiter if any basic code
221  // points were copied; start at the beginning otherwise.
222
223  for /* no final expression */
224  (let index = basic > 0 ? basic + 1 : 0; index < inputLength;) {
225    // `index` is the index of the next character to be consumed.
226    // Decode a generalized variable-length integer into `delta`,
227    // which gets added to `i`. The overflow checking is easier
228    // if we increase `i` as we go, then subtract off its starting
229    // value at the end to obtain `delta`.
230    const oldi = i;
231    for /* no condition */
232    (let w = 1, k = base;; k += base) {
233      if (index >= inputLength) {
234        error('invalid-input');
235      }
236      const digit = basicToDigit(input.charCodeAt(index++));
237      if (digit >= base) {
238        error('invalid-input');
239      }
240      if (digit > floor((maxInt - i) / w)) {
241        error('overflow');
242      }
243      i += digit * w;
244      const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
245      if (digit < t) {
246        break;
247      }
248      const baseMinusT = base - t;
249      if (w > floor(maxInt / baseMinusT)) {
250        error('overflow');
251      }
252      w *= baseMinusT;
253    }
254    const out = output.length + 1;
255    bias = adapt(i - oldi, out, oldi == 0);
256
257    // `i` was supposed to wrap around from `out` to `0`,
258    // incrementing `n` each time, so we'll fix that now:
259    if (floor(i / out) > maxInt - n) {
260      error('overflow');
261    }
262    n += floor(i / out);
263    i %= out;
264
265    // Insert `n` at position `i` of the output.
266    output.splice(i++, 0, n);
267  }
268  return String.fromCodePoint(...output);
269};
270
271/**
272 * Converts a string of Unicode symbols (e.g. a domain name label) to a
273 * Punycode string of ASCII-only symbols.
274 * @memberOf punycode
275 * @param {String} input The string of Unicode symbols.
276 * @returns {String} The resulting Punycode string of ASCII-only symbols.
277 */
278const encode = function encode(input) {
279  const output = [];
280
281  // Convert the input in UCS-2 to an array of Unicode code points.
282  input = ucs2decode(input);
283
284  // Cache the length.
285  const inputLength = input.length;
286
287  // Initialize the state.
288  let n = initialN;
289  let delta = 0;
290  let bias = initialBias;
291
292  // Handle the basic code points.
293  for (const currentValue of input) {
294    if (currentValue < 0x80) {
295      output.push(stringFromCharCode(currentValue));
296    }
297  }
298  const basicLength = output.length;
299  let handledCPCount = basicLength;
300
301  // `handledCPCount` is the number of code points that have been handled;
302  // `basicLength` is the number of basic code points.
303
304  // Finish the basic string with a delimiter unless it's empty.
305  if (basicLength) {
306    output.push(delimiter);
307  }
308
309  // Main encoding loop:
310  while (handledCPCount < inputLength) {
311    // All non-basic code points < n have been handled already. Find the next
312    // larger one:
313    let m = maxInt;
314    for (const currentValue of input) {
315      if (currentValue >= n && currentValue < m) {
316        m = currentValue;
317      }
318    }
319
320    // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
321    // but guard against overflow.
322    const handledCPCountPlusOne = handledCPCount + 1;
323    if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
324      error('overflow');
325    }
326    delta += (m - n) * handledCPCountPlusOne;
327    n = m;
328    for (const currentValue of input) {
329      if (currentValue < n && ++delta > maxInt) {
330        error('overflow');
331      }
332      if (currentValue === n) {
333        // Represent delta as a generalized variable-length integer.
334        let q = delta;
335        for /* no condition */
336        (let k = base;; k += base) {
337          const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
338          if (q < t) {
339            break;
340          }
341          const qMinusT = q - t;
342          const baseMinusT = base - t;
343          output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)));
344          q = floor(qMinusT / baseMinusT);
345        }
346        output.push(stringFromCharCode(digitToBasic(q, 0)));
347        bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);
348        delta = 0;
349        ++handledCPCount;
350      }
351    }
352    ++delta;
353    ++n;
354  }
355  return output.join('');
356};
357
358/**
359 * Converts a Punycode string representing a domain name or an email address
360 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
361 * it doesn't matter if you call it on a string that has already been
362 * converted to Unicode.
363 * @memberOf punycode
364 * @param {String} input The Punycoded domain name or email address to
365 * convert to Unicode.
366 * @returns {String} The Unicode representation of the given Punycode
367 * string.
368 */
369const toUnicode = function toUnicode(input) {
370  return mapDomain(input, function (string) {
371    return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
372  });
373};
374
375/**
376 * Converts a Unicode string representing a domain name or an email address to
377 * Punycode. Only the non-ASCII parts of the domain name will be converted,
378 * i.e. it doesn't matter if you call it with a domain that's already in
379 * ASCII.
380 * @memberOf punycode
381 * @param {String} input The domain name or email address to convert, as a
382 * Unicode string.
383 * @returns {String} The Punycode representation of the given domain name or
384 * email address.
385 */
386const toASCII = function toASCII(input) {
387  return mapDomain(input, function (string) {
388    return regexNonASCII.test(string) ? 'xn--' + encode(string) : string;
389  });
390};
391
392/*--------------------------------------------------------------------------*/
393
394/** Define the public API */
395const punycode = {
396  /**
397   * A string representing the current Punycode.js version number.
398   * @memberOf punycode
399   * @type String
400   */
401  'version': '2.3.1',
402  /**
403   * An object of methods to convert from JavaScript's internal character
404   * representation (UCS-2) to Unicode code points, and back.
405   * @see <https://mathiasbynens.be/notes/javascript-encoding>
406   * @memberOf punycode
407   * @type Object
408   */
409  'ucs2': {
410    'decode': ucs2decode,
411    'encode': ucs2encode
412  },
413  'decode': decode,
414  'encode': encode,
415  'toASCII': toASCII,
416  'toUnicode': toUnicode
417};
418
419/**
420 * @copyright  (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
421 * @license    GNU General Public License version 2 or later; see LICENSE.txt
422 */
423class JFormValidator {
424  constructor() {
425    this.customValidators = {};
426    this.handlers = [];
427    this.handlers = {};
428    this.removeMarking = this.removeMarking.bind(this);
429    this.inputEmail = () => {
430      const input = document.createElement('input');
431      input.setAttribute('type', 'email');
432      return input.type !== 'text';
433    };
434
435    // Default handlers
436    this.setHandler('username', value => {
437      const regex = /[<|>|"|'|%|;|(|)|&]/i;
438      return !regex.test(value);
439    });
440    this.setHandler('password', value => {
441      const regex = /^\S[\S ]{2,98}\S$/;
442      return regex.test(value);
443    });
444    this.setHandler('numeric', value => {
445      const regex = /^(\d|-)?(\d|,)*\.?\d*$/;
446      return regex.test(value);
447    });
448    this.setHandler('email', value => {
449      const newValue = punycode.toASCII(value);
450      const regex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
451      return regex.test(newValue);
452    });
453
454    // Attach all forms with a class 'form-validate'
455    document.querySelectorAll('form').forEach(form => {
456      if (form.classList.contains('form-validate')) {
457        this.attachToForm(form);
458      }
459    });
460  }
461  get custom() {
462    return this.customValidators;
463  }
464  set custom(value) {
465    this.customValidators = value;
466  }
467  setHandler(name, func, en) {
468    const isEnabled = en === '' ? true : en;
469    this.handlers[name] = {
470      enabled: isEnabled,
471      exec: func
472    };
473  }
474  markValid(element) {
475    // Get a label
476    const label = element.form.querySelector(`label[for="${element.id}"]`);
477    let message;
478    if (element.classList.contains('required') || element.getAttribute('required')) {
479      if (label) {
480        message = label.querySelector('span.form-control-feedback');
481      }
482    }
483    element.classList.remove('form-control-danger', 'invalid');
484    element.classList.add('form-control-success');
485    element.parentNode.classList.remove('has-danger');
486    element.parentNode.classList.add('has-success');
487    element.setAttribute('aria-invalid', 'false');
488
489    // Remove message
490    if (message) {
491      message.parentNode.removeChild(message);
492    }
493
494    // Restore Label
495    if (label) {
496      label.classList.remove('invalid');
497    }
498  }
499  markInvalid(element, empty) {
500    // Get a label
501    const label = element.form.querySelector(`label[for="${element.id}"]`);
502    element.classList.remove('form-control-success', 'valid');
503    element.classList.add('form-control-danger', 'invalid');
504    element.parentNode.classList.remove('has-success');
505    element.parentNode.classList.add('has-danger');
506    element.setAttribute('aria-invalid', 'true');
507
508    // Display custom message
509    let mesgCont;
510    const message = element.getAttribute('data-validation-text');
511    if (label) {
512      mesgCont = label.querySelector('span.form-control-feedback');
513    }
514    if (!mesgCont) {
515      const elMsg = document.createElement('span');
516      elMsg.classList.add('form-control-feedback');
517      if (empty && empty === 'checkbox') {
518        elMsg.innerHTML = message !== null ? Joomla.sanitizeHtml(message) : Joomla.sanitizeHtml(Joomla.Text._('JLIB_FORM_FIELD_REQUIRED_CHECK'));
519      } else if (empty && empty === 'value') {
520        elMsg.innerHTML = message !== null ? Joomla.sanitizeHtml(message) : Joomla.sanitizeHtml(Joomla.Text._('JLIB_FORM_FIELD_REQUIRED_VALUE'));
521      } else {
522        elMsg.innerHTML = message !== null ? Joomla.sanitizeHtml(message) : Joomla.sanitizeHtml(Joomla.Text._('JLIB_FORM_FIELD_INVALID_VALUE'));
523      }
524      if (label) {
525        label.appendChild(elMsg);
526      }
527    }
528
529    // Mark the Label as well
530    if (label) {
531      label.classList.add('invalid');
532    }
533  }
534  removeMarking(element) {
535    // Get the associated label
536    let message;
537    const label = element.form.querySelector(`label[for="${element.i
537d}"]`);
538    if (label) {
539      message = label.querySelector('span.form-control-feedback');
540    }
541    element.classList.remove('form-control-danger', 'form-control-success', 'remove');
542    element.classList.add('valid');
543    element.parentNode.classList.remove('has-danger', 'has-success');
544
545    // Remove message
546    if (message && label) {
547      label.removeChild(message);
548    }
549
550    // Restore Label
551    if (label) {
552      label.classList.remove('invalid');
553    }
554  }
555  handleResponse(state, element, empty) {
556    const tagName = element.tagName.toLowerCase();
557
558    // Set the element and its label (if exists) invalid state
559    if (tagName !== 'button' && element.value !== undefined || tagName === 'fieldset') {
560      if (state === false) {
561        this.markInvalid(element, empty);
562      } else {
563        this.markValid(element);
564      }
565    }
566  }
567  validate(element) {
568    let tagName;
569
570    // Ignore the element if its currently disabled,
571    // because are not submitted for the http-request.
572    // For those case return always true.
573    if (element.getAttribute('disabled') === 'disabled' || element.getAttribute('display') === 'none') {
574      this.handleResponse(true, element);
575      return true;
576    }
577    // If the field is required make sure it has a value
578    if (element.getAttribute('required') || element.classList.contains('required')) {
579      tagName = element.tagName.toLowerCase();
580      if (tagName === 'fieldset' && (element.classList.contains('radio') || element.classList.contains('checkboxes'))) {
581        // No options are checked.
582        if (element.querySelector('input:checked') === null) {
583          this.handleResponse(false, element, 'checkbox');
584          return false;
585        }
586      } else if (element.getAttribute('type') === 'checkbox' && element.checked !== true || tagName === 'select' && !element.value.length) {
587        this.handleResponse(false, element, 'checkbox');
588        return false;
589      } else if (!element.value || element.classList.contains('placeholder')) {
590        // If element has class placeholder that means it is empty.
591        this.handleResponse(false, element, 'value');
592        return false;
593      }
594    }
595
596    // Only validate the field if the validate class is set
597    const handler = element.getAttribute('class') && element.getAttribute('class').match(/validate-([a-zA-Z0-9_-]+)/) ? element.getAttribute('class').match(/validate-([a-zA-Z0-9_-]+)/)[1] : '';
598    if (element.getAttribute('pattern') && element.getAttribute('pattern') !== '') {
599      if (element.value.length) {
600        const isValid = new RegExp(`^${element.getAttribute('pattern')}$`).test(element.value);
601        this.handleResponse(isValid, element, 'empty');
602        return isValid;
603      }
604      if (element.hasAttribute('required') || element.classList.contains('required')) {
605        this.handleResponse(false, element, 'empty');
606        return false;
607      }
608      this.handleResponse(true, element);
609      return true;
610    }
611    if (handler === '') {
612      this.handleResponse(true, element);
613      return true;
614    }
615
616    // Check the additional validation types
617    if (handler && handler !== 'none' && this.handlers[handler] && element.value) {
618      // Execute the validation handler and return result
619      if (this.handlers[handler].exec(element.value, element) !== true) {
620        this.handleResponse(false, element, 'invalid_value');
621        return false;
622      }
623    }
624
625    // Return validation state
626    this.handleResponse(true, element);
627    return true;
628  }
629  isValid(form) {
630    let valid = true;
631    let message;
632    let error;
633    let fields;
634    const invalid = [];
635
636    // Validate form fields
637    if (form.nodeName === 'FORM') {
638      fields = [].slice.call(form.elements);
639    } else {
640      fields = form.querySelectorAll('input, textarea, select, button, fieldset');
641    }
642    fields.forEach(field => {
643      if (this.validate(field) === false) {
644        valid = false;
645        invalid.push(field);
646      }
647    });
648
649    // Run custom form validators if present
650    if (Object.keys(this.customValidators).length) {
651      Object.keys(this.customValidators).forEach(key => {
652        if (this.customValidators[key].exec() !== true) {
653          valid = false;
654        }
655      });
656    }
657    if (!valid && invalid.length > 0) {
658      if (form.getAttribute('data-validation-text')) {
659        message = form.getAttribute('data-validation-text');
660      } else {
661        message = Joomla.Text._('JLIB_FORM_CONTAINS_INVALID_FIELDS');
662      }
663      error = {
664        error: [message]
665      };
666      Joomla.renderMessages(error);
667    }
668    return valid;
669  }
670  attachToForm(form) {
671    let elements;
672    if (form.nodeName === 'FORM') {
673      elements = [].slice.call(form.elements);
674    } else {
675      elements = form.querySelectorAll('input, textarea, select, button, fieldset');
676    }
677
678    // Iterate through the form object and attach the validate method to all input fields.
679    elements.forEach(element => {
680      const tagName = element.tagName.toLowerCase();
681      if (['input', 'textarea', 'select', 'fieldset'].indexOf(tagName) > -1 && element.classList.contains('required')) {
682        element.setAttribute('required', '');
683      }
684
685      // Attach isValid method to submit button
686      if ((tagName === 'input' || tagName === 'button') && (element.getAttribute('type') === 'submit' || element.getAttribute('type') === 'image')) {
687        if (element.classList.contains('validate')) {
688          element.addEventListener('click', () => this.isValid(form));
689        }
690      } else if (tagName !== 'button' && !(tagName === 'input' && element.getAttribute('type') === 'button')) {
691        // Attach validate method only to fields
692        if (tagName !== 'fieldset') {
693          element.addEventListener('blur', ({
694            target
695          }) => this.validate(target));
696          element.addEventListener('focus', ({
697            target
698          }) => this.removeMarking(target));
699          if (element.classList.contains('validate-email') && this.inputEmail) {
700            element.setAttribute('type', 'email');
701          }
702        }
703      }
704    });
705  }
706}
707document.formvalidator = new JFormValidator();
708
709/**
710 * Expose the classes to the global scope
711 * These will be removed in Joomla! 6.0
712 */
713window.JFormValidator = JFormValidator;
714window.punycode = punycode;

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.