Source: scripts.js

/**
 * @file Get the data from the API 'Rick and Morty' and display it. It generates a navigation menu filtering through the 3 types of data (characters, locations and episodes). It has a pagination in each of them. It has a searcher input to filter by name.
 * @author Beatriz Sopeña Merino <beatrizsmerino@gmail.com>
 * @copyright Beatriz Sopeña Merino 2019. It is free software and you can find the source code on Github.
 * @see {@link https://beatrizsmerino.github.io/rick-and-morty/}
 */





/**
 * @const urlAPI
 * @description API route 'Rick and morty'
 * @type {String}
 * @see Used in: {@link ajaxHandler}
 */
const urlAPI = "https://rickandmortyapi.com/api/";


/**
 * @var appButton
 * @description App button
 * @type {HTMLElement}
 * @see Used in: {@link click}
 */
let appButton = document.getElementById("appButton");


/**
 * @var appContent
 * @description App content
 * @type {HTMLElement}
 * @see Used in: {@link setAction}, {@link appContentAdd}, {@link filterRemoveContent}, {@link searchCreate}, {@link searchRemove}, {@link paginationCreate}, {@link paginationRemove}, {@link click}
 */
let appContent = document.getElementById("appContent");





// TOOLS
//////////////////////////////////

/**
 * @function svgMe
 * @description Converts an `<img>` tag, with a `.svg` extention and a class `svgMe`, into a `<svg>` tag.
 * @return {Object} Return the file svg
 * @see Used in: {@link functionAnonimAutoExecuted}
 */
function svgMe() {
	let images = document.querySelectorAll("img.svgMe");

	// console.info("Array of images -> ", images);

	images.forEach(image => {
		let imgId = image.getAttribute("id");
		let imgClass = image.getAttribute("class");
		let imgUrl = image.getAttribute("src");

		let request = new XMLHttpRequest();
		request.onreadystatechange = function () {
			if (request.readyState == 4 && request.status == 200) {
				// console.info("request in xml -> ", request.responseXML);
				callback(request.responseXML);
			}
		};

		function callback(requestXML) {
			let imgSvg = requestXML.querySelector("svg");

			// console.info("data type of 'data' -> ", typeof requestXML);
			// console.info("'data' -> ", requestXML);
			// console.info("images with svgMe -> ", imgSvg);

			if (typeof imgId !== "undefined") {
				// console.info(imgId);
				imgSvg.setAttribute("id", imgId);
			}

			if (typeof imgClass !== "undefined") {
				// console.info(imgClass);
				imgSvg.setAttribute("class", imgClass);
				imgSvg.classList.add("svgMe--replaced");
			}

			imgSvg.removeAttribute("xmlns:a");
			if (
				!imgSvg.getAttribute("viewBox") &&
				imgSvg.getAttribute("height") &&
				imgSvg.getAttribute("width")
			) {
				imgSvg.setAttribute(
					"viewBox",
					"0 0 " +
					imgSvg.getAttribute("height") +
					" " +
					imgSvg.getAttribute("width")
				);
			}

			image.replaceWith(imgSvg);
		}

		request.open("GET", imgUrl);
		request.send();
	});
}


/**
 * @function firstUpperCase
 * @description Converts the first letter of a string to uppercase
 * @param {String} string - string with the this letter in lowercase
 * @return {String} returns the same modified string
 * @see Used in: {@link cardCreate}
 */
function firstUpperCase(string) {
	let stingLowerCase = string.toLowerCase();
	let stringCapitalize = stingLowerCase.charAt(0).toUpperCase() + stingLowerCase.slice(1);
	return stringCapitalize;
}


/**
 * @function delay
 * @description Executes a function after a given time
 * @param {Function} fn - function to execute
 * @param {Number} ms - delay time in miliseconds
 * @see Used in: {@link searchAdd}
 */
function delay(fn, ms) {
	let timer = 0;
	return function (...args) {
		clearTimeout(timer);
		timer = setTimeout(fn.bind(this, ...args), ms || 0);
	};
}


