Files
oc-guy/js/site.js
T
The OC Guy 43d0fc4658 Add live OCA module status, Pixabay photography, new email
- new section: Top OCA modules, module / area / 19.0 / 20.0 status,
  rows rendered from the n8n webhook at
  n8n.odoo4projects.com/webhook/oc-guy/modules, with the last fetched
  snapshot in the markup as a no-JS fallback
- photography swapped from archival maps to Pixabay photos (archive
  aisle, cardboard boxes, old books, workshop tools, warehouse)
- featured module is now a full-bleed dark spread with the warehouse shot
- contact address is oliver@oc-guy.com throughout
- credits point at Pixabay and its Content License
2026-10-23 14:57:25 +00:00

143 lines
5.0 KiB
JavaScript

/* The OC Guy — page behaviour.
Everything degrades: without JS the page is a plain, readable
document with working links and a mail form. */
(function () {
'use strict';
var doc = document.documentElement;
doc.classList.add('js');
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* ---------- entrance for the blocks of each section ---------- */
var targets = document.querySelectorAll(
'.lead-caption, .box, .side-list, .section-head, .card, .feature, .news li, .ask-inner'
);
if (!reduce && 'IntersectionObserver' in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
entry.target.classList.add('rv-in');
io.unobserve(entry.target);
});
}, { rootMargin: '0px 0px -8% 0px', threshold: 0.08 });
Array.prototype.forEach.call(targets, function (el) {
el.setAttribute('data-rv', '1');
io.observe(el);
});
} else {
Array.prototype.forEach.call(targets, function (el) { el.classList.add('rv-in'); });
}
/* ---------- the ask form: one question, by mail ---------- */
var form = document.querySelector('.ask-form');
var mail = document.getElementById('ask-mail');
if (form && mail) {
form.addEventListener('submit', function (event) {
event.preventDefault();
var addr = (mail.value || '').trim();
if (!addr || addr.indexOf('@') === -1) {
mail.setAttribute('aria-invalid', 'true');
mail.focus();
return;
}
mail.removeAttribute('aria-invalid');
var body = 'My question about Odoo Community:\n\n\n— reply to: ' + addr + '\n';
window.location.href = 'mailto:oliver@oc-guy.com'
+ '?subject=' + encodeURIComponent('Odoo Community question')
+ '&body=' + encodeURIComponent(body);
});
}
/* ---------- OCA module status, live from the n8n feed ---------- */
var ocaBody = document.getElementById('oca-rows');
var ocaNote = document.getElementById('oca-note');
function statusCell(ok, version) {
var td = document.createElement('td');
td.className = 'oca-status';
var mark = document.createElement('span');
mark.className = ok ? 'mark is-on' : 'mark';
mark.setAttribute('aria-hidden', 'true');
mark.textContent = ok ? '\u2713' : '\u2014';
var sr = document.createElement('span');
sr.className = 'sr-only';
sr.textContent = ok ? ' has a ' + version + ' branch' : ' no ' + version + ' branch yet';
td.appendChild(mark);
td.appendChild(sr);
return td;
}
function renderOca(rows) {
ocaBody.textContent = '';
rows.forEach(function (m) {
var tr = document.createElement('tr');
var name = document.createElement('td');
name.className = 'oca-name';
var a = document.createElement('a');
a.href = m.URL || '#';
a.target = '_blank';
a.rel = 'noopener';
a.textContent = m.name || 'Module';
name.appendChild(a);
var area = document.createElement('td');
area.className = 'oca-area';
area.textContent = m.area || '';
tr.appendChild(name);
tr.appendChild(area);
tr.appendChild(statusCell(!!m.v19, '19.0'));
tr.appendChild(statusCell(!!m.v20, '20.0'));
ocaBody.appendChild(tr);
});
}
if (ocaBody) {
fetch('https://n8n.odoo4projects.com/webhook/oc-guy/modules')
.then(function (r) { if (!r.ok) throw new Error('http ' + r.status); return r.json(); })
.then(function (payload) {
var rows = payload && Array.isArray(payload.data) ? payload.data
: (Array.isArray(payload) ? payload : null);
if (!rows || !rows.length) throw new Error('empty');
renderOca(rows);
if (ocaNote) {
ocaNote.textContent = 'Status read from the OCA module feed at '
+ new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
+ '. A tick means the module carries a branch for that series; a dash means it does not yet.';
}
})
.catch(function () {
if (ocaNote) {
ocaNote.textContent = 'The live feed could not be reached just now; the rows above are the last snapshot.';
}
});
}
/* ---------- which section the reader is in ---------- */
var links = Array.prototype.slice.call(document.querySelectorAll('.nav a[href^="#"]'));
var sections = links
.map(function (a) { return document.querySelector(a.getAttribute('href')); })
.filter(Boolean);
if (sections.length && 'IntersectionObserver' in window) {
var seen = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
links.forEach(function (a) {
if (a.getAttribute('href') === '#' + entry.target.id) {
a.setAttribute('aria-current', 'true');
} else {
a.removeAttribute('aria-current');
}
});
});
}, { rootMargin: '-45% 0px -50% 0px' });
sections.forEach(function (s) { seen.observe(s); });
}
})();