Widget:PageFilterJS/Test

From Granblue Fantasy Wiki
Jump to navigation Jump to search

<script type="application/javascript"> // Widget:PageFilterJS (function() {

 const addEventForChild = function(parent, eventName, childSelector, callback){
   parent.addEventListener(eventName, function(event){
     const clickedElement = event.target;
     const matchingChild = clickedElement.closest(childSelector);
     if (matchingChild)
       callback(event, matchingChild);
   });
 };
 const getPageFilterGroup = function(element) {
   if (element.pageFilterGroupID)
     return element.pageFilterGroupID;
   for (let e = element; e; e = e.parentElement)
     if (e.dataset && e.dataset.pageFilterGroupId)
       return element.pageFilterGroupID = e.dataset.pageFilterGroupId;
   return element.pageFilterGroupID = 'g0';
 };
 const getFilterElement = function(filterID, groupID) {
   for (const e of document.querySelectorAll('.page-filter-group-' + filterID)) {
     if (getPageFilterGroup(e.parentElement) == groupID)
       return e;
   }
   // TODO: remove this fallback to element ID
   var eid = document.getElementById('filter-'+ filterID);
   if (eid && getPageFilterGroup(eid) == groupID) return eid;
   
   return null;
 };
 const getFilter = function(name, groupID) {
   const filterElement = getFilterElement(name, groupID);
   const filters = filterElement ? filterElement.querySelectorAll("label.mw-ui-progressive") : "";
   if (filters.length <= 0)
     return false;
   const result = [];
   for (const filter of filters) {
     if (filter.dataset.value === '*')
       return true;
     const values = filter.dataset.value.split(';');
     for (const value of values) {
       result.push(value);
     };
   }
   return result;
 };
 const filterDefinitions = [
   ['Owned', 'short-id', ['All','*', 'Yes','true', 'No','false']],
   ['Rarity', 'filter-rarity', ['All','*', 'SSR','ssr', 'SR','sr', 'R','r']],
   ['Element', 'filter-element', ['All','*', 'Fire','fire', 'Water','water', 'Earth','earth', 'Wind','wind', 'Light','light', 'Dark','dark', 'Any','any']],
   ['Race', 'filter-race', ['All','*', 'Human','human', 'Erune','erune', 'Draph','draph', 'Harvin','harvin', 'Primal','primal', 'Unknown','unknown', 'Other','other']],
   ['Specialty', 'filter-weapon', ['All','*', 'Sabre','sabre', 'Dagger','dagger', 'Spear','spear', 'Axe','axe', 'Staff','staff', 'Gun','gun', 'Melee','melee', 'Bow','bow', 'Harp','harp', 'Katana','katana']]
 ];
 const addFilterUI = function(container) {
   if (!container) return;
   let filterGroup = getPageFilterGroup(container);
   for (const ex of document.querySelectorAll('[data-extra-filter]')) {
     if (ex.dataset && ex.dataset.extraFilter && ex.dataset.extraFilter.match(/^[a-z:A-Z0-9_ \-*()]*$/) && getPageFilterGroup(ex) == filterGroup) {
       let filterEntry = ex.dataset.extraFilter.split(':');
       filterEntry[2] = filterEntry.slice(2);
       filterDefinitions.push(filterEntry.slice(0,3));
     }
   }
   let skipFilters = {}, whitelistFilters = false;
   if (container.dataset.skipFilters) {
     for (const f of container.dataset.skipFilters.match(/[^, ]+/g)) {
       skipFilters[f] = true;
     }
   }
   if (container.dataset.onlyFilter) {
     whitelistFilters = {};
     for (const f of container.dataset.onlyFilter.match(/[^, ]+/g)) {
       whitelistFilters[f] = true;
     }
   }
   let hasFilters = false;
   for (let i = 0, g; g = filterDefinitions[i]; i++) {
     let groupName = g[0], groupData = g[1], groupList = g[2];
     if (skipFilters[groupData] || (whitelistFilters && !whitelistFilters[groupData])) continue;
     if (getFilterElement(groupData, filterGroup)) continue;
     if (groupData == 'short-id' && !(window.CollectionTrackerState && window.CollectionTrackerState.hasSavedData())) continue;
     const entries = document.querySelectorAll('[data-' + groupData + ']');
     if (entries.length <= 1) continue;
     const dataKey = groupData.replace(/-([a-z])/g, function(_, a) { return a.toUpperCase(); } );
     let hasEntry = {}, hasDistinctValues = false, firstValue = entries[0].dataset[dataKey];
     if (groupData != 'short-id') {
       for (const entry of entries) {
         if (getPageFilterGroup(entry) != filterGroup) continue;
         let ev = entry.dataset[dataKey];
         if (!ev) continue;
         if (ev != firstValue) hasDistinctValues = true;
         for (const fv of ev.match(/[^,]+/)) {
           hasEntry[fv] = true;
         }
       }
       if (!hasDistinctValues) continue;
       hasEntry['*'] = true;
     }
     let div = document.createElement('div');
     div.className = "mw-ui-button-group page-filter-group page-filter-group-" + groupData;
     let label = document.createElement('label');
     label.className = "mw-ui-button mw-ui-disabled label";
     label.appendChild(document.createTextNode(groupName));
     div.appendChild(label);
     let opts = document.createElement('div');
     opts.className = "mw-ui-button-group items";
     div.appendChild(opts);
     let hasOptions = true;
     for (let i = 0; i < groupList.length; i+=2) {
       if (!hasEntry[groupList[i+1]] && groupData != 'short-id') continue;
       let b = document.createElement('label');
       b.className = "mw-ui-button";
       b.dataset.value = groupList[i+1];
       b.appendChild(document.createTextNode(groupList[i]));
       opts.appendChild(b);
       hasOptions = hasOptions || (groupList[i+1] != '*');
     }
     if (!hasOptions) continue;
     if (hasFilters) {
       let clr = document.createElement('p');
       clr.className = 'visualClear';
       clr.style.height = '1px';
       container.appendChild(clr);
     }
     container.appendChild(div);
     hasFilters = true;
   }
   let tr = document.querySelector('tr');
   if (tr) {
     let ov = tr.style.visibility, oh = tr.offsetHeight;
     tr.style.visibility = 'collapse';
     if (tr.offsetHeight >= oh && oh > 0) {
       var style = document.createElement('style');
       style.appendChild(document.createTextNode('tr.hide {display: none}'));
       document.head.appendChild(style);
     }
     tr.style.visibility = ov;
   }
 };
 const refilter = function(updateGroup) {
   const CollectionTrackerState = window.CollectionTrackerState;
   console.time('check filters');
   const filters = {}, filterDataKeys = {};
   let elementSelectors = [];
   for (const fg of filterDefinitions) {
     const filterID = fg[1];
     const val = getFilter(filterID, updateGroup);
     if (val !== false) {
       elementSelectors.push('[data-' + filterID + ']');
       filters[filterID] = val;
       filterDataKeys[filterID] = filterID.replace(/-([a-z])/g, function(_, a) { return a.toUpperCase(); } )
     }
   }
   const filterOwned2 = typeof filters["short-id"] == "object" ? filters["short-id"][0] === 'true' : null;
   if (elementSelectors.length <= 0)
     return;
   const elementSelector = elementSelectors.join(',')
   console.timeEnd('check filters');
   console.time('select elements');
   const elements = document.querySelectorAll(elementSelector);
   console.timeEnd('select elements');
   console.time('update elements');
   for (const element of elements) {
     if (getPageFilterGroup(element) != updateGroup) continue;
     let visible = true;
     for (let fkey in filters) {
       let fval = filters[fkey];
       let ev = element.dataset[filterDataKeys[fkey]];
       if (typeof fval != 'object') continue;
       if (typeof ev == 'undefined') continue;
       if (fkey == 'short-id') {
         if (CollectionTrackerState.isObtained(ev, element.dataset.type) == filterOwned2) continue;
       } else {
         if (element.dataset[fkey] === '*') continue;
         if (fval.indexOf(ev) >= 0) continue;
         if (ev && ev.indexOf(",")) {
           let found = false;
           for (let ev2 = ev.match(/[^,]+/g), j = 0; ev2 && j < ev2.length; j++) {
             if (fval.indexOf(ev2[j]) >= 0) {
               found = true;
               break;
             }
           }
           if (found) continue;
         }
       }
       visible = false;
       break;
     }
     element.classList.toggle('hide', !visible);
   }
   console.timeEnd('update elements');
   console.time('update filterable dividers');
   let rules = document.querySelectorAll('.filterable-divider');
   for (let i = 0, j; i < rules.length; i++) {
     let p = rules[i].parentNode;
     for (j = 0; j < i; j++) {
       if (p == rules[j].parentNode) {
         break;
       }
     }
     if (j < i) continue;
     if (getPageFilterGroup(p) != updateGroup) continue;
     let hasVisibleContent = false, lastVisibleDivider = false, lastHiddenDivider = false;
     for (let e = p.firstElementChild; e; e = e.nextElementSibling) {
       if (e.classList.contains('filterable-divider')) {
         e.classList.toggle('hide', !hasVisibleContent);
         lastVisibleDivider = hasVisibleContent ? e : lastVisibleDivider;
         lastHiddenDivider = hasVisibleContent ? false : e;
         hasVisibleContent = false;
       } else if (!hasVisibleContent && !e.classList.contains('hide')) {
         if (lastVisibleDivider && lastHiddenDivider) {
           lastVisibleDivider.classList.toggle('hide', true);
           lastHiddenDivider.classList.toggle('hide', false);
           lastVisibleDivider = lastHiddenDivider;
           lastHiddenDivider = false;
         }
         hasVisibleContent = true;
       }
     }
     if (!hasVisibleContent && lastVisibleDivider) {
       lastVisibleDivider.classList.toggle('hide', true);
     }
   }
   console.timeEnd('update filterable dividers');
 };
 // Generate filter UI
 // TODO: remove ID variant
 document.querySelectorAll('#page-filter-container, .page-filter-container').forEach(addFilterUI);
 // page setup below this point
 document.querySelectorAll('.page-filter-group label.mw-ui-progressive').forEach(function(label) { label.classList.remove('mw-ui-progressive'); });
 document.querySelectorAll('.page-filter-group .items > label:first-child').forEach(function(label) { label.classList.add('mw-ui-progressive'); });
 addEventForChild(document, 'click', '.page-filter-group .items > label:not(.mw-ui-disabled)', function(event, label) {
   console.time('Click Label');
   let group = label.parentElement;
   let all = group.querySelector('label[data-value="*"]');
   const filterGroup = getPageFilterGroup(group.parentElement);
   if (label === all) {
     if (!all.classList.contains('mw-ui-progressive')) {
       group.querySelectorAll('label').forEach(function(sibling) {
         sibling.classList.remove('mw-ui-progressive');
       });
       all.classList.add('mw-ui-progressive');
     }
   } else if (group.childElementCount <= 3) {
       group.querySelectorAll('label').forEach(function(sibling) {
         sibling.classList.remove('mw-ui-progressive');
       });
       label.classList.add('mw-ui-progressive');
   } else {
     if (all) all.classList.remove('mw-ui-progressive');
     label.classList.toggle('mw-ui-progressive');
     if (group.querySelectorAll('.mw-ui-progressive').length < 1 && all)
       all.classList.add('mw-ui-progressive');
   }
   setTimeout(function() {
     console.time('Click Label Update');
     refilter(filterGroup);
     console.timeEnd('Click Label Update');
   }, 0);
   console.timeEnd('Click Label');
 });

})(); </script>