/**
 * @function getCurrentYear
 * @description Get the current year
 * @return {Number}
 * @see Used in: {@link addCurrentYear}
 */
function getCurrentYear() {
	const year = new Date().getFullYear();

	return year;
}





// AJAX HANDLER - FETCH
//////////////////////////////////

/**
 * @function ajaxHandler
 * @description API request
 * @param {String} url - root of the API
 * @param {String} action - name of the action to excute
 * @return {object}
 * @see Used inside: {@link loaderAdd}, {@link loaderRemove}, {@link setAction}
 * @see Used in: {@link searchAdd}, {@link paginationAdd}, {@link click}
 */
function ajaxHandler(url, action) {
	loaderAdd();

	fetch(url)
		.then(handleResponse)
		.then(function (data) {
			// console.log("%c--- Promise 2 ---", "padding: 0.5rem 1rem; color: #C0C0C0; background-color: #454545;");
			// console.info(data);
			// console.info('data is', data);
			let timer = setInterval(function () {
				clearInterval(timer);
				loaderRemove();
				messageRemove("messageError404");
				setAction(action, appContent, data);
			}, 3000);
		})
		.catch(function (error) {
			// console.warn('error is', error);
			if (error.status === 404) {
				loaderRemove();
				messageError404Add();
			}
		});

	function handleResponse(response) {
		let contentType = response.headers.get('content-type')
		if (contentType.includes('application/json')) {
			return handleJSONResponse(response);
		} else if (contentType.includes('text/html')) {
			return handleTextResponse(response);
		} else {
			// Other response types as necessary. I haven't found a need for them yet though.
			throw new Error(`Sorry, content-type ${contentType} not supported`);
		}
	}

	function handleJSONResponse(response) {
		return response.json()
			.then(json => {
				if (response.ok) {
					return json;
				} else {
					return Promise.reject(Object.assign({}, json, {
						status: response.status,
						statusText: response.statusText
					}));
				}
			});
	}

	function handleTextResponse(response) {
		return response.text()
			.then(text => {
				if (response.ok) {
					return json;
				} else {
					return Promise.reject({
						status: response.status,
						statusText: response.statusText,
						err: text
					});
				}
			});
	}
}





// COPYRIGHT
//////////////////////////////////
/**
 * @function addCurrentYear
 * @description Add the current year to the copyright
 * @see Used inside: {@link getCurrentYear}
 * @see Used in: {@link functionAnonimAutoExecuted}
 */
function addCurrentYear() {
	const copyrightYear = document.querySelector("#currentYear");

	copyrightYear.innerHTML = getCurrentYear();
}




// LOADER
//////////////////////////////////
/**
 * @function loaderCreate
 * @description Creation of a loading animation
 * @return {HTMLElement}
 * @see Used in: {@link loaderAdd}
 */
function loaderCreate() {
	let template = `
        <div class="spinner">
            <div class="double-bounce1"></div>
            <div class="double-bounce2"></div>
        </div>
        `;
	let loader = document.createElement("div");

	loader.setAttribute("id", "loader");
	loader.setAttribute("class", "loader");
	loader.innerHTML = template;

	return loader;
}


/**
 * @function loaderAdd
 * @description Add loading animation
 * @see Used in: {@link ajaxHandler}
 */
function loaderAdd() {
	let loader = loaderCreate();
	if (loader) {
		let timer = setInterval(function () {
			let loaderDom = document.getElementById("loader");
			if (!loaderDom) {
				clearInterval(timer);
				// document.querySelectorAll(".page__item").style.filter = "blur(1rem)";
				document.body.classList.add("is-searching");
				document.body.appendChild(loader);
			}
		}, 100);
	}
}


/**
 * @function loaderRemove
 * @description Remove loading animation
 * @see Used in: {@link ajaxHandler}
 */
