lib/input.js
function Input(el, validatorsNameOptionsTuples, onInputValidationResult, isBlurOnly) {

    if (validInputTagNames.indexOf(el.nodeName.toLowerCase()) === -1) {
        throw 'only operates on the following html tags: ' + validInputTagNames.toString();
    }

    this._el = el;
    this._validatorsNameOptionsTuples = validatorsNameOptionsTuples;
    this._onInputValidationResult = onInputValidationResult || defaultOnInputValidationResult;
    this._isBlurOnly = isBlurOnly;
    this._validators = buildValidators();
    this._inputState = new InputState();
    this._elName = el.nodeName.toLowerCase();
    this._elType = el.type;
    this._isKeyed = (this._elName === 'textarea' || keyStrokedInputTypes.indexOf(this._elType) > -1);
    this._runValidatorsBounded = this._runValidators.bind(this);

    this._initListeners();

    function buildValidators() {
        var result = [];
        validatorsNameOptionsTuples.forEach(function(validatorsNameOptionsTuple) {
            var validatorName = validatorsNameOptionsTuple[0];
            var validatorOptions = validatorsNameOptionsTuple[1];

            result.push({
                name: validatorName,
                run: validatorRepo.build(validatorName, validatorOptions)
            });

        });

        return result;
    }

    /** The default {@link _internal.onInputValidationResult onInputValidationResult} used when {@link vivalid.Input} is initiated without a 3rd parameter
     *  @name defaultOnInputValidationResult
     *  @function
     *  @memberof! _internal
     */
    function defaultOnInputValidationResult(el, validationsResult, validatorName, stateEnum) {

        var errorDiv;

        // for radio buttons and checkboxes:  get the last element in group by name
        if ((el.nodeName.toLowerCase() === 'input' && (el.type === 'radio' || el.type === 'checkbox'))) {

            var getAllByName = el.parentNode.querySelectorAll('input[name="' + el.name + '"]');

            el = getAllByName.item(getAllByName.length - 1);
        }

        if (validationsResult.stateEnum === stateEnum.invalid) {

            errorDiv = getExistingErrorDiv(el);
            if (errorDiv) {
                errorDiv.textContent = validationsResult.message;
            } else {
                appendNewErrorDiv(el, validationsResult.message);
            }

            el.style.borderStyle = "solid";
            el.style.borderColor = "#ff0000";
            $$.addClass(el, "vivalid-error-input");
        } else {
            errorDiv = getExistingErrorDiv(el);
            if (errorDiv) {
                errorDiv.parentNode.removeChild(errorDiv);
                el.style.borderStyle = "";
                el.style.borderColor = "";
                $$.removeClass(el, "vivalid-error-input");
            }
        }

        function getExistingErrorDiv(el) {
            if (el.nextElementSibling && el.nextElementSibling.className === "vivalid-error") {
                return el.nextElementSibling;
            }

        }

        function appendNewErrorDiv(el, message) {
            errorDiv = document.createElement("DIV");
            errorDiv.className = "vivalid-error";
            errorDiv.style.color = "#ff0000";
            var t = document.createTextNode(validationsResult.message);
            errorDiv.appendChild(t);
            el.parentNode.insertBefore(errorDiv, el.nextElementSibling);
        }

    }

}
function Input(el, validatorsNameOptionsTuples, onInputValidationResult, isBlurOnly) {

    if (validInputTagNames.indexOf(el.nodeName.toLowerCase()) === -1) {
        throw 'only operates on the following html tags: ' + validInputTagNames.toString();
    }

    this._el = el;
    this._validatorsNameOptionsTuples = validatorsNameOptionsTuples;
    this._onInputValidationResult = onInputValidationResult || defaultOnInputValidationResult;
    this._isBlurOnly = isBlurOnly;
    this._validators = buildValidators();
    this._inputState = new InputState();
    this._elName = el.nodeName.toLowerCase();
    this._elType = el.type;
    this._isKeyed = (this._elName === 'textarea' || keyStrokedInputTypes.indexOf(this._elType) > -1);
    this._runValidatorsBounded = this._runValidators.bind(this);

    this._initListeners();

    function buildValidators() {
        var result = [];
        validatorsNameOptionsTuples.forEach(function(validatorsNameOptionsTuple) {
            var validatorName = validatorsNameOptionsTuple[0];
            var validatorOptions = validatorsNameOptionsTuple[1];

            result.push({
                name: validatorName,
                run: validatorRepo.build(validatorName, validatorOptions)
            });

        });

        return result;
    }

    /** The default {@link _internal.onInputValidationResult onInputValidationResult} used when {@link vivalid.Input} is initiated without a 3rd parameter
     *  @name defaultOnInputValidationResult
     *  @function
     *  @memberof! _internal
     */
    function defaultOnInputValidationResult(el, validationsResult, validatorName, stateEnum) {

        var errorDiv;

        // for radio buttons and checkboxes:  get the last element in group by name
        if ((el.nodeName.toLowerCase() === 'input' && (el.type === 'radio' || el.type === 'checkbox'))) {

            var getAllByName = el.parentNode.querySelectorAll('input[name="' + el.name + '"]');

            el = getAllByName.item(getAllByName.length - 1);
        }

        if (validationsResult.stateEnum === stateEnum.invalid) {

            errorDiv = getExistingErrorDiv(el);
            if (errorDiv) {
                errorDiv.textContent = validationsResult.message;
            } else {
                appendNewErrorDiv(el, validationsResult.message);
            }

            el.style.borderStyle = "solid";
            el.style.borderColor = "#ff0000";
            $$.addClass(el, "vivalid-error-input");
        } else {
            errorDiv = getExistingErrorDiv(el);
            if (errorDiv) {
                errorDiv.parentNode.removeChild(errorDiv);
                el.style.borderStyle = "";
                el.style.borderColor = "";
                $$.removeClass(el, "vivalid-error-input");
            }
        }

        function getExistingErrorDiv(el) {
            if (el.nextElementSibling && el.nextElementSibling.className === "vivalid-error") {
                return el.nextElementSibling;
            }

        }

        function appendNewErrorDiv(el, message) {
            errorDiv = document.createElement("DIV");
            errorDiv.className = "vivalid-error";
            errorDiv.style.color = "#ff0000";
            var t = document.createTextNode(validationsResult.message);
            errorDiv.appendChild(t);
            el.parentNode.insertBefore(errorDiv, el.nextElementSibling);
        }

    }

}
function Input ( el , validatorsNameOptionsTuples , onInputValidationResult , isBlurOnly ) { if ( validInputTagNames . indexOf ( el . nodeName . toLowerCase ( ) ) === - 1 ) { throw 'only operates on the following html tags: ' + validInputTagNames . toString ( ) ; } this . _el = el ; this . _validatorsNameOptionsTuples = validatorsNameOptionsTuples ; this . _onInputValidationResult = onInputValidationResult || defaultOnInputValidationResult ; this . _isBlurOnly = isBlurOnly ; this . _validators = buildValidators ( ) ; this . _inputState = new InputState ( ) ; this . _elName = el . nodeName . toLowerCase ( ) ; this . _elType = el . type ; this . _isKeyed = ( this . _elName === 'textarea' || keyStrokedInputTypes . indexOf ( this . _elType ) > - 1 ) ; this . _runValidatorsBounded = this . _runValidators . bind ( this ) ; this . _initListeners ( ) ; function buildValidators ( ) { var result = [ ] ; validatorsNameOptionsTuples . forEach ( function ( validatorsNameOptionsTuple ) { var validatorName = validatorsNameOptionsTuple [ 0 ] ; var validatorOptions = validatorsNameOptionsTuple [ 1 ] ; result . push ( { name : validatorName , run : validatorRepo . build ( validatorName , validatorOptions ) } ) ; } ) ; return result ; } /** The default {@link _internal.onInputValidationResult onInputValidationResult} used when {@link vivalid.Input} is initiated without a 3rd parameter
     *  @name defaultOnInputValidationResult
     *  @function
     *  @memberof! _internal
     */ function defaultOnInputValidationResult ( el , validationsResult , validatorName , stateEnum ) { var errorDiv ; // for radio buttons and checkboxes:  get the last element in group by name if ( ( el . nodeName . toLowerCase ( ) === 'input' && ( el . type === 'radio' || el . type === 'checkbox' ) ) ) { var getAllByName = el . parentNode . querySelectorAll ( 'input[name="' + el . name + '"]' ) ; el = getAllByName . item ( getAllByName . length - 1 ) ; } if ( validationsResult . stateEnum === stateEnum . invalid ) { errorDiv = getExistingErrorDiv ( el ) ; if ( errorDiv ) { errorDiv . textContent = validationsResult . message ; } else { appendNewErrorDiv ( el , validationsResult . message ) ; } el . style . borderStyle = "solid" ; el . style . borderColor = "#ff0000" ; $$ . addClass ( el , "vivalid-error-input" ) ; } else { errorDiv = getExistingErrorDiv ( el ) ; if ( errorDiv ) { errorDiv . parentNode . removeChild ( errorDiv ) ; el . style . borderStyle = "" ; el . style . borderColor = "" ; $$ . removeClass ( el , "vivalid-error-input" ) ; } } function getExistingErrorDiv ( el ) { if ( el . nextElementSibling && el . nextElementSibling . className === "vivalid-error" ) { return el . nextElementSibling ; } } function appendNewErrorDiv ( el , message ) { errorDiv = document . createElement ( "DIV" ) ; errorDiv . className = "vivalid-error" ; errorDiv . style . color = "#ff0000" ; var t = document . createTextNode ( validationsResult . message ) ; errorDiv . appendChild ( t ) ; el . parentNode . insertBefore ( errorDiv , el . nextElementSibling ) ; } } }
creates a new Input object wrapping around a DOM object.
@memberof! vivalid
@class
@example new Input(document.getElementById('Name'), [['required',{msg: 'custom required message'}],['max',{max: 10}]])
@param {HTMLElement} el the DOM object to wrap. For radios and checkboxes, pass only 1 element- the class will find it's siblings with the same name attribute.
@param {_internal.validatorsNameOptionsTuple[]} validatorsNameOptionsTuples <b> the order matters- the input's state is the first {@link _internal.validatorsNameOptionsTuple validatorsNameOptionsTuple} that evulates to a non-valid (pending or invalid) state. </b>
@param {function} [onInputValidationResult] Signature of {@link _internal.onInputValidationResult onInputValidationResult}. A function to handle an input state or message change. If not passed, {@link _internal.defaultOnInputValidationResult defaultOnInputValidationResult} will be used.
@param {boolean} isBlurOnly if true, doesn't not trigger validation on 'input' or 'change' events.
creates a new Input object wrapping around a DOM object .