1import CALENDAR_DATA from '/api/calendar2025.json' with { type: 'json' }; 2import { ROUTES } from "/js/datos.js" 3 4const ROOT_HTML = await $.get('/templates/calendario2025-template.html'); 5const CALENDAR = CALENDAR_DATA.map(entry => { 6 try { 7 return { 8 ...entry, 9 'route': mapRoute(entry.route), 10 'date': parseDate(entry.date) 11 }; 12 } catch (error) { 13 console.error(error); 14 return null; 15 } 16 }).filter(entry => entry != null); 17 18 19function mapRoute(name) { 20 let route = ROUTES[name]; 21 if (route === undefined) { 22 throw new Error(`Route '${name}' not defined!`); 23 } 24 return route; 25} 26 27function parseDate(d) { 28 const [day, month, year] = d.split('/'); 29 const fullYear = 2000 + Number(year); 30 return new Date(fullYear, month - 1, day); 31} 32 33function initTable() { 34 const data = CALENDAR.map(entry => { 35 return { 36 'date': entry.date, 37 'time': entry.time, 38 'name': entry.route.name, 39 'dist': entry.route.dist, 40 'alt': entry.route.alt, 41 'dur': entry.route.dur, 42 'zone': entry.route.zone, 43 'map': { 44 'img': entry.route.map, 45 'url': entry.route.url 46 } 47 } 48 }); 49 new DataTable('#calendar-table', { 50 columns: [ 51 { 52 title: 'Fecha', 53 data: 'date', 54 type: 'date', 55 render: (date, type) => type === 'sort' ? date : toDate(date) 56 }, 57 { 58 title: 'Hora', 59 data: 'time', 60 orderable: false 61 }, 62 { 63 title: 'Ruta', 64 data: 'name' 65 }, 66 { 67 title: 'Distancia', 68 data: 'dist', 69 type: 'numeric', 70 defaultContent: 0, 71 render: (dist, type) => type === 'display' ? toDistance(dist) : dist 72 }, 73 { 74 title: 'Desnivel', 75 data: 'alt', 76 type: 'numeric', 77 defaultContent: 0, 78 render: (alt, type) => type === 'display' ? toElevation(alt) : alt 79 }, 80 { 81 title: 'Duración (est.)', 82 data: 'dur', 83 type: 'numeric', 84 defaultContent: 0, 85 render: (dur, type) => type === 'display' ? toDuration(dur) : dur 86 }, 87 { 88 title: 'Zona', 89 data: 'zone' 90 }, 91 { 92 title: 'Mapa', 93 data: 'map', 94 render: renderMap, 95 orderable: false 96 } 97 ], 98 data: data, 99 paging: false, 100 fixedHeader: true, 101 scrollY: true, 102 info: false, 103 language: { 104 url: 'https://cdn.datatables.net/plug-ins/2.3.5/i18n/es-ES.json', 105 } 106 }); 107} 108 109function toDuration(dur) { 110 if (!dur) { 111 return "---" 112 } 113 const h =Math.trunc(dur); 114 const m = Math.trunc((dur-h) * 60); 115 if (m === 0) { 116 return `${h}h` 117 } else { 118 return `${h}h ${m}m` 119 } 120} 121 122function toDistance(dist) { 123 if (!dist) { 124 return "---"; 125 } 126 return `${dist.toFixed(1)} km` 127} 128 129function toElevation(alt) { 130 if (!alt) { 131 return "---"; 132 } 133 return `${alt.toFixed(0)} m(+)` 134} 135 136function toDate(date) { 137 return date.toLocaleDateString('es-ES', { 138 day: 'numeric', 139 month: 'short', 140 year: 'numeric' 141 }).replaceAll(' ', '-'); 142} 143 144function renderMap(map) { 145 return ` 146 <a href="${map.url}"> 147 <img class="map" src="/routes/${map.img}" /> 148 </a>`; 149} 150 151export function loadCalendar() { 152 $("#main").html(ROOT_HTML); 153 154 initTable(); 155}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.