function loaderRemove() {
	let loaderDom = document.getElementById("loader");
	if (loaderDom) {
		//scripts.jsdocument.querySelectorAll(".page__item").style.filter = "none";
		document.body.classList.remove("is-searching");
		document.body.removeChild(loaderDom);
	}
}





// FILTER
//////////////////////////////////

/**
 * @function appContentAdd
 * @description Add link of the API to the app content
 * @param {String} url - root of the API
 * @see Used in: {@link click}
 */
function appContentAdd(url) {
	let linkId = document.getElementById("linkApi");

	if (!linkId) {
		let link = document.createElement("a");
		let linkText = document.createTextNode(url);

		link.setAttribute("id", "linkApi");
		link.setAttribute("href", url);
		link.setAttribute("target", "_blank");
		link.appendChild(linkText);
		appContent.appendChild(link);
	}
}


/**
 * @function setAction
 * @description List of functions to choose from
 * @param {String} action - name of the action to excute
 * @param {HTMLElement} elementDom - DOM element where the response data is inserted
 * @param {Object} dataResponse - response data of the ajax handler (json)
 * @see Used inside: {@link filterAdd}, {@link filterAddContent}
 * @see Used in: {@link ajaxHandler}
 */
function setAction(action, elementDom, dataResponse) {
	if (action === "filterAdd") {
		filterAdd(elementDom, dataResponse);
	} else if (action === "filterAddContent") {
		filterAddContent(elementDom, dataResponse);
	}
}


/**
 * @function filterAdd
 * @description Add navigation menu filtering through the 3 types of data (characters, locations and episodes) to the app content.
 * @param {HTMLElement} elementDom - DOM element where the filter is inserted
 * @param {Object} responseData - response data of the ajax handler (json)
 * @see Used in: {@link setAction}
 */
function filterAdd(elementDom, responseData) {
	let navId = document.getElementById("filter");

	if (!navId) {
		let list = document.createElement("ul");
		list.setAttribute("id", "filter");
		list.setAttribute("class", "filter");

		for (const key in responseData) {
			const element = responseData[key];
			let item = document.createElement("li");
			let itemText = document.createTextNode(key);

			item.setAttribute("data-filter", key);
			item.setAttribute("data-url", element + "?page=1");
			item.setAttribute("class", "filter__item");

			item.appendChild(itemText);
			list.appendChild(item);
		}

		elementDom.appendChild(list);
	}
}


/**
 * @function filterActive
 * @description Add class 'is-active' to the item of the navigation clicked.
 * @param {HTMLCollectionOf} item - filter list
 * @param {Element} thisActive - filter selected
 * @see Used in: {@link functionAnonimAutoExecuted}
 */
function filterActive(item, thisActive) {
	for (let index = 0; index < item.length; index++) {
		const element = item[index];
		if (element.classList.contains("is-active")) {
			// console.log("has class");
			element.classList.remove("is-active");
		}
		thisActive.classList.add("is-active");
	}
}


/**
 * @function filterAddContentInfo
 * @description Insert information to the content with the number of results of the request
 * @param {Object} responseData - response data of the ajax handler (json)
 * @return {Element}
 * @see Used in: {@link filterAddContent}
 */
function filterAddContentInfo(responseData) {
	// console.table(responseData.info);
	let listInfo = document.createElement("div");
	listInfo.setAttribute("class", "list-info");
	listInfo.innerHTML = "<p><strong>Results: </strong>" + responseData.info.count + "</p>";

	return listInfo;
}


/**
 * @function filterAddContentResults
 * @description Insert results to the content of the request
 * @param {Object} responseData - response data of the ajax handler (json)
 * @return {Element}
 * @see Used inside: {@link cardCreate}, {@link cardMoveImage}, {@link cardWhenClicked}
 * @see Used in: {@link filterAddContent}
 */
