MediaWiki:Script/Filter.js : Différence entre versions
| Ligne 10 : | Ligne 10 : | ||
} | } | ||
| − | function | + | function editCardData(cardsData) { |
| − | + | for (let cardIndex = 0; cardIndex < cardsData.length; cardIndex++) { | |
| − | + | const cardData = cardsData[cardIndex]; | |
| − | + | const cardName = cardData.card.querySelector("[data-name]").textContent; | |
| − | + | ||
| + | cardData.name = toNormalForm(cardName); | ||
} | } | ||
} | } | ||
| − | function | + | function observeLanguageChange(filterName, cardsData) { |
| − | + | if (!filterName) { | |
| − | + | return; | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | + | const observer = new MutationObserver(function (mutation) { | |
| − | + | editCardData(cardsData); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
}); | }); | ||
| − | + | observer.observe(filterName, { attributes: true }); | |
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | function | + | function openFilter() { |
| − | + | const filterButton = document.getElementById("open-filter"); | |
| − | + | const filterDropdown = filterButton.nextElementSibling; | |
| − | + | ||
| + | hideElement(filterDropdown); | ||
| − | + | filterButton.addEventListener("click", handleDropdown); | |
| − | |||
| − | function | + | function handleDropdown() { |
| − | + | toggleElement(filterDropdown); | |
| − | |||
} | } | ||
| − | + | document.addEventListener("mousedown", function (event) { | |
| + | if ( | ||
| + | !filterButton.contains(event.target) && | ||
| + | !filterDropdown.contains(event.target) | ||
| + | ) { | ||
| + | hideElement(filterDropdown); | ||
| + | } | ||
| + | }); | ||
} | } | ||
| − | function | + | function fillData(filter, filterData) { |
| − | + | const { filter: category, value } = filter.dataset; | |
| − | |||
| − | + | if (filter.type === "checkbox") { | |
| − | + | const span = filter.parentElement.querySelector("span.counter"); | |
| + | const filterInfo = { value: 0, span }; | ||
| + | const { checkbox } = filterData; | ||
| − | + | checkbox[category] = checkbox[category] || {}; | |
| − | + | checkbox[category][value] = filterInfo; | |
| − | + | } else if (filter.type === "number") { | |
| − | + | const { range } = filterData; | |
| − | + | if (range.hasOwnProperty(category)) { | |
| − | + | return; | |
} | } | ||
| + | const init = { min: Number(filter.min), max: Number(filter.max) }; | ||
| + | range[category] = { init: init }; | ||
} | } | ||
| + | } | ||
| − | + | function extractInitData(card, cardData) { | |
| − | + | const cardNameElement = card.querySelector("[data-name]"); | |
| − | |||
| − | |||
| − | |||
| − | + | cardData.card = card; | |
| − | + | cardData.name = toNormalForm(cardNameElement.textContent); | |
| − | + | cardData.trueName = cardNameElement.firstChild.title; | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | function extractLevelData(card, cardData) { | |
| − | + | const levelElement = card.querySelector("[data-level]"); | |
| − | + | const [level, rank] = levelElement.textContent.slice(1, -1).split(", "); | |
| − | |||
| − | |||
| − | |||
| − | + | cardData["level"] = Number(level); | |
| − | + | cardData["rank"] = removeAccent(rank); | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | function extractElementData(card, cardData) { | |
| − | + | const elementChild = card.querySelector("[data-elem]").children; | |
| − | + | let elementValue = ""; | |
| − | + | if (elementChild.length) { | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | if ( | ||
| − | |||
for ( | for ( | ||
| − | + | let elementIndex = 0; | |
| − | + | elementIndex < elementChild.length; | |
| − | + | elementIndex++ | |
) { | ) { | ||
| − | + | elementValue += elementChild[elementIndex].title + " "; | |
} | } | ||
| − | |||
| − | |||
} | } | ||
| + | elementValue = elementValue.trim() || "Aucun"; | ||
| + | cardData.elem = removeAccent(elementValue); | ||
| + | } | ||
| − | + | function extractTypeData(card, cardData) { | |
| − | + | const typeElement = card.querySelector("[data-type]"); | |
| − | + | cardData.type = removeAccent(typeElement.textContent.split(" ")[0]); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | function | + | function extractDamageData(card, cardData) { |
| − | + | const damageElement = card.querySelector("[data-damage]"); | |
| − | + | cardData.damage = removeAccent(damageElement.textContent.replace(" + ", " ")); | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | function extractLocData(card, cardData) { | |
| − | + | const locElement = card.querySelector("[data-loc]"); | |
| − | + | cardData.loc = locElement.dataset.loc; | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | function getCardsData(cardsContainer, filterData, dataExtractionMapping) { | |
| − | + | const cards = cardsContainer.children; | |
| − | + | const activeExtractors = [extractInitData]; | |
| − | |||
| − | |||
| − | |||
| − | + | for (const [key, extractorFunction] of Object.entries( | |
| − | + | dataExtractionMapping | |
| − | + | )) { | |
| − | + | if ( | |
| − | + | filterData.range.hasOwnProperty(key) || | |
| − | + | filterData.checkbox.hasOwnProperty(key) | |
| − | + | ) { | |
| − | + | activeExtractors.push(extractorFunction); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | + | const cardsData = []; | |
| − | |||
| − | + | for (let cardIndex = 0; cardIndex < cards.length; cardIndex++) { | |
| − | + | const card = cards[cardIndex]; | |
| − | + | const cardData = {}; | |
| − | + | for (const extractor of activeExtractors) { | |
| − | + | extractor(card, cardData); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | |||
| − | |||
| − | + | cardsData.push(cardData); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | + | return cardsData; | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | function filterInitialization(filterForm) { | |
| − | + | const filterData = { | |
| − | + | form: filterForm, | |
| − | + | filters: { filterName: "", filter: {}, rangeFilter: {} }, | |
| − | |||
range: {}, | range: {}, | ||
checkbox: {}, | checkbox: {}, | ||
reverse: false, | reverse: false, | ||
}; | }; | ||
| − | + | const filters = filterForm.querySelectorAll("[data-filter]"); | |
| − | |||
| − | + | filters.forEach((filter) => fillData(filter, filterData)); | |
| − | |||
| − | + | return filterData; | |
| + | } | ||
| − | + | function displayCounterValue(checkbox) { | |
| − | + | for (let filterCategory in checkbox) { | |
| − | + | const category = checkbox[filterCategory]; | |
| − | + | for (let filterValue in category) { | |
| + | const valueData = category[filterValue]; | ||
| − | + | valueData.span.textContent = " (" + valueData.value + ")"; | |
| − | + | valueData.value = 0; | |
| − | + | } | |
| − | + | } | |
| − | + | } | |
| − | + | function updateCounter(cardData, checkbox, filterCategory) { | |
| − | + | cardData[filterCategory].split(" ").forEach((cardValue) => { | |
| − | + | checkbox[filterCategory][cardValue].value += 1; | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
}); | }); | ||
| + | } | ||
| − | return [ | + | function isObjectValuesInRangeFilter(parameters, rangeFilter) { |
| + | return Object.entries(rangeFilter).every( | ||
| + | ([property, { min, max }]) => | ||
| + | parameters[property] >= min && parameters[property] <= max | ||
| + | ); | ||
} | } | ||
| − | function | + | function filterByName(parameters, filterName) { |
| − | + | if (filterName) { | |
| − | return | + | return parameters.name.includes(filterName); |
} | } | ||
| + | return true; | ||
| + | } | ||
| + | |||
| + | function isObjectValuesInFilter(parameters, filter) { | ||
| + | return Object.entries(filter).every(([property, values]) => | ||
| + | parameters[property].split(" ").some((value) => values.includes(value)) | ||
| + | ); | ||
| + | } | ||
| − | + | function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) { | |
| − | + | return ( | |
| − | + | isObjectValuesInFilter(parameters, filter) && | |
| − | + | filterByName(parameters, filterName) && | |
| − | + | isObjectValuesInRangeFilter(parameters, rangeFilter) | |
| − | + | ); | |
| + | } | ||
| − | + | function filterCards(cardsContainer, filterData, cardsData) { | |
| − | + | const { filters, checkbox } = filterData; | |
| − | + | const { filter, rangeFilter, filterName } = filters; | |
| − | |||
| − | if ( | + | if (filterData.reverse) { |
| − | for ( | + | for ( |
| − | + | let reverseIndex = 1; | |
| + | reverseIndex < cardsData.length; | ||
| + | reverseIndex++ | ||
| + | ) { | ||
| + | cardsContainer.insertBefore( | ||
| + | cardsData[reverseIndex].card, | ||
| + | cardsContainer.firstChild | ||
| + | ); | ||
} | } | ||
| + | cardsData.reverse(); | ||
| + | filterData.reverse = false; | ||
} | } | ||
| − | if ( | + | for (let cardIndex = 0; cardIndex < cardsData.length; cardIndex++) { |
| − | + | const cardData = cardsData[cardIndex]; | |
| + | |||
| + | if (isObjectValuesInFilters(cardData, filter, rangeFilter, filterName)) { | ||
| + | showElement(cardData.card); | ||
| + | for (let filterCategory in checkbox) { | ||
| + | updateCounter(cardData, checkbox, filterCategory); | ||
| + | } | ||
| + | } else { | ||
| + | hideElement(cardData.card); | ||
| + | } | ||
} | } | ||
| − | + | displayCounterValue(checkbox); | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | function handleCheckbox(target, filter) { | |
| − | + | const { filter: category, value } = target.dataset; | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | + | if (target.checked) { | |
| − | + | filter[category] = filter[category] || []; | |
| − | + | filter[category].push(value); | |
| − | + | } else { | |
| − | + | const index = filter[category].indexOf(value); | |
| − | + | if (index !== -1) { | |
| − | + | filter[category].splice(index, 1); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | + | if (!filter[category].length) { | |
| − | if ( | + | delete filter[category]; |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | |||
| − | |||
} | } | ||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | function | + | function handleNumberType(target, rangeFilter, range) { |
| − | + | const { filter: category, value: extremum } = target.dataset; | |
| + | const currentValue = Number(target.value); | ||
| + | const initialRange = range[category].init; | ||
| − | + | if (rangeFilter[category]) { | |
| − | + | rangeFilter[category][extremum] = currentValue; | |
| − | + | } else { | |
| − | + | rangeFilter[category] = { | |
| + | min: initialRange.min, | ||
| + | max: initialRange.max, | ||
| + | }; | ||
| + | rangeFilter[category][extremum] = currentValue; | ||
| + | } | ||
| + | if ( | ||
| + | rangeFilter[category].max === initialRange.max && | ||
| + | rangeFilter[category].min === initialRange.min | ||
) { | ) { | ||
| − | + | delete rangeFilter[category]; | |
| − | |||
| − | |||
} | } | ||
} | } | ||
| − | function | + | function handleFormEvents(cardsContainer, filterForm, filterData, cardsData) { |
| − | + | const { filters, range } = filterData; | |
| + | let debounceTimer; | ||
| − | + | filterForm.addEventListener("submit", function (event) { | |
| − | + | event.preventDefault(); | |
| − | } | + | }); |
| + | |||
| + | filterForm.addEventListener("change", updateFilter); | ||
| − | + | filterForm.addEventListener("input", function (event) { | |
| − | + | clearTimeout(debounceTimer); | |
| + | debounceTimer = setTimeout(() => { | ||
| + | if (event.target.id === "filter-name") { | ||
| + | updateFilter(event, true); | ||
| + | } | ||
| + | }, 500); | ||
}); | }); | ||
| − | + | function updateFilter(event, filterByName = false) { | |
| + | const target = event.target; | ||
| + | const targetType = target.type; | ||
| + | |||
| + | if (filterByName) { | ||
| + | filters.filterName = toNormalForm(target.value); | ||
| + | } else if (targetType === "checkbox") { | ||
| + | handleCheckbox(target, filters.filter); | ||
| + | } else if (targetType === "number") { | ||
| + | handleNumberType(target, filters.rangeFilter, range); | ||
| + | } | ||
| + | |||
| + | filterCards(cardsContainer, filterData, cardsData); | ||
| + | } | ||
} | } | ||
| − | function | + | function processUrlParameter(filterName, filterData, key, value) { |
| − | + | const { filters } = filterData; | |
| − | + | ||
| − | + | if (key === "name") { | |
| − | + | filterName.value = toNormalForm(value); | |
| − | + | filters.filterName = value; | |
| − | + | } else if (Object.keys(filterData.checkbox).indexOf(key) !== -1) { | |
| − | + | const checkboxElement = document.getElementById(key + "-" + value); | |
| − | + | ||
| − | + | if (!checkboxElement) return; | |
| − | + | ||
| − | + | checkboxElement.checked = true; | |
| − | + | filters.filter[key] = filters.filter[key] || []; | |
| − | + | filters.filter[key].push(value); | |
| − | + | } else if (key === "reverse") { | |
| − | + | if (value === "1") { | |
| − | + | filterData.reverse = true; | |
| − | + | const reverseElement = document.getElementById("filter-reverse"); | |
| − | + | if (reverseElement) { | |
| − | + | reverseElement.checked = true; | |
| − | |||
} | } | ||
| − | } else { | + | } |
| − | + | } else { | |
| − | + | const [splitKey, extremum] = key.split("-"); | |
| − | + | ||
| − | + | if (Object.keys(filterData.range).indexOf(splitKey) !== -1) { | |
| − | + | const rangeElement = document.getElementById(key); | |
| − | + | ||
| − | + | if (!rangeElement) return; | |
| − | + | ||
| − | + | rangeElement.value = value; | |
| − | + | ||
| − | + | const rangeData = filterData.range[splitKey]; | |
| − | + | const rangeFilter = filters.rangeFilter; | |
| − | + | ||
| − | + | if (rangeFilter[splitKey]) { | |
| − | + | rangeFilter[splitKey][extremum] = value; | |
| − | + | } else { | |
| − | + | rangeFilter[splitKey] = { | |
| − | + | min: rangeData.init.min, | |
| + | max: rangeData.init.max, | ||
| + | }; | ||
| + | rangeFilter[splitKey][extremum] = value; | ||
} | } | ||
} | } | ||
} | } | ||
| + | } | ||
| − | + | function filterWithUrl(filterName, filterData) { | |
| − | + | const url = new URL(window.location.href); | |
| − | + | const { hash, search } = url; | |
| − | + | let useParams = true; | |
| − | if ( | + | if (hash) { |
| − | + | const start = ".3F"; | |
| − | + | const equal = ".3D"; | |
| − | + | const and = ".26"; | |
| − | + | const startParametersIndex = hash.indexOf(start); | |
if (startParametersIndex !== -1) { | if (startParametersIndex !== -1) { | ||
| − | + | const parameters = hash.slice(startParametersIndex + start.length); | |
| − | |||
parameters.split(and).forEach(function (keyValue) { | parameters.split(and).forEach(function (keyValue) { | ||
| − | + | const [key, value] = keyValue.split(equal); | |
| − | + | processUrlParameter(filterName, filterData, key, value); | |
}); | }); | ||
| + | |||
| + | useParams = false; | ||
} | } | ||
} | } | ||
if (useParams) { | if (useParams) { | ||
| − | + | const URLparams = new URLSearchParams(search); | |
| − | for ( | + | for (const [key, value] of URLparams.entries()) { |
| − | + | processUrlParameter(filterName, filterData, key, value); | |
} | } | ||
} | } | ||
} | } | ||
| − | + | function main_filter() { | |
| − | + | const filterForm = document.getElementById("filter-form"); | |
| − | + | const filterName = document.getElementById("filter-name"); | |
| + | const cardsContainer = document.getElementById("cards-container"); | ||
| + | |||
| + | const dataExtractionMapping = { | ||
| + | level: extractLevelData, | ||
| + | elem: extractElementData, | ||
| + | type: extractTypeData, | ||
| + | damage: extractDamageData, | ||
| + | loc: extractLocData | ||
| + | }; | ||
| + | |||
| + | const filterData = filterInitialization(filterForm); | ||
| + | const cardsData = getCardsData( | ||
| + | cardsContainer, | ||
| + | filterData, | ||
| + | dataExtractionMapping | ||
| + | ); | ||
| + | |||
| + | observeLanguageChange(filterName, cardsData); | ||
| + | openFilter(); | ||
| + | filterWithUrl(filterName, filterData); | ||
| + | filterCards(cardsContainer, filterData, cardsData); | ||
| + | handleFormEvents(cardsContainer, filterForm, filterData, cardsData); | ||
| + | } | ||
| − | + | main_filter(); | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
Version du 11 décembre 2024 à 08:32
function removeAccent(str) {
return str
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.toLowerCase();
}
function toNormalForm(str) {
return removeAccent(str).replace(/[^a-zA-Z0-9 ]/g, "");
}
function editCardData(cardsData) {
for (let cardIndex = 0; cardIndex < cardsData.length; cardIndex++) {
const cardData = cardsData[cardIndex];
const cardName = cardData.card.querySelector("[data-name]").textContent;
cardData.name = toNormalForm(cardName);
}
}
function observeLanguageChange(filterName, cardsData) {
if (!filterName) {
return;
}
const observer = new MutationObserver(function (mutation) {
editCardData(cardsData);
});
observer.observe(filterName, { attributes: true });
}
function openFilter() {
const filterButton = document.getElementById("open-filter");
const filterDropdown = filterButton.nextElementSibling;
hideElement(filterDropdown);
filterButton.addEventListener("click", handleDropdown);
function handleDropdown() {
toggleElement(filterDropdown);
}
document.addEventListener("mousedown", function (event) {
if (
!filterButton.contains(event.target) &&
!filterDropdown.contains(event.target)
) {
hideElement(filterDropdown);
}
});
}
function fillData(filter, filterData) {
const { filter: category, value } = filter.dataset;
if (filter.type === "checkbox") {
const span = filter.parentElement.querySelector("span.counter");
const filterInfo = { value: 0, span };
const { checkbox } = filterData;
checkbox[category] = checkbox[category] || {};
checkbox[category][value] = filterInfo;
} else if (filter.type === "number") {
const { range } = filterData;
if (range.hasOwnProperty(category)) {
return;
}
const init = { min: Number(filter.min), max: Number(filter.max) };
range[category] = { init: init };
}
}
function extractInitData(card, cardData) {
const cardNameElement = card.querySelector("[data-name]");
cardData.card = card;
cardData.name = toNormalForm(cardNameElement.textContent);
cardData.trueName = cardNameElement.firstChild.title;
}
function extractLevelData(card, cardData) {
const levelElement = card.querySelector("[data-level]");
const [level, rank] = levelElement.textContent.slice(1, -1).split(", ");
cardData["level"] = Number(level);
cardData["rank"] = removeAccent(rank);
}
function extractElementData(card, cardData) {
const elementChild = card.querySelector("[data-elem]").children;
let elementValue = "";
if (elementChild.length) {
for (
let elementIndex = 0;
elementIndex < elementChild.length;
elementIndex++
) {
elementValue += elementChild[elementIndex].title + " ";
}
}
elementValue = elementValue.trim() || "Aucun";
cardData.elem = removeAccent(elementValue);
}
function extractTypeData(card, cardData) {
const typeElement = card.querySelector("[data-type]");
cardData.type = removeAccent(typeElement.textContent.split(" ")[0]);
}
function extractDamageData(card, cardData) {
const damageElement = card.querySelector("[data-damage]");
cardData.damage = removeAccent(damageElement.textContent.replace(" + ", " "));
}
function extractLocData(card, cardData) {
const locElement = card.querySelector("[data-loc]");
cardData.loc = locElement.dataset.loc;
}
function getCardsData(cardsContainer, filterData, dataExtractionMapping) {
const cards = cardsContainer.children;
const activeExtractors = [extractInitData];
for (const [key, extractorFunction] of Object.entries(
dataExtractionMapping
)) {
if (
filterData.range.hasOwnProperty(key) ||
filterData.checkbox.hasOwnProperty(key)
) {
activeExtractors.push(extractorFunction);
}
}
const cardsData = [];
for (let cardIndex = 0; cardIndex < cards.length; cardIndex++) {
const card = cards[cardIndex];
const cardData = {};
for (const extractor of activeExtractors) {
extractor(card, cardData);
}
cardsData.push(cardData);
}
return cardsData;
}
function filterInitialization(filterForm) {
const filterData = {
form: filterForm,
filters: { filterName: "", filter: {}, rangeFilter: {} },
range: {},
checkbox: {},
reverse: false,
};
const filters = filterForm.querySelectorAll("[data-filter]");
filters.forEach((filter) => fillData(filter, filterData));
return filterData;
}
function displayCounterValue(checkbox) {
for (let filterCategory in checkbox) {
const category = checkbox[filterCategory];
for (let filterValue in category) {
const valueData = category[filterValue];
valueData.span.textContent = " (" + valueData.value + ")";
valueData.value = 0;
}
}
}
function updateCounter(cardData, checkbox, filterCategory) {
cardData[filterCategory].split(" ").forEach((cardValue) => {
checkbox[filterCategory][cardValue].value += 1;
});
}
function isObjectValuesInRangeFilter(parameters, rangeFilter) {
return Object.entries(rangeFilter).every(
([property, { min, max }]) =>
parameters[property] >= min && parameters[property] <= max
);
}
function filterByName(parameters, filterName) {
if (filterName) {
return parameters.name.includes(filterName);
}
return true;
}
function isObjectValuesInFilter(parameters, filter) {
return Object.entries(filter).every(([property, values]) =>
parameters[property].split(" ").some((value) => values.includes(value))
);
}
function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) {
return (
isObjectValuesInFilter(parameters, filter) &&
filterByName(parameters, filterName) &&
isObjectValuesInRangeFilter(parameters, rangeFilter)
);
}
function filterCards(cardsContainer, filterData, cardsData) {
const { filters, checkbox } = filterData;
const { filter, rangeFilter, filterName } = filters;
if (filterData.reverse) {
for (
let reverseIndex = 1;
reverseIndex < cardsData.length;
reverseIndex++
) {
cardsContainer.insertBefore(
cardsData[reverseIndex].card,
cardsContainer.firstChild
);
}
cardsData.reverse();
filterData.reverse = false;
}
for (let cardIndex = 0; cardIndex < cardsData.length; cardIndex++) {
const cardData = cardsData[cardIndex];
if (isObjectValuesInFilters(cardData, filter, rangeFilter, filterName)) {
showElement(cardData.card);
for (let filterCategory in checkbox) {
updateCounter(cardData, checkbox, filterCategory);
}
} else {
hideElement(cardData.card);
}
}
displayCounterValue(checkbox);
}
function handleCheckbox(target, filter) {
const { filter: category, value } = target.dataset;
if (target.checked) {
filter[category] = filter[category] || [];
filter[category].push(value);
} else {
const index = filter[category].indexOf(value);
if (index !== -1) {
filter[category].splice(index, 1);
}
if (!filter[category].length) {
delete filter[category];
}
}
}
function handleNumberType(target, rangeFilter, range) {
const { filter: category, value: extremum } = target.dataset;
const currentValue = Number(target.value);
const initialRange = range[category].init;
if (rangeFilter[category]) {
rangeFilter[category][extremum] = currentValue;
} else {
rangeFilter[category] = {
min: initialRange.min,
max: initialRange.max,
};
rangeFilter[category][extremum] = currentValue;
}
if (
rangeFilter[category].max === initialRange.max &&
rangeFilter[category].min === initialRange.min
) {
delete rangeFilter[category];
}
}
function handleFormEvents(cardsContainer, filterForm, filterData, cardsData) {
const { filters, range } = filterData;
let debounceTimer;
filterForm.addEventListener("submit", function (event) {
event.preventDefault();
});
filterForm.addEventListener("change", updateFilter);
filterForm.addEventListener("input", function (event) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
if (event.target.id === "filter-name") {
updateFilter(event, true);
}
}, 500);
});
function updateFilter(event, filterByName = false) {
const target = event.target;
const targetType = target.type;
if (filterByName) {
filters.filterName = toNormalForm(target.value);
} else if (targetType === "checkbox") {
handleCheckbox(target, filters.filter);
} else if (targetType === "number") {
handleNumberType(target, filters.rangeFilter, range);
}
filterCards(cardsContainer, filterData, cardsData);
}
}
function processUrlParameter(filterName, filterData, key, value) {
const { filters } = filterData;
if (key === "name") {
filterName.value = toNormalForm(value);
filters.filterName = value;
} else if (Object.keys(filterData.checkbox).indexOf(key) !== -1) {
const checkboxElement = document.getElementById(key + "-" + value);
if (!checkboxElement) return;
checkboxElement.checked = true;
filters.filter[key] = filters.filter[key] || [];
filters.filter[key].push(value);
} else if (key === "reverse") {
if (value === "1") {
filterData.reverse = true;
const reverseElement = document.getElementById("filter-reverse");
if (reverseElement) {
reverseElement.checked = true;
}
}
} else {
const [splitKey, extremum] = key.split("-");
if (Object.keys(filterData.range).indexOf(splitKey) !== -1) {
const rangeElement = document.getElementById(key);
if (!rangeElement) return;
rangeElement.value = value;
const rangeData = filterData.range[splitKey];
const rangeFilter = filters.rangeFilter;
if (rangeFilter[splitKey]) {
rangeFilter[splitKey][extremum] = value;
} else {
rangeFilter[splitKey] = {
min: rangeData.init.min,
max: rangeData.init.max,
};
rangeFilter[splitKey][extremum] = value;
}
}
}
}
function filterWithUrl(filterName, filterData) {
const url = new URL(window.location.href);
const { hash, search } = url;
let useParams = true;
if (hash) {
const start = ".3F";
const equal = ".3D";
const and = ".26";
const startParametersIndex = hash.indexOf(start);
if (startParametersIndex !== -1) {
const parameters = hash.slice(startParametersIndex + start.length);
parameters.split(and).forEach(function (keyValue) {
const [key, value] = keyValue.split(equal);
processUrlParameter(filterName, filterData, key, value);
});
useParams = false;
}
}
if (useParams) {
const URLparams = new URLSearchParams(search);
for (const [key, value] of URLparams.entries()) {
processUrlParameter(filterName, filterData, key, value);
}
}
}
function main_filter() {
const filterForm = document.getElementById("filter-form");
const filterName = document.getElementById("filter-name");
const cardsContainer = document.getElementById("cards-container");
const dataExtractionMapping = {
level: extractLevelData,
elem: extractElementData,
type: extractTypeData,
damage: extractDamageData,
loc: extractLocData
};
const filterData = filterInitialization(filterForm);
const cardsData = getCardsData(
cardsContainer,
filterData,
dataExtractionMapping
);
observeLanguageChange(filterName, cardsData);
openFilter();
filterWithUrl(filterName, filterData);
filterCards(cardsContainer, filterData, cardsData);
handleFormEvents(cardsContainer, filterForm, filterData, cardsData);
}
main_filter();