- Posts: 37
Question
Age at event
- godzil
-
Topic Author
- Offline
- New Member
-
Less
More
2 months 1 day ago - 2 months 1 day ago #116610
by godzil
Regards
Adrian
webtrees.cytr.us
Age at event was created by godzil
Hi,
I recall there was porbably buil-it option do display individual age at event. Now i cant't find it in webtrees nor any module.
I generated simple JS script pasted in Custom CSS and JS but wondering about another solution
if you want to use this script you need to translate it to your local language - i belive any AI will change phrases for you
I recall there was porbably buil-it option do display individual age at event. Now i cant't find it in webtrees nor any module.
I generated simple JS script pasted in Custom CSS and JS but wondering about another solution
if you want to use this script you need to translate it to your local language - i belive any AI will change phrases for you
Code:
<script>
(function () {
'use strict';
if (window.__wtAgeAtEventInjected) return;
window.__wtAgeAtEventInjected = true;
const MONTHS = {
stycznia: 0, styczen: 0, styczeń: 0, styczniem: 0,
lutego: 1, luty: 1, lutym: 1,
marca: 2, marzec: 2, marcem: 2,
kwietnia: 3, kwiecien: 3, kwiecień: 3, kwietniem: 3,
maja: 4, maj: 4, majem: 4,
czerwca: 5, czerwiec: 5, czerwcem: 5,
lipca: 6, lipiec: 6, lipcem: 6,
sierpnia: 7, sierpien: 7, sierpień: 7, sierpniem: 7,
wrzesnia: 8, wrzesien: 8, września: 8, wrzesień: 8, wrzesniem: 8, wrześniem: 8,
pazdziernika: 9, pazdziernik: 9, października: 9, październik: 9, pazdziernikiem: 9, październikiem: 9,
listopada: 10, listopad: 10, listopadem: 10,
grudnia: 11, grudzien: 11, grudzień: 11, grudniem: 11
};
function normalize(text) {
return (text || '')
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/\u00a0/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
function parseExactPolishDate(text) {
const src = normalize(text).replace(/\*/g, '');
let m = src.match(/^(\d{1,2})\s+([\p{L}]+)\s+(\d{4})$/u);
if (m) {
const day = Number(m[1]);
const month = MONTHS[normalize(m[2])];
const year = Number(m[3]);
if (month !== undefined) return new Date(year, month, day);
}
m = src.match(/^([\p{L}]+)\s+(\d{4})$/u);
if (m) {
const month = MONTHS[normalize(m[1])];
const year = Number(m[2]);
if (month !== undefined) return new Date(year, month, 15);
}
m = src.match(/^(\d{4})$/);
if (m) return new Date(Number(m[1]), 6, 1);
return null;
}
function parseDateExpression(text) {
const src = normalize(text).replace(/\*/g, '');
let m;
m = src.match(/^(przed|bef|before)\s+(.+)$/);
if (m) {
const date = parseExactPolishDate(m[2]);
if (date) return { kind: 'before', date };
}
m = src.match(/^(po|aft|after)\s+(.+)$/);
if (m) {
const date = parseExactPolishDate(m[2]);
if (date) return { kind: 'after', date };
}
m = src.match(/^(okolo|około|abt|about|circa|ca\.?)\s+(.+)$/);
if (m) {
const date = parseExactPolishDate(m[2]);
if (date) return { kind: 'about', date };
}
m = src.match(/^(miedzy|między|pomiedzy|pomiędzy|bet|between)\s+(.+?)\s+(a|i|and)\s+(.+)$/);
if (m) {
const start = parseExactPolishDate(m[2]);
const end = parseExactPolishDate(m[4]);
if (start && end) return { kind: 'between', start, end };
}
m = src.match(/^(od|from)\s+(.+?)\s+(do|to)\s+(.+)$/);
if (m) {
const start = parseExactPolishDate(m[2]);
const end = parseExactPolishDate(m[4]);
if (start && end) return { kind: 'fromto', start, end };
}
const exact = parseExactPolishDate(src);
if (exact) return { kind: 'exact', date: exact };
return null;
}
function diffAge(birth, event) {
let years = event.getFullYear() - birth.getFullYear();
let months = event.getMonth() - birth.getMonth();
let days = event.getDate() - birth.getDate();
if (days < 0) {
months -= 1;
const prevMonthLastDay = new Date(event.getFullYear(), event.getMonth(), 0).getDate();
days += prevMonthLastDay;
}
if (months < 0) {
years -= 1;
months += 12;
}
return { years, months, days };
}
function diffDays(start, end) {
const oneDay = 24 * 60 * 60 * 1000;
const startDate = new Date(start.getFullYear(), start.getMonth(), start.getDate());
const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
return Math.round((endDate - startDate) / oneDay);
}
function pluralDays(n) {
if (n === 1) return 'dzień';
return 'dni';
}
function formatExactAge(age, birthDate, eventDate) {
if (age.years < 0) return null;
if (age.years === 0 && age.months === 0) {
const days = diffDays(birthDate, eventDate);
if (days === 0) return 'w dniu urodzenia';
return `${days} ${pluralDays(days)}`;
}
if (age.years === 0) {
if (age.days > 0) return `${age.months} mies. ${age.days} ${pluralDays(age.days)}`;
return `${age.months} mies.`;
}
if (age.months === 0) {
if (age.days > 0) return `${age.years} l. ${age.days} ${pluralDays(age.days)}`;
return `${age.years} l.`;
}
if (age.days > 0) return `${age.years} l. ${age.months} mies. ${age.days} ${pluralDays(age.days)}`;
return `${age.years} l. ${age.months} mies.`;
}
function formatAgeFromExpression(birthDate, expr) {
if (!expr) return null;
if (expr.kind === 'exact') {
const value = formatExactAge(diffAge(birthDate, expr.date), birthDate, expr.date);
return value ? `wiek: ${value}` : null;
}
if (expr.kind === 'about') {
const value = formatExactAge(diffAge(birthDate, expr.date), birthDate, expr.date);
return value ? `wiek: ok. ${value}` : null;
}
if (expr.kind === 'before') {
const value = formatExactAge(diffAge(birthDate, expr.date), birthDate, expr.date);
return value ? `wiek: maks. ${value}` : null;
}
if (expr.kind === 'after') {
const value = formatExactAge(diffAge(birthDate, expr.date), birthDate, expr.date);
return value ? `wiek: min. ${value}` : null;
}
if (expr.kind === 'between' || expr.kind === 'fromto') {
const startValue = formatExactAge(diffAge(birthDate, expr.start), birthDate, expr.start);
const endValue = formatExactAge(diffAge(birthDate, expr.end), birthDate, expr.end);
if (startValue && endValue) return `wiek: ${startValue} – ${endValue}`;
}
return null;
}
function getFactLabel(row) {
return normalize(row.querySelector('.wt-fact-label')?.textContent || '');
}
function getFactRows() {
return Array.from(document.querySelectorAll('tr')).filter(row => row.querySelector('.wt-fact-label'));
}
function findBirthDate(rows) {
for (const row of rows) {
const label = getFactLabel(row);
if (!/(^urodzenie$|^birth$)/.test(label)) continue;
const dateNodes = row.querySelectorAll('.wt-fact-date-age .date');
for (const node of dateNodes) {
const txt = (node.textContent || '').trim();
const parsed = parseDateExpression(txt);
if (parsed?.kind === 'exact') return parsed.date;
if (parsed?.kind === 'about') return parsed.date;
}
}
return null;
}
function findEventDateExpression(row) {
const dateNodes = row.querySelectorAll('.wt-fact-date-age .date');
for (const node of dateNodes) {
const txt = (node.textContent || '').trim();
const parsed = parseDateExpression(txt);
if (parsed) return parsed;
}
return null;
}
function insertAge(row, birthDate) {
if (row.querySelector('.wt-age-at-event')) return;
const label = getFactLabel(row);
if (/(^urodzenie$|^birth$)/.test(label)) return;
const expr = findEventDateExpression(row);
if (!expr) return;
const text = formatAgeFromExpression(birthDate, expr);
if (!text) return;
const labelNode = row.querySelector('th .wt-fact-label');
if (!labelNode || !labelNode.parentNode) return;
const line = document.createElement('div');
line.className = 'wt-age-at-event';
line.textContent = text;
line.style.display = 'block';
line.style.fontSize = '0.875rem';
line.style.color = 'var(--fgColor-default, #9198a1)';
line.style.lineHeight = '1.35';
line.style.marginTop = '0.2rem';
line.style.fontWeight = 'var(--bs-body-font-weight)';
labelNode.parentNode.insertBefore(line, labelNode.nextSibling);
}
function renderAges() {
const rows = getFactRows();
if (!rows.length) return false;
const birthDate = findBirthDate(rows);
if (!birthDate) return false;
rows.forEach(row => insertAge(row, birthDate));
return true;
}
function boot() {
renderAges();
const observer = new MutationObserver(() => {
renderAges();
});
observer.observe(document.body, { childList: true, subtree: true });
let tries = 0;
const timer = setInterval(() => {
renderAges();
tries += 1;
if (tries > 20) clearInterval(timer);
}, 500);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}
})();
</script>
Regards
Adrian
webtrees.cytr.us
Last edit: 2 months 1 day ago by godzil.
Please Log in or Create an account to join the conversation.
- kiwi
-
- Offline
- Platinum Member
-
1 month 4 weeks ago #116611
by kiwi
Nigel
www.our-families.info
Replied by kiwi on topic Age at event
Webtrees does still display age at an event, but just not all events.
This forum discussion provides a much simpler solution if that is your problem:
www.webtrees.net/index.php/forum/4-custo...9860-age-of-resident
This forum discussion provides a much simpler solution if that is your problem:
www.webtrees.net/index.php/forum/4-custo...9860-age-of-resident
Nigel
www.our-families.info
Please Log in or Create an account to join the conversation.
- bertkoor
-
- Offline
- Platinum Member
-
- Greetings from Utrecht, Holland
1 month 4 weeks ago - 1 month 4 weeks ago #116612
by bertkoor
github.com/BertKoor/wt-module-custom-views
Also, Greg proposed an imho elegant solution:
stamboom.BertKoor.nl runs on webtrees v2.2.6
Replied by bertkoor on topic Age at event
Since then I've published a module which facilitates doing that small change in fact-date.phtml and not losing it on an update.This forum discussion provides a much simpler solution if that is your problem:
www.webtrees.net/index.php/forum/4-custo...9860-age-of-resident
github.com/BertKoor/wt-module-custom-views
Also, Greg proposed an imho elegant solution:
I'll try to implement that and submit a PR for it.How about suppressing all "aged 0"?
stamboom.BertKoor.nl runs on webtrees v2.2.6
Last edit: 1 month 4 weeks ago by bertkoor.
Please Log in or Create an account to join the conversation.