function filterAddContentResults(responseData) {
	// console.table(responseData.results);
	let listCards = document.createElement("div");
	let listCardsInner = document.createElement("div");

	listCards.setAttribute("class", "list-cards");

	listCardsInner.setAttribute("id", "filterResult");
	listCardsInner.setAttribute("class", "list-cards__inner");

	cardCreate(listCardsInner, responseData);
	cardMoveImage();
	cardWhenClicked();

	listCards.appendChild(listCardsInner);

	return listCards;
}


/**
 * @function filterAddContent
 * @description Add the filter content application
 * @param {HTMLElement} elementDom - DOM element where the filter content is inserted
 * @param {Object} responseData - response data of the ajax handler (json)
 * @see Used inside: {@link filterAddContentInfo}, {@link filterAddContentResults}...
 * @see Used in: {@link setAction}
 */
function filterAddContent(elementDom, responseData) {
	let list = document.createElement("section");
	list.setAttribute("class", "list");
	list.setAttribute("id", "list");

	const infoContent = filterAddContentInfo(responseData);
	const resultsContent = filterAddContentResults(responseData);

	/**
	* @function filterAddAllContent
	* @description Insert the content
	* @see {@link filterFoundContent}
	*/
	function filterAddAllContent() {
		list.appendChild(infoContent);
		list.appendChild(resultsContent);
		elementDom.appendChild(list);
	}

	/**
	 * @function filterFoundContent
	 * @description Check if the contents of one filter are shown and before loading another one, delete it
	 * @see Used inside: {@link filterAddAllContent}, {@link filterRemoveContent}, {@link paginationRemove}, {@link paginationAdd}
	 */
	function filterFoundContent() {
		let element = document.querySelectorAll(".list");
		if (element != undefined) {
			// console.dir(element);
			// console.log(element.length);
			if (element.length == 0) {
				filterAddAllContent();
				paginationAdd(responseData);
			} else {
				filterRemoveContent();
				paginationRemove();
				filterAddAllContent();
				paginationAdd(responseData);
				return true;
			}
		}
	}

	let timer = setInterval(function () {
		if (filterFoundContent()) {
			clearInterval(timer);
		}
	}, 100);
}


/**
 * @function filterRemoveContent
 * @description Remove the selected filter content of the application content
 * @see Used in: {@link searchAdd}, {@link filterAddContent}, {@link paginationAdd}, {@link functionAnonimAutoExecuted}
 */
function filterRemoveContent() {
	let list = document.querySelectorAll(".list");
	for (let index = 0; index < list.length; index++) {
		const element = list[index];
		if (element && element.innerHTML !== "") {
			appContent.removeChild(element);
		}
	}
}





// MESSAGE
//////////////////////////////////
/**
 * @function messageAdd
 * @description Create the message component
 * @param {String} messageId - Id for events js
 * @param {String} messageClass - Class css with modifier BEM of the message
 * @param {String} messageText - Text of the message
 * @see Used inside: {@link messageCloseAdd}
 * @see Used in: {@link messageError404Add}, {@link messageAlertAdd}
 */
function messageAdd(messageId, messageClass, messageText) {
	let messageDom = document.getElementById(messageId);

	let messageButton;
	switch (messageClass) {
		case "message-alert":
			messageButton = messageCloseAdd();
			messageButton = messageButton.outerHTML;
			break;
		case "message-error404":
			messageButton = "";
		default:
			break;
	}

	if (!messageDom) {
		let messageElem = document.createElement("div");
		messageElem.setAttribute("id", messageId);
		messageElem.setAttribute("class", `message ${messageClass}`);

		let templateMessage = `
			<div class="message__inner">
				${messageButton}
				<div class="message__content">
					<p>
						${messageText}
					</p>
				</div>
			</div>
		`;
		messageElem.innerHTML = templateMessage;
		return messageElem;
	}
}



/**
 * @function messageCloseAdd
 * @description Create a button for remove the message
 * @see Used in: {@link messageAlertAdd}
 */
function messageCloseAdd() {
	let buttonDom = document.createElement("button");
	buttonDom.classList.add("message__button-close");

	return buttonDom;
}


