MediaWiki:Script/Filter.js : Différence entre versions

Ligne 177 : Ligne 177 :
 
     }
 
     }
 
     cardInformation.data.reverse();
 
     cardInformation.data.reverse();
 +
    filterInformation.reverse = false;
 
   }
 
   }
 
    
 
    

Version du 1 septembre 2023 à 00:08

function hideElement(element) {
  element.classList.add("tabber-noactive");
}


function showElement(element) {
  element.classList.remove("tabber-noactive");
}


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 addValueToObject(object, key, value) {
          
  if (object[key]) {
    object[key].push(value);
  } else {
    object[key] = [value];
  }
}


function loading() {
  
  var mainContainer = document.getElementById("hide-all");
  var loadingAnimation = document.getElementById("loading-animation");

  mainContainer.classList.remove("tabber-noactive");
  loadingAnimation.classList.add("tabber-noactive");
}


function handleDropdowns(filterInformation) {
  
  var form = filterInformation.form;
  var activeButton = null;

  function toggleDropdown(button, dropdownMenu) {
    if (button === activeButton) {
      hideElement(dropdownMenu);
      activeButton = null;
    } else {
      if (activeButton) {
        hideElement(activeButton.nextElementSibling);
      }
      showElement(dropdownMenu);
      activeButton = button;
    }
  }

  
  function closeDropdowns() {
    if (activeButton) {
      hideElement(activeButton.nextElementSibling);
      activeButton = null;
    }
  }

  form.addEventListener('click', function(event) {

    var target = event.target;
    var button = target.closest('button');
    
    if (button) {
      
      var dropdownMenu = button.nextElementSibling;
      
      toggleDropdown(button, dropdownMenu);
      
    } else if (!target.closest('.dropdown-menu')) {
      closeDropdowns();
    }
  });

  document.addEventListener('click', function(event) {
    if (!form.contains(event.target)) {
      closeDropdowns();
    }
  });
}


function incrementCounter(counterElement, counterValue) {

  if (counterValue === 0) {
    showElement(counterElement);
  }

  counterElement.textContent = counterValue + 1;
}


function decrementCounter(counterElement, counterValue) {

  if (counterValue === 1) {
    hideElement(counterElement);
  }

  counterElement.textContent = counterValue - 1;
}


function filterItems(filterInformation, cardInformation) {
  
  
  function showCounter() {
    var checkbox = filterInformation.checkbox
    
    for (var filterName in checkbox) {
      var values = checkbox[filterName].values
      
      for (var filterValue in values) {
        var span = values[filterValue].span;
        
        span.textContent = " (" + values[filterValue].value + ")";
        values[filterValue].value = 0;
      }
    }
  }
  
  
  function addCount(cardParameters, checkboxNames, parameter) {
    cardParameters[parameter].split(' ').forEach(function(cardValue) {
      checkboxNames[parameter].values[cardValue].value += 1;
    });
  }
 
  
  function isObjectValuesInRangeFilter(parameters, rangeFilter) {
    return Object.keys(rangeFilter).every(function(property) {
      var propertyValue = parameters[property];
      return rangeFilter[property].min <= propertyValue && rangeFilter[property].max >= propertyValue;
    });
  }
  
  
  function filterByName(parameters, filterName) {
    if (filterName) {
      return parameters.name.indexOf(filterName) !== -1;
    }
    return true;
  }
  
  
  function isObjectValuesInFilter(parameters, filter) {
    return Object.keys(filter).every(function(property) {
      return parameters[property].split(' ').some(function(value) {
        return filter[property].indexOf(value) !== -1;
      });
    });
  }
  
  
  function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) {
    return isObjectValuesInFilter(parameters, filter) && filterByName(parameters, filterName) && isObjectValuesInRangeFilter(parameters, rangeFilter);
  }
  
  var filter = filterInformation.filters.filter;
  var rangeFilter = filterInformation.filters.rangeFilter;
  var filterName = filterInformation.filters.filterName;
  var checkboxNames = filterInformation.checkbox;
  var listToFilter = cardInformation.listToFilter.children;
  var cardData = cardInformation.data;
  
  if (filterInformation.reverse) {
    var parent = cardInformation.listToFilter;
    for (var reverseIndex = 1; reverseIndex < listToFilter.length; reverseIndex++) {
      parent.insertBefore(listToFilter[reverseIndex], parent.firstChild);
    }
    cardInformation.data.reverse();
    filterInformation.reverse = false;
  }
  
  for (var cardIndex = 0; cardIndex < listToFilter.length; cardIndex++) {
    var card = listToFilter[cardIndex];
    var cardParameters = cardData[cardIndex];
    if (isObjectValuesInFilters(cardParameters, filter, rangeFilter, filterName)) {
      showElement(card);
      for (var parameter in checkboxNames) {
        addCount(cardParameters, checkboxNames, parameter);
      }
    } else {
      hideElement(card);
    }
  }
  showCounter();
}


