/** * * This bookmarklet extracts event data from the first four tables on a webpage, * specifically looking for tables that contain 'date', 'venue', and 'location' headers. * It processes the event data to identify special events and formats the dates. * The extracted data is then used to create an iCalendar (.ics) file, which is * automatically downloaded to the user's device. * * Functions: * - extractEventData: Extracts event data from the first four tables on the webpage. * - createICal: Creates an iCalendar (.ics) content string from the extracted event data. * - downloadICal: Initiates the download of the iCalendar (.ics) file with the given content and filename. */ javascript: (() => { function extractEventData() { let tables = document.querySelectorAll('table'); if (tables.length > 4) { tables = Array.from(tables).slice(0, 4); } const data = []; tables.forEach(table => { const headers = []; const rows = table.querySelectorAll('tr'); const firstRow = rows[0]; firstRow.querySelectorAll('td').forEach(td => { headers.push(td.textContent.trim().toLowerCase()); }); if ( headers.includes('date') && headers.includes('venue') && headers.includes('location') ) { Array.from(rows) .slice(1) .forEach(row => { const cells = row.querySelectorAll('td'); const rowData = {}; if ( Array.from(cells).some(cell => cell.querySelector('span[style*="color: #2dc26b"]') ) ) { rowData.specialEvent = true; } cells.forEach((cell, j) => { const header = headers[j]; let cellText = cell.innerHTML.replace(//gi, ', ').trim(); cellText = cellText.replace(/<\/?[^>]+(>|$)/g, '').trim(); if (header === 'date') { const month = cellText.split(' ')[0]; const year = cellText.split(',')[1].trim(); const startDay = cellText .split(' ')[1] .split(cellText.includes(' – ') ? ' – ' : '–')[0] .trim(); const endDay = cellText .split(cellText.includes(' – ') ? ' – ' : '–')[1] .split(',')[0] .trim(); rowData.startDate = `${month} ${startDay}, ${year}`; rowData.endDate = `${month} ${endDay}, ${year}`; } else if (header === 'venue') { rowData.venue = cellText; } else if (header === 'location') { rowData.location = cellText; } }); data.push(rowData); }); } }); return data; } const data = extractEventData(tables); function createICal(events) { let icalContent = 'BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//FragginWagon//P!P //Regional-Special-Championships\n'; events.forEach(event => { icalContent += 'BEGIN:VEVENT\n'; icalContent += `DTSTART:${new Date(event.startDate).toISOString().replace(/[-:]/g, '').split('.')[0]}Z\n`; icalContent += `DTEND:${new Date(event.endDate).toISOString().replace(/[-:]/g, '').split('.')[0]}Z\n`; icalContent += `SUMMARY:${event.specialEvent ? 'Special Event' : 'Regional'} - ${event.venue} \n`; icalContent += `LOCATION:${event.location}\n`; icalContent += 'END:VEVENT\n'; }); icalContent += 'END:VCALENDAR'; return icalContent; } function downloadICal(content, filename) { const blob = new Blob([content], { type: 'text/calendar' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } const newIcalContent = createICal(extractEventData()); downloadICal(newIcalContent, 'play_pokemon_regional_special_events.ics'); })();