/**
 * @function messageRemove
 * @description Remove the message component
 * @param {String} messageId - id of the message to remove
 * @see Used in: {@link ajaxHandler}
 */
function messageRemove(messageId) {
	let messsage = document.getElementById(messageId);
	if (messsage) {
		messsage.parentElement.removeChild(messsage);
		// console.log("Message removed");
	}
}


/**
 * @function messageError404Add
 * @description Add message error 404 (search not found)
 * @see Used inside: {@link messageAdd}
 * @see Used in: {@link ajaxHandler}
 */
function messageError404Add() {
	filterRemoveContent();
	paginationRemove();

	let templateMessage = messageAdd("messageError404", "message-error404", "Error 404.</br> Search not found");
	appContent.appendChild(templateMessage);
}


/**
 * @function messageAlertAdd
 * @description Create a alert personalized
 * @param {String} messageName - Name of message in camellCase
 * @param {String} messageText - Text of message
 * @see Used inside: {@link messageAdd}, {@link messageRemove}
 */
function messageAlertAdd(messageName, messageText) {
	let messageId = "messageAlert" + messageName;
	let templateMessage = messageAdd(messageId, "message-alert", messageText);
	document.body.appendChild(templateMessage);
	document.querySelector("#" + messageId + " .message__button-close").addEventListener("click", function () {
		messageRemove(messageId);
	});
}





// CARD
//////////////////////////////////

/**
 * @function cardCreate
 * @description Create card with the data response
 * @param {Element} listCardsInner - DOM element that wraps up the card list
 * @param {object} responseData - response data of the ajax handler (json)
 * @see Used inside: {@link firstUpperCase}
 * @see Used in: {@link filterAddContentResults}
 */
function cardCreate(listCardsInner, responseData) {
	// console.group("Results");
	for (const key in responseData.results) {
		const element = responseData.results[key];
		let card = document.createElement("article");

		card.setAttribute("class", "card");
		card.setAttribute("data-index", key);

		let cardButton = document.createElement("span");
		cardButton.setAttribute("class", "card__button icon-eye");

		// console.group("Result " + key);
		for (const titleData in element) {
			const cardItemData = element[titleData];
			// console.info(firstUpperCase(titleData) + ": " + cardItemData);

			let cardItemDom = document.createElement("div");
			cardItemDom.setAttribute("class", "card__data");
			cardItemDom.setAttribute("data-type", titleData);

			if (titleData !== "image") {
				let cardParagraphDom = document.createElement("h4");
				cardParagraphDom.setAttribute("class", "card__subtitle");
				let cardParagraphTextDom = document.createTextNode(
					firstUpperCase(titleData) + ": "
				);
				cardParagraphDom.appendChild(cardParagraphTextDom);
				cardItemDom.appendChild(cardParagraphDom);
			} else {
				let cardImageDom = document.createElement("img");
				cardImageDom.setAttribute("src", cardItemData);
				cardItemDom.appendChild(cardImageDom);
			}

			// console.assert(typeof cardItemData === "string" || typeof cardItemData === "number", cardItemData + " es un " + typeof cardItemData);

			if (typeof cardItemData === "object") {
				if (Array.isArray(cardItemData)) {
					let cardUlDom = document.createElement("ul");
					cardUlDom.setAttribute("class", "card__list");

					for (let index = 0; index < cardItemData.length; index++) {
						const cardUlData = cardItemData[index];

						let cardLiDom = document.createElement("li");
						let cardLiTextDom = document.createTextNode(cardUlData);

						cardLiDom.appendChild(cardLiTextDom);
						cardUlDom.appendChild(cardLiDom);
					}

					cardItemDom.appendChild(cardUlDom);
				} else {
					let cardUlDom = document.createElement("ul");
					cardUlDom.setAttribute("class", "card__list");

					for (const key in cardItemData) {
						const cardUlData = cardItemData[key];

						let cardLiDom = document.createElement("li");
						let cardLiTextDom = document.createTextNode(cardUlData);

						cardLiDom.appendChild(cardLiTextDom);
						cardUlDom.appendChild(cardLiDom);
					}

					cardItemDom.appendChild(cardUlDom);
				}
			} else {
				if (titleData !== "image") {
					let cardParagraphDom = document.createElement("p");
					let cardParagraphTextDom = document.createTextNode(cardItemData);

					cardParagraphDom.appendChild(cardParagraphTextDom);
					cardItemDom.appendChild(cardParagraphDom);
				}
			}

			card.appendChild(cardButton);
			card.appendChild(cardItemDom);
		}
		// console.groupEnd();

		listCardsInner.appendChild(card);
	}
	// console.groupEnd();
}


