Jump to content

User:Habst/getWikiWinners.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <nowiki>
window.meets ??= {};
window.redirs ??= {};
(async () => {
  const getRedir = async pg => {
    redirs[pg] ??= new DOMParser().parseFromString(await (await fetch(`/wiki/${pg}`)).text(), 'text/html').querySelector('title').innerText.slice(0, -12);
    return redirs[pg];
  }
  const addPipe = name => `${name}${name.includes('(') ? '|' : ''}`;
  const bullet = (yr) => winners[yr] ? `* [[${yr} USA Indoor Track and Field Championships|${yr}]]: ${winners[yr].map(w => w.ctry ? `{{fla|[[${addPipe(w.name)}]]|${w.ctry}}}` : `[[${addPipe(w.name)}]]${w.pl > 1 ? ` (${ord(w.pl)})` : ''}`).join(', ') ?? ''}` : '';
  const range = (start, end) => [...Array(end - start + 1)].map((_, i) => i + start);
  const getRed = href => new URLSearchParams(href.split('?').at(-1)).get('title').replaceAll('_', ' ');
  const ord = n => n + ['st', 'nd', 'rd'][(((n < 0 ? -n : n) + 90) % 100 - 10) % 10 - 1] || 'th';
  const removeRowspans = table => {
    const rows = Array.from(table.rows);
    for (let i = 0; i < rows.length; i++) {
      const cells = Array.from(rows[i].cells);
      for (let cell of cells) {
        const rowspan = cell.getAttribute('rowspan');
        if (rowspan && rowspan > 1) {
          const rowSpanValue = parseInt(rowspan);
          cell.removeAttribute('rowspan');
          for (let j = 1; j < rowSpanValue; j++) {
            const targetRow = rows[i + j];
            if (targetRow) {
              const newCell = cell.cloneNode(true);
              targetRow.insertBefore(newCell, targetRow.cells[cell.cellIndex]);
            }
          }
        }
      }
    }
  }

  const GEN = 'Men';
  const START = 1906;
  const END = new Date().getFullYear();
  const matchEvts = {
    '60m': ['60 metres', '40-yard dash', '40 yards', '50 m', '50 metres', '55 m', '55 metres', '50 yards', '50-yard dash', '60 yards', '60-yard dash'],
    '75y': ['75 yards', '75-yard dash'],
    '150y': ['150 yards'],
    '200m': ['200 metres', '220 yards', '220-yard dash', '200 yards', '240 yards'],
    '400m': ['400 metres', '440 yards', '440-yard dash', '300 metres', '300 m', '300 yards', '300-yard dash'],
    '600m': ['600 metres', '600 m', '500 metres', '500 m', '600 yards', '600-yard run', 'Middle-distance running'],
    '800m': ['800 metres', '880-yard dash', '880 yards', '880-yard run', '800 m', '1000 m', '1000 metres', '1000 yards', '1000-yard run'],
    'Mile': ['Mile run', 'Mile', '1500 m', '1500 metres'],
    '3000m': ['3000 metres', 'Two miles', '2 miles', '3 miles', '5000 metres', '5000 m'],
    '5M': ['5 miles', 'Five miles', '5-mile run', 'Five-mile run'],
    '60mH': ['60 metres hurdles', '60 yards hurdles', '60-yard hurdles', '55 metres hurdles', '50 metres hurdles', '50 yards hurdles', '50-yard hurdles', '80 metres hurdles', '70 yards hurdles', '70-yard hurdles'],
    '220yH': ['220 yards hurdles', 'Low hurdles'],
    '440yH': ['440 yards hurdles', '300 yards hurdles', '400 metres hurdles'],
    '3000mSC': ['3000 metres steeplechase', '3000 m steeplechase', '2 miles steeplechase', 'Steeplechase (athletics)'],
    HJ: ['High jump'],
    SHJ: ['Standing high jump'],
    LJ: ['Long jump', 'Standing long jump'],
    SP: ['Shot put'],
    DT: ['Discus throw'],
    TJ: ['Triple jump'],
    STJ: ['Standing triple jump'],
    PV: ['Pole vault'],
    PVD: ['Pole vault for distance', 'Fierljeppen'],
    WT: ['Weight throw', 'Weight throw for height'],
    'MileW': ['Mile walk', '1500 m walk', '1500 metres walk', '1500 metres race walk', '1500 metres racewalk', '1500 m race walk', '1500 m racewalk'],
    '3000mW': ['3000 metres race walk', '2 miles race walk', '2 miles walk'],
    '5000mW': ['5000 metres race walk', '3 miles race walk', '3 miles walk'],
    PEN: ['Women\'s Pentathlon'],
    HEP: ['Heptathlon'],
  }['HEP'];
  const trackOrField = 'field';
  const winners = {};
  for (const y of range(START, END)) {
    meets[y] ??= await (await fetch(`/wiki/${y}_USA_Indoor_Track_and_Field_Championships`)).text();
    const doc = new DOMParser().parseFromString(meets[y], 'text/html');
    const tables = [GEN, `${GEN}\\'s_${trackOrField}`].map(id => doc.querySelector(`#${id}`)?.parentElement.nextSibling.nextSibling).filter(x => x?.tagName === 'TABLE');
    for (const table of tables) removeRowspans(table);
    const trs = tables.flatMap(table => [...table?.querySelectorAll('tr') ?? []]);
    const evtRows = [];
    for (const tr of trs) {
      const tds = tr.querySelectorAll('td');
      const rowEvtA = tds[0]?.querySelector('a');
      const rowEvt = rowEvtA?.href.split('/').at(-1).split('#')[0];
      if (!rowEvt) continue;
      const evt = rowEvtA.classList.contains('new') ? getRed(rowEvt) : await getRedir(rowEvt);
      if (matchEvts.includes(evt)) evtRows.push(tds);
    }
    for (const tds of evtRows) {
      const getWinner = async (idx) => {
        const winnerA = tds[idx].querySelector('a');
        const winnerHref = winnerA?.href.split('/').at(-1);
        if (!winnerHref) return;
        const name = winnerA.classList.contains('new') ? getRed(winnerHref) : await getRedir(winnerHref);
        const ctry = tds[idx].querySelector('.flagicon') ? tds[idx].querySelector('abbr').innerText : undefined;
        return { name, ctry, pl: (idx + 1) / 2 };
      }
      winners[y] ??= [];
      for (let i = 1; i <= 5; i += 2) {
        const winner = await getWinner(i);
        if (!winner) continue;
        if (!winners[y].find(w => w.name === winner.name && w.pl === winner.pl))
          winners[y].push(winner);
        //if (!winner.ctry) break;
      }
    }
    if (!winners[y]) continue;
    winners[y].sort((a, b) => a.pl - b.pl);
    for (const winner of winners[y]) {
      const idx = winners[y].findIndex(w => w.name === winner.name);
      const getNextIdx = () => winners[y].slice(idx + 1).findIndex(w => w.name === winner.name);
      while (getNextIdx() !== -1) winners[y].splice(getNextIdx(), 1);
    }
    const topNativeFinish = [...Array(3)].map((_, i) => i + 1).find(num => winners[y].find(ath => ath.pl === num && !ath.ctry));
    if (!topNativeFinish) console.log('no native finish', y);
    winners[y] = winners[y].filter(ath => {
      if (ath.pl > topNativeFinish) return false;
      if (ath.pl > 1 && ath.ctry) return false;
      return true;
    });
  }
  const abbrEvt = matchEvts[0].replace('metres', 'm').toLowerCase();
  const out = `
{{Navbox
 | name = USA Indoor Track and Field Championships winners in ${GEN.toLowerCase()}'s ${abbrEvt}
 | title = [[USA Indoor Track and Field Championships]] winners in ${GEN.toLowerCase()}'s [[${abbrEvt}]]
 | state = {{{state<includeonly>|collapsed</includeonly>}}}
 | listclass = hlist
 | nowrapitems = yes

 | titlestyle = background: #F0DC82
 | groupstyle = text-align: center; background: #F0DC82

 | group1 = ${START}–1979<br />{{small|[[Amateur Athletic Union]]}}
 | list1 =

${range(START, 1979).map(bullet).filter(x => x).join('\n')}

 | group2 = 1980–1992<br />{{small|[[The Athletics Congress]]}}
 | list2 =

${range(1980, 1992).map(bullet).filter(x => x).join('\n')}

 | group3 = 1993–present<br />{{small|[[USA Track & Field]]}}
 | list3 =

${range(1993, END).map(bullet).filter(x => x).join('\n')}

|group4 = Notes
|list4 =
{{allow wrap|* Distances have varied as follows: 440 yards (1959–1986), 400 meters (1987–date) alternating with 300 meters in odd numbered years starting 2015}}

}}<noinclude>
{{collapsible option}}
[[Category:United States indoor track and field champions navigational boxes|${abbrEvt[0].toUpperCase() + abbrEvt.slice(1)}, ${GEN.toLowerCase()}]]
</noinclude>`
  console.log(out);
})();
// </nowiki>