function updateFilterObject(filterInformation, cardInformation) {
  
  
  function updateFilter(event, filterByName = false) {

    
    function handleNumberType(target) {
      
      var [filterName, extremum] = target.id.split("-");
      var currentValue = Number(target.value);
      var counterElement = filterInformation.range[filterName].counter;
      var counterValue = Number(counterElement.textContent);
      var initialRange = filterInformation.range[filterName].init;
      var rangeFilter = filterInformation.filters.rangeFilter;
      
      if (rangeFilter[filterName]) {
        rangeFilter[filterName][extremum] = currentValue;
      } else {
        incrementCounter(counterElement, counterValue);
        rangeFilter[filterName] = {min: initialRange.min, max: initialRange.max};
        rangeFilter[filterName][extremum] = currentValue;
      }
      if ((rangeFilter[filterName].max === initialRange.max) && (rangeFilter[filterName].min === initialRange.min)) {
        decrementCounter(counterElement, counterValue);
        delete rangeFilter[filterName];
      }
    }
    
    
    function handleCheckbox(target) {
      
      var filterName = target.id.split("-")[0];
      var filter = filterInformation.filters.filter;
      var filterValue = target.dataset.filter;
      var counterElement = filterInformation.checkbox[filterName].counter;
      var counterValue = Number(counterElement.textContent);
      
      if (target.checked) {
        incrementCounter(counterElement, counterValue);
        addValueToObject(filter, filterName, filterValue);
        
      } else {
        decrementCounter(counterElement, counterValue);
        var index = filter[filterName].indexOf(filterValue);
        if (index !== -1) {
          if (filter[filterName].length === 1) {
            delete filter[filterName];
          } else {
            filter[filterName].splice(index, 1);
          }
        }
      }
    }
    
    var target = event.target;
    
    if (filterByName) {
      filterInformation.filters.filterName = toNormalForm(target.value);
    } else {
      var type = target.type;
      
      if (type === "number") {
        handleNumberType(target);
      } else if (type === "checkbox") {
        if (target.id === "filter-reverse") {
          filterInformation.reverse = true;
        } else {
          handleCheckbox(target);
        }
      }
    }
    filterItems(filterInformation, cardInformation);
  }
  
  var form = filterInformation.form;
  var debounceTimer;
  
  form.addEventListener("submit", function(event) {
    event.preventDefault();
  });
  
  form.addEventListener("change", function(event) {
    updateFilter(event);
  });
  
  form.addEventListener("input", function(event) {
    if (event.target.id === "filter-name") {
      clearTimeout(debounceTimer);
      debounceTimer = setTimeout(function() {
        updateFilter(event, true);
      }, 500);
    }
  });
}


function filterInitialization() {
  
  function createSpan() {
    var span = document.createElement("span");
    span.style.color = '#9F9F9F';
    span.style.fontSize = '12px';
    return span;
  }
  
  
  function handlefilterParameters(filterParameters, param, filterName) {
    
    if (param === "levels") {
      addValueToObject(filterParameters, "levels", filterName)
      
    } else if (param.startsWith("replace_")) {
      
      var replace = param.split("replace_")[1].replace("_", " ");
      
      if (!filterParameters["replace"]) {
        filterParameters["replace"] = {};
      }
      filterParameters["replace"][filterName] = {"value": replace};
      
    } else if (param === "element") {
      filterParameters["element"] = filterName;
    }
  }
  
  var form = document.getElementById("filter-form");
  var filters = { filterName: "", filter: {}, rangeFilter: {} };
  var filterInformation = { form: form, filters: filters, range: {}, checkbox: {}, reverse: false };
  var allButton = form.querySelectorAll("button");
  var filterParameters = {};

  allButton.forEach(function(button) {
    
    var buttonSibling = button.nextElementSibling;
    
    if (!buttonSibling) return;
    
    var filterName = buttonSibling.id;
    var counter = buttonSibling.nextElementSibling;
    var param = buttonSibling.dataset.param;
    
    if (!filterName || !counter || !param) return;

    var infoType = filterName.endsWith("-range") ? "range" : "checkbox";
    var filterName = filterName.replace("-range", "")
    var filterObj = filterInformation[infoType][filterName] = { counter: counter };
    
    handlefilterParameters(filterParameters, param, filterName);
    
    if (infoType === "checkbox") {
      filterObj.values = {};
      var allInput = buttonSibling.querySelectorAll("input");
      allInput.forEach(function(input) {
        var filterValue = input.dataset.filter;
        
        if (!filterValue) return;

        var span = createSpan();
        input.parentElement.appendChild(span);
        filterObj.values[filterValue] = { value: 0, span: span};
      });
    } else if (infoType === "range") {
      filterObj.init = {}
      filterObj.init.min = Number(buttonSibling.children[0].firstChild.min);
      filterObj.init.max = Number(buttonSibling.children[0].firstChild.max);
    }
  });

  return [filterInformation, filterParameters];
}