/**
 * @function cardMoveImage
 * @description Move the card image up.
 * @see Used in: {@link filterAddContentResults}
 */
function cardMoveImage() {
	let timer = setInterval(function () {
		let cardData = document.querySelectorAll(".card__data");
		if (cardData) {
			clearInterval(timer);
			let card = document.querySelectorAll(".card");
			for (let index = 0; index < card.length; index++) {
				const element = card[index];
				let imageItem = element.querySelector(".card__data[data-type='image']");
				if (imageItem) {
					element.removeChild(imageItem);
					element.insertBefore(imageItem, element.firstChild);
				}
			}
		}
	}, 300);
}


/**
 * @function cardToggleView
 * @description See more card info
 * @param {HTMLCollectionOf} item - list of cards
 * @param {Element} thisView - card selected
 * @see Used in: {@link cardWhenClicked}
 */
function cardToggleView(item, thisView) {
	for (let index = 0; index < item.length; index++) {
		const element = item[index];
		if (!thisView.classList.contains("is-view")) {
			element.classList.remove("is-view");
		}
	}
	thisView.classList.toggle("is-view");
}


/**
 * @function cardWhenClicked
 * @description Event click in the card
 * @see Used inside: {@link cardToggleView}
 * @see Used in: {@link click}
 */
function cardWhenClicked() {
	let timerCard = setInterval(function () {
		let cardItem = document.getElementsByClassName("card");

		if (cardItem.length > 0) {
			clearInterval(timerCard);
			for (let index = 0; index < cardItem.length; index++) {
				const element = cardItem[index];

				/**
				* @description View more card info when click it.
				* @event click
				* @type {object}
				* @see Used inside: {@link cardToggleView}
				*/
				element.addEventListener("click", function (e) {
					cardToggleView(cardItem, this);
				});
			}
		}
	});
}





// SEARCH
//////////////////////////////////

/**
 * @function searchCreate
 * @description Create searcher
 * @see Used in: {@link searchAdd}
 */
function searchCreate() {
	let searchDom = document.createElement("div");
	let searchInnerDom = document.createElement("div");
	let searchIconDom = document.createElement("div");
	let searchInput = document.createElement("input");

	searchDom.setAttribute("id", "search");
	searchDom.setAttribute("class", "search");
	searchInnerDom.setAttribute("class", "search__inner");
	searchIconDom.setAttribute("class", "search__icon icon-magnifying-glass");

	searchInput.setAttribute("id", "searchInput");
	searchInput.setAttribute("class", "search__input");

	searchInnerDom.appendChild(searchIconDom);
	searchInnerDom.appendChild(searchInput);
	searchDom.appendChild(searchInnerDom);
	appContent.appendChild(searchDom);
}


/**
 * @function searchGet
 * @description Get the active filter to find it.
 * @param {Element} filterActive - filter selected
 * @see Used in: {@link searchAdd}
 */
function searchGet(filterActive) {
	let searchInput = document.getElementById("searchInput");
	let filterActiveText = filterActive.getAttribute("data-filter");
	searchInput.setAttribute("placeholder", "Search by name of " + filterActiveText);

	let searchBy;
	switch (filterActiveText) {
		case "characters":
			searchBy = "character";
			break;
		case "episodies":
			searchBy = "episode";
			break;
		case "locations":
			searchBy = "location";
			break;
		default:
			break;
	}

	// console.assert(searchBy !== "", "Not Search");
	// console.log(searchBy);

	return searchBy;
}


