API
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
/* ============================================================================
|
||||
SoftSPM - harmonogram z Akademii Wodociągowca
|
||||
Podmienia wiersze tabeli terminów danymi z api/schedule.php.
|
||||
Gdy API nie odpowiada albo nie ma pozycji, statyczne wiersze z HTML-a
|
||||
zostają nietknięte - strona nigdy nie pokazuje pustej tabeli.
|
||||
========================================================================= */
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var DICT = {
|
||||
pl: {
|
||||
dateHead: 'Data',
|
||||
webinar: 'Webinar',
|
||||
training: 'Szkolenie',
|
||||
online: 'Online',
|
||||
elearning: 'Online · e-learning',
|
||||
onDemand: 'Na żądanie',
|
||||
signUp: 'Zapisz się →',
|
||||
viewCourse: 'Zobacz kurs →',
|
||||
soldOut: 'Brak miejsc',
|
||||
soon: 'Zapisy wkrótce',
|
||||
note: 'Terminy pobierane na bieżąco z platformy kursowej Akademia Wodociągowca. Zapisy prowadzi Akademia.',
|
||||
plateTitle: 'Terminy i kursy otwarte',
|
||||
heading: 'Najbliższe szkolenia i webinaria',
|
||||
intro: 'Poniżej pozycje otwarte w tej chwili na naszej platformie kursowej. Zapisy prowadzi Akademia Wodociągowca.',
|
||||
locale: 'pl-PL',
|
||||
levels: { BASIC: 'podstawowy', INTERMEDIATE: 'średni', ADVANCED: 'zaawansowany' }
|
||||
},
|
||||
en: {
|
||||
dateHead: 'Date',
|
||||
webinar: 'Webinar',
|
||||
training: 'Training',
|
||||
online: 'Online',
|
||||
elearning: 'Online · e-learning',
|
||||
onDemand: 'On demand',
|
||||
signUp: 'Sign up →',
|
||||
viewCourse: 'View course →',
|
||||
soldOut: 'Fully booked',
|
||||
soon: 'Registration soon',
|
||||
note: 'Dates are pulled live from our Akademia Wodociagowca course platform, which also handles registration.',
|
||||
plateTitle: 'Open dates and courses',
|
||||
heading: 'Upcoming training and webinars',
|
||||
intro: 'Everything currently open on our course platform. Registration is handled by Akademia Wodociagowca.',
|
||||
locale: 'en-GB',
|
||||
levels: { BASIC: 'basic', INTERMEDIATE: 'intermediate', ADVANCED: 'advanced' }
|
||||
}
|
||||
};
|
||||
|
||||
var lang = (document.documentElement.getAttribute('lang') || 'pl').slice(0, 2).toLowerCase();
|
||||
var t = DICT[lang] || DICT.pl;
|
||||
|
||||
function el(tag, className, text) {
|
||||
var node = document.createElement(tag);
|
||||
if (className) { node.className = className; }
|
||||
if (text !== undefined && text !== null) { node.textContent = text; }
|
||||
return node;
|
||||
}
|
||||
|
||||
function formatDate(iso, timezone) {
|
||||
var date = new Date(iso);
|
||||
if (isNaN(date.getTime())) { return null; }
|
||||
var zone = timezone || 'Europe/Warsaw';
|
||||
var opts = { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: zone };
|
||||
var timeOpts = { hour: '2-digit', minute: '2-digit', timeZone: zone };
|
||||
try {
|
||||
return {
|
||||
day: new Intl.DateTimeFormat(t.locale, opts).format(date),
|
||||
hour: new Intl.DateTimeFormat(t.locale, timeOpts).format(date)
|
||||
};
|
||||
} catch (e) {
|
||||
// Nieznana strefa albo stary silnik - pokazujemy datę bez strefy.
|
||||
return { day: date.toLocaleDateString(t.locale), hour: date.toLocaleTimeString(t.locale) };
|
||||
}
|
||||
}
|
||||
|
||||
function actionCell(item) {
|
||||
var cell = el('td', 's-act');
|
||||
if (item.kind === 'webinar' && item.soldOut) {
|
||||
cell.appendChild(el('span', 'text-muted', t.soldOut));
|
||||
return cell;
|
||||
}
|
||||
if (item.kind === 'webinar' && item.open === false) {
|
||||
cell.appendChild(el('span', 'text-muted', t.soon));
|
||||
return cell;
|
||||
}
|
||||
if (!item.url) {
|
||||
cell.appendChild(el('span', 'text-muted', item.kind === 'webinar' ? t.soon : ''));
|
||||
return cell;
|
||||
}
|
||||
var link = el('a', 'sign', item.kind === 'webinar' ? t.signUp : t.viewCourse);
|
||||
link.href = item.url;
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener';
|
||||
cell.appendChild(link);
|
||||
return cell;
|
||||
}
|
||||
|
||||
function buildRow(item) {
|
||||
var row = document.createElement('tr');
|
||||
|
||||
var date = el('td', 's-date');
|
||||
if (item.kind === 'webinar') {
|
||||
var parts = formatDate(item.startsAt, item.timezone);
|
||||
if (parts) {
|
||||
date.appendChild(document.createTextNode(parts.day));
|
||||
date.appendChild(el('span', 's-hour', parts.hour));
|
||||
} else {
|
||||
date.appendChild(el('span', 'tag tag-soon', t.onDemand));
|
||||
}
|
||||
} else {
|
||||
date.appendChild(el('span', 'tag tag-soon', t.onDemand));
|
||||
}
|
||||
row.appendChild(date);
|
||||
|
||||
// textContent, nie innerHTML - tytuły przychodzą z innego systemu.
|
||||
row.appendChild(el('td', 's-topic', item.title));
|
||||
|
||||
var form = el('td', 's-form');
|
||||
form.appendChild(el(
|
||||
'span',
|
||||
item.kind === 'webinar' ? 'tag tag-outline' : 'tag tag-accent',
|
||||
item.kind === 'webinar' ? t.webinar : t.training
|
||||
));
|
||||
row.appendChild(form);
|
||||
|
||||
var place = item.kind === 'webinar' ? t.online : t.elearning;
|
||||
if (item.kind === 'course' && item.level && t.levels[item.level]) {
|
||||
place = t.elearning + ' · ' + t.levels[item.level];
|
||||
}
|
||||
row.appendChild(el('td', 's-place', place));
|
||||
|
||||
row.appendChild(actionCell(item));
|
||||
return row;
|
||||
}
|
||||
|
||||
function render(table, items) {
|
||||
var body = table.querySelector('tbody');
|
||||
if (!body) { return; }
|
||||
|
||||
var fresh = document.createDocumentFragment();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
fresh.appendChild(buildRow(items[i]));
|
||||
}
|
||||
body.innerHTML = '';
|
||||
body.appendChild(fresh);
|
||||
|
||||
// Mamy realne daty, więc nagłówek kolumny wraca z "Termin" na "Data".
|
||||
var head = table.querySelector('[data-schedule-datehead]');
|
||||
if (head) { head.textContent = t.dateHead; }
|
||||
|
||||
// Przy realnych terminach nagłówki mówiące "ustalamy terminy" przestają
|
||||
// być prawdziwe, więc lecą razem z wierszami.
|
||||
var section = table.closest ? table.closest('section') : null;
|
||||
if (section) {
|
||||
var heading = section.querySelector('[data-schedule-heading]');
|
||||
if (heading) { heading.textContent = t.heading; }
|
||||
var intro = section.querySelector('[data-schedule-intro]');
|
||||
if (intro) { intro.textContent = t.intro; }
|
||||
}
|
||||
|
||||
var plate = table.closest ? table.closest('.plate') : null;
|
||||
var plateTitle = plate ? plate.querySelector('[data-schedule-title]') : null;
|
||||
if (plateTitle) { plateTitle.textContent = t.plateTitle; }
|
||||
|
||||
var note = plate ? plate.querySelector('[data-schedule-note]') : null;
|
||||
if (note) {
|
||||
note.textContent = t.note + ' ';
|
||||
var link = el('a', null, 'akademiawodociagowca.pl');
|
||||
link.href = 'https://akademiawodociagowca.pl/';
|
||||
link.target = '_blank';
|
||||
link.rel = 'noopener';
|
||||
note.appendChild(link);
|
||||
}
|
||||
table.setAttribute('data-schedule-state', 'live');
|
||||
}
|
||||
|
||||
function boot() {
|
||||
var tables = document.querySelectorAll('table[data-schedule]');
|
||||
if (!tables.length) { return; }
|
||||
|
||||
var limit = 0;
|
||||
for (var i = 0; i < tables.length; i++) {
|
||||
limit = Math.max(limit, parseInt(tables[i].getAttribute('data-schedule-limit'), 10) || 12);
|
||||
}
|
||||
|
||||
fetch('api/schedule.php?limit=' + limit, {
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Accept': 'application/json' }
|
||||
})
|
||||
.then(function (response) { return response.json(); })
|
||||
.then(function (data) {
|
||||
if (!data || data.source !== 'api' || !data.items || !data.items.length) { return; }
|
||||
for (var i = 0; i < tables.length; i++) {
|
||||
var own = parseInt(tables[i].getAttribute('data-schedule-limit'), 10) || data.items.length;
|
||||
render(tables[i], data.items.slice(0, own));
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
// Cisza jest właściwą reakcją: w tabeli zostają statyczne wiersze.
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user