function getCardInformation(filterParameters) {
  
  function createDataSelector(name) {
    return "[data-" + name + "]"
  }
  
  var listToFilter = document.getElementById("list-to-filter");
  var listToFilterChildren = listToFilter.children;
  var allCardInformation = [];
  var filterLevelsNames = filterParameters["levels"];
  var filterWithReplace = filterParameters["replace"];
  var filterElementName = filterParameters["element"];
  
  if (filterLevelsNames) {
    var [level0, level1] = filterLevelsNames;
    var levelsSelector = createDataSelector(level0);
  }
  
  if (filterWithReplace) {
    for (var replaceName in filterWithReplace) {
      filterWithReplace[replaceName].selector = createDataSelector(replaceName);
    }
  }
  
  if (filterElementName) {
    var elementSelector = createDataSelector(filterElementName);
  }

  for (var cardIndex = 0; cardIndex < listToFilterChildren.length; cardIndex++) {
    
    var card = listToFilterChildren[cardIndex];
    var cardInformation = {};
    var cardName = card.querySelector("[data-name]").textContent;
    cardInformation.name = toNormalForm(cardName);
    
    if (filterLevelsNames) {
      var levelsElement = card.querySelector(levelsSelector);
      var [levelValue0, levelValue1] = levelsElement.textContent.slice(1, -1).split(", ");
      cardInformation[level0] = Number(levelValue0);
      cardInformation[level1] = removeAccent(levelValue1);
    }
    
    if (filterElementName) {
      var elementChild = card.querySelector(elementSelector).children;
      var elementValue = "";
      if (elementChild.length) {
        for (var elementIndex = 0; elementIndex < elementChild.length; elementIndex++) {
          elementValue += elementChild[elementIndex].title + " ";
        }
      }
      elementValue = elementValue.trim() || "Aucun";
      cardInformation[filterElementName] = removeAccent(elementValue);
    }
      
    if (filterWithReplace) {
      for (var replaceName in filterWithReplace) {
        var replaceInformation = filterWithReplace[replaceName];
        var replaceValue = card.querySelector(replaceInformation.selector).textContent.replace(replaceInformation.value, '');
        cardInformation[replaceName] = removeAccent(replaceValue)
      }
    }
      
    allCardInformation.push(cardInformation);
  }
  allCardInformation = { listToFilter: listToFilter, data: allCardInformation };
  
  return allCardInformation;
}


function filterWithUrl(filterInformation) {
  
  function processParameter(key, value, filters) {

    if (key === "name") {
      var filterName = document.getElementById("filter-name");
      filterName.value = toNormalForm(value);
      filters.filterName = value;
    } else if (Object.keys(filterInformation.checkbox).indexOf(key) !== -1) {
      var checkboxElement = document.getElementById(key + "-" + value);
      if (!checkboxElement) return;
      var counterElement = filterInformation.checkbox[key].counter;
      var counterValue = Number(counterElement.textContent);
      incrementCounter(counterElement, counterValue);
      checkboxElement.checked = true;
      addValueToObject(filters.filter, key, value);
    } else if (key === "reverse") {
      if (value === "1") {
        filterInformation.reverse = true;
        var reverseElement = document.getElementById("filter-reverse");
        if (reverseElement) {
          reverseElement.checked = true;
        }
      }
    } else {
      var splitKey = key.split("-")[0];
      if (Object.keys(filterInformation.range).indexOf(splitKey) !== -1) {
        var rangeElement = document.getElementById(key);
        if (!rangeElement) return;
        rangeElement.value = value;
        var rangeInformation = filterInformation.range[splitKey];
        incrementCounter(rangeInformation.counter, 0);
        var extremum = key.split("-")[1];
        var rangeFilter = filters.rangeFilter;
        if (rangeFilter[splitKey]) {
          rangeFilter[splitKey][extremum] = value;
        } else {
          rangeFilter[splitKey] = { min: rangeInformation.init.min, max: rangeInformation.init.max };
          rangeFilter[splitKey][extremum] = value;
        }
      }
    }
  }
  
  var url = new URL(window.location.href);
  var urlHash = url.hash;
  var useParams = true;
  var filters = filterInformation.filters;

  if (urlHash) {
    
    var start = ".3F";
    var equal = '.3D';
    var and = '.26';
    var startParametersIndex = urlHash.indexOf(start);

    if (startParametersIndex !== -1) {
      
      useParams = false;
      var parameters = urlHash.slice(startParametersIndex + start.length);

      parameters.split(and).forEach(function(keyValue) {
        var [key, value] = keyValue.split(equal);
        processParameter(key, value, filters);
      });
    }
  }
  
  if (useParams) {
    var URLparams = new URLSearchParams(url.search);

    for (var [key, value] of URLparams.entries()) {
      processParameter(key, value, filters);
    }
  }
}

    
(function(){
  
  var [filterInformation, filterParameters] = filterInitialization();
  var cardInformation = getCardInformation(filterParameters);

  handleDropdowns(filterInformation);
  filterWithUrl(filterInformation);
  filterItems(filterInformation, cardInformation);
  updateFilterObject(filterInformation, cardInformation);
  loading();
})();