/**
 * @function searchAdd
 * @description Add searcher
 * @param {Element} filterActive - filter selected
 * @see Used inside: {@link searchCreate}, {@link searchGet}...
 * @see Used in: {@link functionAnonimAutoExecuted}
 */
function searchAdd(filterActive) {
	searchCreate();

	let searchBy = searchGet(filterActive);

	/**
	* @description Search by selected filter name when typing in the search engine input.
	* @event keyup
	* @type {Object}
	* @see Used inside: {@link delay}, {@link filterRemoveContent}, {@link paginationRemove}, {@link ajaxHandler}
	*/
	document.getElementById("searchInput").addEventListener("keyup", delay(function (e) {
		let valueInput = this.value;

		filterRemoveContent();
		paginationRemove();
		ajaxHandler(urlAPI + searchBy + "/?" + "name" + "=" + valueInput, "filterAddContent");

		// console.log(this);
		// console.log(this.value);
		// console.log(urlAPI + searchBy + "/?" + "name" + "=" + valueInput);
		// console.assert(valueInput, "Input hasn`t value");
	}, 500));
}


/**
 * @function searchRemove
 * @description Remove searcher
 * @see Used in: {@link functionAnonimAutoExecuted}
 */
function searchRemove() {
	let search = document.getElementById("search");
	if (search) {
		appContent.removeChild(search);
	}
}




// PAGINATION
//////////////////////////////////

/**
 * @function paginationCreate
 * @description Create pagination
 * @param {Object} responseData - response data of the ajax handler (json)
 * @see Used in: {@link paginationAdd}
 */
function paginationCreate(responseData) {
	let pagination = document.createElement("div");
	pagination.setAttribute("class", "pagination");
	pagination.setAttribute("id", "pagination");

	let buttonNext = document.createElement("div");
	buttonNext.setAttribute("class", "pagination__button icon-chevron-right");
	buttonNext.setAttribute("id", "buttonNext");
	buttonNext.setAttribute("data-url", responseData.info.next);

	let buttonPrev = document.createElement("div");
	buttonPrev.setAttribute("class", "pagination__button icon-chevron-left");
	buttonPrev.setAttribute("id", "buttonPrev");
	buttonPrev.setAttribute("data-url", responseData.info.prev);

	pagination.appendChild(buttonPrev);
	pagination.appendChild(buttonNext);
	appContent.appendChild(pagination);
}


/**
 * @function paginationSetCounter
 * @description Create counter pagination
 * @param {Object} responseData - response data of the ajax handler (json)
 * @see Used in: {@link paginationAdd}
 */
function paginationSetCounter(responseData) {
	let buttonPrev = document.getElementById("buttonPrev");

	let paginationTotal = responseData.info.pages;
	let paginationNext = responseData.info.next;
	let paginationNow;

	// console.log(paginationNext);
	if (paginationNext == "") {
		paginationNow = paginationTotal;
	} else {
		var paginationNextUrl = new URL(paginationNext);
		var numPageNext = paginationNextUrl.searchParams.get("page");
		paginationNow = parseInt(numPageNext) - 1;

		if (paginationNow <= 1 || isNaN(paginationNow)) {
			paginationNow = 1;
		}
	}


	// console.log(paginationNext);
	// console.log(paginationNow);


	let paginationCounter = document.createElement("div");
	let paginationCounterText = document.createTextNode(
		paginationNow.toString() + " - " + paginationTotal.toString()
	);

	paginationCounter.setAttribute("class", "pagination__counter");
	paginationCounter.appendChild(paginationCounterText);
	// console.log(paginationCounter);

	buttonPrev.parentNode.insertBefore(paginationCounter, buttonPrev.nextSibling);
}


