Rendre cliquables les adresses écrites dans l'agenda
« infos et inscriptions sur https://installparty.alpinux.org » s'affichait en texte mort dans la fiche d'un événement : à recopier à la main. Les adresses du descriptif et du lieu deviennent des liens, la ponctuation qui termine la phrase restant en dehors. Le texte vient du calendrier, donc de quelqu'un qui écrit du texte et non du HTML : il est échappé avant d'être lié, et les titres et lieux des cartes le sont aussi, ce qui n'était pas le cas jusqu'ici. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JYfYUZRcJmmEWJwAxZb4o2
This commit is contained in:
parent
3baa10db65
commit
ddf3f79e7a
1 changed files with 34 additions and 8 deletions
|
|
@ -437,6 +437,8 @@
|
|||
}
|
||||
|
||||
.ev-modal-body { font-size: .92rem; line-height: 1.6; color: #444; }
|
||||
.ev-modal-body a { color: #1a6bbf; word-break: break-word; }
|
||||
.ev-modal-body a:hover { text-decoration: none; }
|
||||
|
||||
.event-date {
|
||||
font-size: .82rem;
|
||||
|
|
@ -1088,6 +1090,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Le calendrier est saisi par des humains : son texte est du texte, jamais du HTML. */
|
||||
function echapper(texte) {
|
||||
return String(texte == null ? '' : texte)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
/* Rend cliquables les adresses écrites dans un descriptif. Le texte reçu est déjà
|
||||
échappé — le motif s'arrête donc avant une balise — et la ponctuation qui termine
|
||||
une phrase reste en dehors du lien. */
|
||||
function avecLiens(texteEchappe) {
|
||||
return texteEchappe.replace(/https?:\/\/[^\s<]+/g, function(url) {
|
||||
var queue = '';
|
||||
var fin = /[.,;:!?»)\]]+$/.exec(url);
|
||||
if (fin) {
|
||||
queue = fin[0];
|
||||
url = url.slice(0, url.length - queue.length);
|
||||
}
|
||||
return '<a href="' + url + '" target="_blank" rel="noopener">' + url + '</a>' + queue;
|
||||
});
|
||||
}
|
||||
|
||||
function showDetail(date, evs, el) {
|
||||
el.hidden = false;
|
||||
el.innerHTML = '<strong>' +
|
||||
|
|
@ -1097,9 +1123,9 @@
|
|||
var time = e.allDay ? '' :
|
||||
' <span class="ev-loc">' +
|
||||
e.start.toLocaleTimeString('fr-FR', { hour:'2-digit', minute:'2-digit' }) + '</span>';
|
||||
return '<li>' + e.title + time +
|
||||
return '<li>' + echapper(e.title) + time +
|
||||
(e.desc ? ' <span class="ev-has-desc" title="Descriptif disponible">ℹ</span>' : '') +
|
||||
(e.location ? '<span class="ev-loc"> — ' + e.location + '</span>' : '') +
|
||||
(e.location ? '<span class="ev-loc"> — ' + echapper(e.location) + '</span>' : '') +
|
||||
'</li>';
|
||||
}).join('') + '</ul>';
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
|
|
@ -1120,11 +1146,11 @@
|
|||
var descHtml = '';
|
||||
if (ev.desc) {
|
||||
descHtml = '<p style="margin-top:.8rem;color:#555;font-size:.88rem;white-space:pre-line">' +
|
||||
ev.desc.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') + '</p>';
|
||||
avecLiens(echapper(ev.desc)) + '</p>';
|
||||
}
|
||||
body.innerHTML =
|
||||
'<p>📅 ' + dateStr + '</p>' +
|
||||
(ev.location ? '<p style="margin-top:.4rem">📍 ' + ev.location + '</p>' : '') +
|
||||
(ev.location ? '<p style="margin-top:.4rem">📍 ' + avecLiens(echapper(ev.location)) + '</p>' : '') +
|
||||
descHtml;
|
||||
modal.hidden = false;
|
||||
document.getElementById('ev-modal').querySelector('.ev-modal-close').focus();
|
||||
|
|
@ -1156,8 +1182,8 @@
|
|||
: ev.start.toLocaleTimeString('fr-FR', { hour:'2-digit', minute:'2-digit' }) +
|
||||
(ev.end ? ' – ' + ev.end.toLocaleTimeString('fr-FR', { hour:'2-digit', minute:'2-digit' }) : '')) +
|
||||
'</div>' +
|
||||
'<div class="event-title">' + ev.title + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + ev.location + '</div>' : '');
|
||||
'<div class="event-title">' + echapper(ev.title) + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + echapper(ev.location) + '</div>' : '');
|
||||
card.addEventListener('click', function() { openModal(ev); });
|
||||
container.appendChild(card);
|
||||
});
|
||||
|
|
@ -1179,8 +1205,8 @@
|
|||
card.innerHTML =
|
||||
(ev.desc ? '<span class="ev-has-desc" title="Descriptif disponible">ℹ</span>' : '') +
|
||||
'<div class="event-date">' + fmtDate(ev.start, ev.allDay) + '</div>' +
|
||||
'<div class="event-title">' + ev.title + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + ev.location + '</div>' : '');
|
||||
'<div class="event-title">' + echapper(ev.title) + '</div>' +
|
||||
(ev.location ? '<div class="event-where">📍 ' + echapper(ev.location) + '</div>' : '');
|
||||
card.addEventListener('click', function() { openModal(ev); });
|
||||
container.appendChild(card);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue