/** * FormValidation (https://formvalidation.io) * The best validation library for JavaScript * (c) 2013 - 2020 Nguyen Huu Phuoc */ import { Localization, ValidateInput, ValidateOptions, ValidateResult } from '../core/Core'; import format from '../utils/format'; export interface StringLengthOptions extends ValidateOptions { // At least one of two options is required // The min, max keys define the number which the field value compares to. min, max can be // - A number // - Name of field which its value defines the number // - Name of callback function that returns the number // - A callback function that returns the number max?: number | string; min?: number | string; // Indicate the length will be calculated after trimming the value or not. It is false, by default trim?: boolean | string; // Evaluate string length in UTF-8 bytes, default to false utf8Bytes?: boolean | string; } export interface StringLengthLocalization extends Localization { stringLength: { between: string, default: string, less: string, more: string, }; } export default function stringLength() { // Credit to http://stackoverflow.com/a/23329386 (@lovasoa) for UTF-8 byte length code const utf8Length = (str: string) => { let s = str.length; for (let i = str.length - 1; i >= 0; i--) { const code = str.charCodeAt(i); if (code > 0x7f && code <= 0x7ff) { s++; } else if (code > 0x7ff && code <= 0xffff) { s += 2; } if (code >= 0xDC00 && code <= 0xDFFF) { i--; } } return `${s}`; }; return { /** * Check if the length of element value is less or more than given number */ validate(input: ValidateInput): ValidateResult { const opts = Object.assign({}, { message: '', trim: false, utf8Bytes: false, }, input.options); const v = (opts.trim === true || `${opts.trim}` === 'true') ? input.value.trim() : input.value; if (v === '') { return { valid: true }; } // TODO: `min`, `max` can be dynamic options const min = opts.min ? `${opts.min}` : ''; const max = opts.max ? `${opts.max}` : ''; const length = opts.utf8Bytes ? utf8Length(v) : v.length; let isValid = true; let msg = input.l10n ? (opts.message || input.l10n.stringLength.default) : opts.message; if ((min && length < parseInt(min, 10)) || (max && length > parseInt(max, 10))) { isValid = false; } switch (true) { case (!!min && !!max): msg = format( input.l10n ? opts.message || input.l10n.stringLength.between : opts.message, [min, max], ); break; case (!!min): msg = format( input.l10n ? opts.message || input.l10n.stringLength.more : opts.message, `${(parseInt(min, 10) - 1)}`, ); break; case (!!max): msg = format( input.l10n ? opts.message || input.l10n.stringLength.less : opts.message, `${(parseInt(max, 10) + 1)}`, ); break; default: break; } return { message: msg, valid: isValid, }; }, }; }