/**
 * Theme Name: errigal
 * Theme URI: https://projecterrigal.com/themes/errigal/
 * Author: Project errigal
 * Author URI: https://projecterrigal.com/
 * Version: 1.2.1
 */
( function() {
	'use strict';

	const ATTRIBUTE_ARIA_HIDDEN = 'aria-hidden';
	const ATTRIBUTE_ARIA_INVALID = 'aria-invalid';
	const ATTRIBUTE_ARIA_LABEL = 'aria-label';
	const CLASS_SHARED_ERROR = 'error';
	const CLASS_SHARED_ERROR_MESSAGE = 'error-message';
	const OBJECT_KEY_COMMENT_FORM_ERROR_AUTHOR_REQUIRED = 'AuthorRequired';
	const OBJECT_KEY_COMMENT_FORM_ERROR_COMMENT_REQUIRED = 'CommentRequired';
	const OBJECT_KEY_COMMENT_FORM_ERROR_EMAIL_ADDRESS_INVALID = 'EmailAddressInvalid';
	const OBJECT_KEY_COMMENT_FORM_ERROR_EMAIL_ADDRESS_REQUIRED = 'EmailAddressRequired';
	const TAG_DIV = 'div';
	const ATTRIBUTE_VALUE_TRUE = 'true';
	const ID_COMMENT_FORM_AUTHOR_FIELD = 'author';
	const CHARACTER_HASH = '#';
	const INDEX_SECOND = 1;
	const EMPTY_STRING = '';

	function isFunction( value ) {
		return value instanceof Function;
	}

	function isObjectType( value, expectedType ) {
		return Object.prototype.toString.call( value ) ===
			`[object ${ expectedType }]`;
	}

	function isString( value ) {
		return isObjectType( value, 'String' );
	}

	function isNonEmptyString( value ) {
		return (
			isString( value ) &&
			isFunction( value.trim ) &&
			value.trim() !== EMPTY_STRING
		);
	}

	const INDEX_FIRST = 0;

	function stringStartsWith( fullString, partialString ) {
		return (
			isNonEmptyString( fullString ) &&
			isNonEmptyString( partialString ) &&
			fullString.indexOf( partialString ) === INDEX_FIRST
		);
	}

	const NULL_ELEMENT = null;

	function isHTMLCollection( elements ) {
		return elements instanceof HTMLCollection;
	}

	function isNumber( value ) {
		return (
			! isNaN( value ) &&
			isObjectType( value, 'Number' ) &&
			isFinite( value )
		);
	}

	function isPositiveNumber( value ) {
		return isNumber( value ) && value > 0;
	}

	function isIterable( items ) {
		return !! items && isPositiveNumber( items.length );
	}

	function isTrue( value ) {
		return value === true;
	}

	function forEach( items, callback ) {
		if ( ! isIterable( items ) || ! isFunction( callback ) ) {
			return false;
		}

		if ( isHTMLCollection( items ) ) {
			items = Array.prototype.slice.call( items );
		}

		for ( let i = INDEX_FIRST; i < items.length; i++ ) {
			if ( isTrue( callback( items[ i ], i, items ) ) ) {
				return true;
			}
		}

		return false;
	}

	function hasClassList( element ) {
		return (
			!! element &&
			element.classList instanceof DOMTokenList &&
			isFunction( element.classList.contains )
		);
	}

	function isHTMLElement( element, ...classNames ) {
		if ( ! ( element instanceof HTMLElement ) ) {
			return false;
		}

		return (
			hasClassList( element ) &&
			! forEach(
				classNames,
				( className ) => ! element.classList.contains( className )
			)
		);
	}

	function isDocument( element ) {
		return element instanceof Document;
	}

	function isisHTMLElementOrDocument( element ) {
		return isHTMLElement( element ) || isDocument( element );
	}

	function callElementMethod(
		methodName,
		nameOrSelectors,
		rootElement
	) {
		return (
			isNonEmptyString( methodName ) &&
			isNonEmptyString( nameOrSelectors ) &&
			isisHTMLElementOrDocument( rootElement ) &&
			isFunction( rootElement[ methodName ] )
		)
			? rootElement[ methodName ]( nameOrSelectors )
			: NULL_ELEMENT;
	}

	function getElementById( id, rootElement = document ) {
		return (
			isNonEmptyString( id ) &&
			callElementMethod(
				'getElementById',
				stringStartsWith( id, CHARACTER_HASH )
					? id.slice( INDEX_SECOND )
					: id,
				rootElement
			)
		);
	}

	function getCommentFormAuthorField() {
		return getElementById( ID_COMMENT_FORM_AUTHOR_FIELD );
	}

	const ID_COMMENT_FORM_COMMENT_FIELD = 'comment';

	function getCommentFormCommentField() {
		return getElementById( ID_COMMENT_FORM_COMMENT_FIELD );
	}

	const ID_COMMENT_FORM_EMAIL_FIELD = 'email';

	function getCommentFormEmailField() {
		return getElementById( ID_COMMENT_FORM_EMAIL_FIELD );
	}

	const SELECTOR_COMPONENT_INPUT_FIELD_ERROR_MESSAGE = `${ TAG_DIV }.${ CLASS_SHARED_ERROR_MESSAGE }`;

	function getParentElement( element ) {
		return isHTMLElement( element )
			? element.parentElement
			: NULL_ELEMENT;
	}

	function querySelector( selectors, rootElement = document ) {
		return callElementMethod( 'querySelector', selectors, rootElement );
	}

	const CLASS_COMPONENT_INPUT_FIELD = 'input-field';
	const TAG_INPUT = 'input';
	const TAG_TEXTAREA = 'textarea';
	const SELECTOR_COMPONENT_INPUT_FIELD_INPUT_OR_TEXTAREA = `.${ CLASS_COMPONENT_INPUT_FIELD } > ${ TAG_INPUT }, .${ CLASS_COMPONENT_INPUT_FIELD } > ${ TAG_TEXTAREA }`;

	function matches( element, selectors ) {
		if ( ! isHTMLElement( element ) || ! isNonEmptyString( selectors ) ) {
			return false;
		}

		if ( isFunction( element.matches ) ) {
			return isTrue( element.matches( selectors ) );
		}

		if ( isFunction( element.msMatchesSelector ) ) {
			return isTrue( element.msMatchesSelector( selectors ) );
		}

		return false;
	}

	function isInputField( element ) {
		return matches( element, SELECTOR_COMPONENT_INPUT_FIELD_INPUT_OR_TEXTAREA );
	}

	function isInputFieldContainer( element ) {
		return isHTMLElement( element, CLASS_COMPONENT_INPUT_FIELD );
	}

	function getCommentFormFieldErrorMessage( inputField ) {
		if ( ! isInputField( inputField ) ) {
			return NULL_ELEMENT;
		}

		const INPUT_FIELD_CONTAINER = getParentElement( inputField );

		return isInputFieldContainer( INPUT_FIELD_CONTAINER )
			? querySelector(
				SELECTOR_COMPONENT_INPUT_FIELD_ERROR_MESSAGE,
				INPUT_FIELD_CONTAINER
			)
			: NULL_ELEMENT;
	}

	const ID_COMMENT_FORM = 'commentform';
	const SELECTOR_COMMENT_FORM_FIELD_WITH_ERROR = `#${ ID_COMMENT_FORM } .${ CLASS_SHARED_ERROR }`;

	function getFirstCommentFormFieldWithError() {
		return querySelector( SELECTOR_COMMENT_FORM_FIELD_WITH_ERROR );
	}

	const ATTRIBUTE_ID = 'id';
	const NULL_VALUE = null;

	function getAttribute( element, name ) {
		return isHTMLElement( element ) && isFunction( element.getAttribute )
			? element.getAttribute( name )
			: NULL_VALUE;
	}

	function isCommentForm( element ) {
		return getAttribute( element, ATTRIBUTE_ID ) === ID_COMMENT_FORM;
	}

	const ID_COMMENT_FORM_SUBMIT_BUTTON = 'submit';

	function isCommentFormSubmitButton( element ) {
		return getAttribute( element, ATTRIBUTE_ID ) ===
			ID_COMMENT_FORM_SUBMIT_BUTTON;
	}

	function isInputFieldFilled( element ) {
		return isInputField( element ) && isNonEmptyString( element.value );
	}

	const ATTRIBUTE_REQUIRED = 'required';

	function hasAttribute( element, attribute ) {
		return (
			!! element &&
			isFunction( element.hasAttribute ) &&
			isTrue( element.hasAttribute( attribute ) )
		);
	}

	function isInputFieldRequired( element ) {
		return (
			isInputField( element ) &&
			hasAttribute( element, ATTRIBUTE_REQUIRED )
		);
	}

	const SELECTOR_COMPONENT_INPUT_FIELD = `.${ CLASS_COMPONENT_INPUT_FIELD } > ${ TAG_INPUT }, .${ CLASS_COMPONENT_INPUT_FIELD } > ${ TAG_TEXTAREA }`;

	function isNodeList( element ) {
		return element instanceof NodeList;
	}

	function querySelectorAll( selectors, rootElement = document ) {
		const ELEMENTS =
			callElementMethod(
				'querySelectorAll',
				selectors,
				rootElement
			);

		return isNodeList( ELEMENTS )
			? ELEMENTS
			: NULL_ELEMENT;
	}

	function getInputFields() {
		return querySelectorAll( SELECTOR_COMPONENT_INPUT_FIELD );
	}

	const CLASS_SHARED_ACTIVE = 'active';
	const TAG_LABEL = 'label';

	function getFirstItem( items ) {
		return isIterable( items )
			? items[ INDEX_FIRST ]
			: NULL_VALUE;
	}

	function getElementsByTagName(
		tagName,
		rootElement = document
	) {
		const ELEMENTS =
			callElementMethod(
				'getElementsByTagName',
				tagName,
				rootElement
			);

		return isHTMLCollection( ELEMENTS )
			? ELEMENTS
			: NULL_ELEMENT;
	}

	function getElementByTagName(
		tagName,
		rootElement = document
	) {
		return getFirstItem( getElementsByTagName( tagName, rootElement ) );
	}

	function getInputFieldLabel( inputField ) {
		if ( ! isInputField( inputField ) ) {
			return NULL_ELEMENT;
		}

		const INPUT_FIELD_CONTAINER = getParentElement( inputField );

		return isInputFieldContainer( INPUT_FIELD_CONTAINER )
			? getElementByTagName( TAG_LABEL, INPUT_FIELD_CONTAINER )
			: NULL_ELEMENT;
	}

	function addClass( element, className ) {
		if (
			! isHTMLElement( element ) ||
			! hasClassList( element ) ||
			! isFunction( element.classList.add ) ||
			! isNonEmptyString( className )
		) {
			return;
		}

		element.classList.add( className );
	}

	function floatInputFieldLabel( inputField ) {
		addClass( getInputFieldLabel( inputField ), CLASS_SHARED_ACTIVE );
	}

	function initialiseFloatingInputFieldLabel( inputField ) {
		if ( isInputFieldFilled( inputField ) ) {
			floatInputFieldLabel( inputField );
		}
	}

	function initialiseFloatingInputFieldLabels() {
		forEach( getInputFields(), initialiseFloatingInputFieldLabel );
	}

	function isNode( element ) {
		return element instanceof Node;
	}

	function appendChild( node, element ) {
		if (
			! isNode( node ) ||
			! isFunction( node.appendChild ) ||
			! isHTMLElement( element )
		) {
			return;
		}

		node.appendChild( element );
	}

	function removeAttribute( element, ...names ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.removeAttribute )
		) {
			return;
		}

		forEach( names, ( name ) => element.removeAttribute( name ) );
	}

	function removeClass( element, className ) {
		if (
			! isHTMLElement( element ) ||
			! hasClassList( element ) ||
			! isFunction( element.classList.remove ) ||
			! isNonEmptyString( className )
		) {
			return;
		}

		element.classList.remove( className );
	}

	function removeElement( element ) {
		if (
			! isHTMLElement( element ) ||
			! isNode( element.parentNode ) ||
			! isFunction( element.parentNode.removeChild )
		) {
			return;
		}

		element.parentNode.removeChild( element );
	}

	function setAttribute( element, name, value ) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.setAttribute ) ||
			! isNonEmptyString( name )
		) {
			return;
		}

		element.setAttribute( name, value );
	}

	function setTextContent( element, text ) {
		if ( ! ( isHTMLElement( element ) || isString( element.textContent ) ) ) {
			return;
		}

		element.textContent = text;
	}

	const EVENT_CLICK = 'click';

	function isBoolean( value ) {
		return isObjectType( value, 'Boolean' );
	}

	function isObject( value ) {
		return value instanceof Object;
	}

	function isUndefined( value ) {
		return isObjectType( value, 'Undefined' );
	}

	function onDocumentEvent( eventType, callback, options ) {
		if (
			! isNonEmptyString( eventType ) ||
			! isFunction( callback ) ||
			! ( isUndefined( options ) || isObject( options ) || isBoolean( options ) )
		) {
			return;
		}

		document.addEventListener( eventType, callback, options || false );
	}

	function onDocumentClick( callback, options ) {
		onDocumentEvent( EVENT_CLICK, callback, options );
	}

	const EVENT_SUBMIT = 'submit';

	function onDocumentSubmit( callback, options ) {
		onDocumentEvent( EVENT_SUBMIT, callback, options );
	}

	const CALLBACK_INITIAL_ATTEMPT_COUNT = 0;
	const CALLBACK_INITIAL_INTERVAL = 0;
	const CALLBACK_INTERVAL = 50;
	const CALLBACK_MAX_ATTEMPT_COUNT = 20;

	function focusElement(
		element,
		attemptCount = CALLBACK_INITIAL_ATTEMPT_COUNT,
		interval = CALLBACK_INITIAL_INTERVAL
	) {
		if (
			! isHTMLElement( element ) ||
			! isFunction( element.focus ) ||
			! isNumber( attemptCount ) ||
			! isNumber( interval ) ||
			attemptCount === CALLBACK_MAX_ATTEMPT_COUNT
		) {
			return;
		}

		element.focus();
		setTimeout(
			() => {
				if ( element === document.activeElement ) {
					return;
				}

				focusElement( element, ++attemptCount, CALLBACK_INTERVAL );
			},
			interval
		);
	}

	function getObjectValue( obj, key ) {
		return isObject( obj ) && ( key in obj )
			? obj[ key ]
			: NULL_VALUE;
	}

	function filter( items, callback ) {
		return (
			!! items &&
			isFunction( items.filter ) &&
			isFunction( callback )
		)
			? items.filter( callback )
			: NULL_VALUE;
	}

	const STRING_SANITISATION_RULES = [
		{
			pattern: /<script[^>]*?>.*?<\/script>/gi,
			replacement: EMPTY_STRING,
		},
		{
			pattern: /<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g,
			replacement: EMPTY_STRING,
		},
		{
			pattern: /&/g,
			replacement: '&amp;',
		},
		{
			pattern: /</g,
			replacement: '&lt;',
		},
		{
			pattern: />/g,
			replacement: '&gt;',
		},
		{
			pattern: /"/g,
			replacement: '&quot;',
		},
		{
			pattern: /'/g,
			replacement: '&#39;',
		},
	];

	function sanitiseString( value ) {
		if ( ! isString( value ) ) {
			return EMPTY_STRING;
		}

		forEach(
			filter(
				STRING_SANITISATION_RULES,
				( rule ) =>
					!! rule && isObject( rule.pattern ) && isString( rule.replacement )
			),
			( rule ) => value = value.replace( rule.pattern, rule.replacement )
		);

		return value;
	}

	function toLowerCase( value ) {
		return isNonEmptyString( value ) && isFunction( value.toLowerCase )
			? value.toLowerCase()
			: EMPTY_STRING;
	}

	function hasParentNode( element ) {
		return isHTMLElement( element ) && !! element.parentNode;
	}

	function isEvent( value ) {
		return (
			value instanceof Event &&
			isFunction( value.preventDefault ) &&
			isFunction( value.stopPropagation )
		);
	}

	function isFalse( value ) {
		return value === false;
	}

	const OBJECT_KEYS_COMMENT_FORM_ERRORS = [
		OBJECT_KEY_COMMENT_FORM_ERROR_AUTHOR_REQUIRED,
		OBJECT_KEY_COMMENT_FORM_ERROR_COMMENT_REQUIRED,
		OBJECT_KEY_COMMENT_FORM_ERROR_EMAIL_ADDRESS_REQUIRED,
		OBJECT_KEY_COMMENT_FORM_ERROR_EMAIL_ADDRESS_INVALID,
	];
	const OBJECT_NAME_COMMENT_FORM_ERRORS = 'ERRIGAL_COMMENT_FORM_ERRORS';
	const EMPTY_ARRAY = [];
	const NULL_OBJECT = null;

	function hasObjectKey( value, index ) {
		return (
			!! value &&
			!! index &&
			isTrue( Object.prototype.hasOwnProperty.call( value, index ) )
		);
	}

	function isStringArray( items ) {
		return Array.isArray( items ) && isIterable( items )
			? ! forEach( items, ( item ) => ! isNonEmptyString( item ) )
			: false;
	}

	function getGlobalObject(
		objectName,
		expectedKeys = EMPTY_ARRAY
	) {
		if ( ! ( expectedKeys === EMPTY_ARRAY || isStringArray( expectedKeys ) ) ) {
			return NULL_OBJECT;
		}

		const GLOBAL_OBJECT = getObjectValue( window, objectName );

		if ( ! isObject( GLOBAL_OBJECT ) ) {
			return NULL_OBJECT;
		}

		if ( ! isPositiveNumber( expectedKeys.length ) ) {
			return GLOBAL_OBJECT;
		}

		const HAS_EXPECTED_KEYS =
			! forEach(
				expectedKeys,
				( key ) => ! hasObjectKey( GLOBAL_OBJECT, key )
			);

		return isTrue( HAS_EXPECTED_KEYS )
			? GLOBAL_OBJECT
			: NULL_OBJECT;
	}

	function getCommentFormErrorsObject() {
		return getGlobalObject(
			OBJECT_NAME_COMMENT_FORM_ERRORS,
			OBJECT_KEYS_COMMENT_FORM_ERRORS
		);
	}

	function focusFirstCommentFormFieldWithError() {
		focusElement( getFirstCommentFormFieldWithError() );
	}

	function isValidEmailAddressFormat( value ) {
		const REGEX_EMAIL_ADDRESS_FORMAT = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

		return (
			isNonEmptyString( value ) &&
			REGEX_EMAIL_ADDRESS_FORMAT.test( toLowerCase( value ) )
		);
	}

	function hasEmail() {
		const EMAIL_FIELD = getCommentFormEmailField();

		if ( ! isInputFieldRequired( EMAIL_FIELD ) ) {
			return true;
		}

		const HAS_EMAIL = isInputFieldFilled( EMAIL_FIELD );

		updateCommentFormFieldError(
			EMAIL_FIELD,
			HAS_EMAIL,
			OBJECT_KEY_COMMENT_FORM_ERROR_EMAIL_ADDRESS_REQUIRED
		);

		if ( isFalse( HAS_EMAIL ) ) {
			return false;
		}

		const IS_VALID_EMAIL_ADDRESS_FORMAT =
			isValidEmailAddressFormat( EMAIL_FIELD.value );

		updateCommentFormFieldError(
			EMAIL_FIELD,
			IS_VALID_EMAIL_ADDRESS_FORMAT,
			OBJECT_KEY_COMMENT_FORM_ERROR_EMAIL_ADDRESS_INVALID
		);

		return isTrue( IS_VALID_EMAIL_ADDRESS_FORMAT );
	}

	function hasName() {
		const AUTHOR_FIELD = getCommentFormAuthorField();

		if ( ! isInputFieldRequired( AUTHOR_FIELD ) ) {
			return true;
		}

		const HAS_NAME = isInputFieldFilled( AUTHOR_FIELD );

		updateCommentFormFieldError(
			AUTHOR_FIELD,
			HAS_NAME,
			OBJECT_KEY_COMMENT_FORM_ERROR_AUTHOR_REQUIRED
		);

		return isTrue( HAS_NAME );
	}

	function addCommentFormFieldError( inputField, errorMessage ) {
		if ( ! isInputField( inputField ) ) {
			return;
		}

		const ERROR_MESSAGE_TEXT = sanitiseString( errorMessage );

		if ( ! isNonEmptyString( ERROR_MESSAGE_TEXT ) ) {
			return;
		}

		addClass( inputField, CLASS_SHARED_ERROR );
		setAttribute( inputField, ATTRIBUTE_ARIA_LABEL, ERROR_MESSAGE_TEXT );
		setAttribute( inputField, ATTRIBUTE_ARIA_INVALID, ATTRIBUTE_VALUE_TRUE );

		const ERROR_MESSAGE = document.createElement( TAG_DIV );

		if ( ! ERROR_MESSAGE || ! hasParentNode( inputField ) ) {
			return;
		}

		setTextContent( ERROR_MESSAGE, ERROR_MESSAGE_TEXT );
		addClass( ERROR_MESSAGE, CLASS_SHARED_ERROR_MESSAGE );
		setAttribute( ERROR_MESSAGE, ATTRIBUTE_ARIA_HIDDEN, ATTRIBUTE_VALUE_TRUE );
		appendChild( inputField.parentNode, ERROR_MESSAGE );
	}

	function removeCommentFormFieldError( inputField ) {
		if ( ! isInputField( inputField ) ) {
			return;
		}

		removeClass( inputField, CLASS_SHARED_ERROR );
		removeAttribute( inputField, ATTRIBUTE_ARIA_LABEL, ATTRIBUTE_ARIA_INVALID );
		removeElement( getCommentFormFieldErrorMessage( inputField ) );
	}

	function updateCommentFormFieldError(
		inputField,
		hasValidValue,
		commentFormErrorKey
	) {
		if ( ! isInputField( inputField ) ) {
			return;
		}

		removeCommentFormFieldError( inputField );

		if ( isTrue( hasValidValue ) ) {
			return;
		}

		addCommentFormFieldError(
			inputField,
			getObjectValue( getCommentFormErrorsObject(), commentFormErrorKey )
		);
	}

	function hasComment() {
		const COMMENT_FIELD = getCommentFormCommentField();

		if ( ! COMMENT_FIELD ) {
			return true;
		}

		const HAS_COMMENT = isInputFieldFilled( COMMENT_FIELD );

		updateCommentFormFieldError(
			COMMENT_FIELD,
			HAS_COMMENT,
			OBJECT_KEY_COMMENT_FORM_ERROR_COMMENT_REQUIRED
		);

		return isTrue( HAS_COMMENT );
	}

	function isCommentFormValid() {
		const HAS_COMMENT = hasComment();
		const HAS_NAME = hasName();
		const HAS_EMAIL = hasEmail();

		return HAS_COMMENT && HAS_NAME && HAS_EMAIL;
	}

	function addCommentValidationEvents() {
		onDocumentClick( ( event ) => {
			if ( ! isEvent( event ) ) {
				return;
			}

			if (
				isCommentFormSubmitButton( event.target ) &&
				! isCommentFormValid()
			) {
				event.preventDefault();
				focusFirstCommentFormFieldWithError();
			}
		} );
		onDocumentSubmit( ( event ) => {
			if ( ! isEvent( event ) ) {
				return;
			}

			if ( isCommentForm( event.target ) ) {
				initialiseFloatingInputFieldLabels();
			}
		} );
	}

	function addCommentEvents() {
		addCommentValidationEvents();
	}

	addCommentEvents();
}() );