/**
 * @function paginationAdd
 * @description Add pagination
 * @param {Object} responseData - response data of the ajax handler (json)
 * @see Used inside: {@link paginationCreate}, {@link paginationSetCounter}...
 * @see Used in: {@link filterFoundContent}
 */
function paginationAdd(responseData) {
	paginationCreate(responseData);
	paginationSetCounter(responseData);

	let button = document.getElementsByClassName("pagination__button");
	for (let index = 0; index < button.length; index++) {
		const element = button[index];

		/**
		* @description Remove/Add content and pagination by selecting the filter from the navigation menu.
		* @event click
		* @type {object}
		* @see Used inside: {@link filterRemoveContent}, {@link paginationRemove}, {@link ajaxHandler}
		*/
		element.addEventListener("click", function () {
			let url = this.getAttribute("data-url");

			if (url !== "") {
				filterRemoveContent();
				paginationRemove();
				ajaxHandler(url, "filterAddContent");
			}
		});
	}
}


/**
 * @function paginationRemove
 * @description Remove pagination
 * @see Used in: {@link functionAnonimAutoExecuted}, {@link filterAddContent}, {@link searchAdd}, {@link paginationAdd}
 */
function paginationRemove() {
	let pagination = document.getElementById("pagination");
	if (pagination) {
		appContent.removeChild(pagination);
	}
}





// ADBLOCK
//////////////////////////////////

/**
 * @function adblockDetected
 * @description Callback executed if adblock is installed
 * @see Used inside {@link messageAlert}
 * @see Used in: {@link checkAdblock}
 **/
function adblockDetected() {
	let message = "<i class='message-alert__icon icon-warning'></i> AdBlock is enabled";
	// console.warn(message);
	// alert(message);
	messageAlertAdd("AdBlock", message);
}


/**
 * @function adblockDisabled
 * @description Callback executed if adblock is disabled
 * @see Used in: {@link checkAdblock}
 **/
function adblockDisabled() {
	let message = "AdBlock is not enabled";
	// console.info(message);
}


/**
 * @function adblockVerify
 * @description Verify if the user has installed the Adblock browser extension
 * @see Used inside: {@link adblockDetected} {@link adblockDisabled}
 * @see Used in: {@link functionAnonimAutoExecuted}
 **/
function adblockVerify() {
	if (typeof blockAdBlock === "undefined") {
		adblockDetected();
	} else {
		blockAdBlock.onDetected(adblockDetected);
		blockAdBlock.onNotDetected(adblockDisabled);
	}
}





/**
 * @description Get API data
 * @event click
 * @type {Object}
 * @see Used inside: {@link appContentAdd}, {@link ajaxHandler}
 */
appButton.addEventListener("click", function () {
	// alert("Get API data");
	appContentAdd(urlAPI);
	appContent.removeChild(document.getElementById("portal"));
	ajaxHandler(urlAPI, "filterAdd");
});


/**
 * @function functionAnonimAutoExecuted
 * @description Anonymous auto executed function
 * @see Used inside: {@link svgMe}...
 */
(function () {
	adblockVerify();
	svgMe();
	addCurrentYear();

	let timerFilterItem = setInterval(function () {
		let filterArray = document.getElementsByClassName("filter__item");
		if (filterArray.length > 0) {
			clearInterval(timerFilterItem);
			for (let index = 0; index < filterArray.length; index++) {
				const filterItem = filterArray[index];

				/**
				* @description Remove / Add content and pagination when selecting the filter of the navigation menu.
				* @event click
				* @type {object}
				* @see Used inside: {@link filterRemoveContent}, {@link paginationRemove}, {@link searchRemove}, {@link filterActive}, {@link searchAdd}, {@link ajaxHandler}
				*/
				filterItem.addEventListener("click", function () {
					filterRemoveContent();
					paginationRemove();
					searchRemove();

					filterActive(filterArray, this);
					searchAdd(this);
					ajaxHandler(this.getAttribute("data-url"), "filterAddContent");
				});
			}
		}
	});
})();