Widget:PageFilterJS/Test
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>