Mein Club

TC Goldscheuer


Herzlich willkommen auf einer der schönsten Tennisanlagen in Mittelbaden !

Hier werdet Ihr von unseren 8 Sandplätzen, eingebettet in einer großen Grünanlage, empfangen. Alleine der Anblick der großzügigen Plätze macht schon Lust zum Tennisspielen. Aber auch, wenn Ihr nicht selbst zum Schläger greifen wollt, lassen sich von der Tribüne aus oder von den zahlreichen Bänken im Schatten der Bäume spannende Matches in angenehmer Atmosphäre als Zuschauer genießen.

Darüber hinaus steht Euch ganzjährig unsere Tennishalle mit 2 Plätzen (Granulatboden) und hervorragenden Lichtverhältnissen zur Verfügung.

Für das leibliche Wohl ist in der öffentlichen Gaststätte „da Pamito’s“ oder auf deren herrlicher Terrasse gesorgt, von der aus man ebenfalls einen großartigen Blick über die Tennisplätze bis hin zu den Bergen des Schwarzwalds hat. Zahlreiche Parkplätze sind für aktive Tennisspieler und Tennisspielerinnen oder für die stets willkommenen Besucher der Anlage oder der Gastronomie vorhanden.




Noch mehr tagesaktuelle Inhalte findest du in unserer neuen App und auf unseren SocialMedia Seiten:
Anlage

Anlage

Unser Tennisclub:


Unser Restaurant:





Mitglied werden

Werden Sie mitglied vom TC Goldscheuer ...

Zum digitalen Mitgliedschaftsantrag
Mitgliedsbeiträge ansehen
Mitgliedsbeiträge
Keine Mitgliedsbeiträge vorhanden.

// ==UserScript==
// @name Platzbuchung Halle – vertikale Ansicht
// @namespace tennis-club-vertical
// @version 1.0
// @description Transposes the FullCalendar resource-timeline (courts = rows) into a vertical view (courts = columns). Updates automatically on date change / reload of bookings.
// @match https://webseite.tennis-club.net/Platzbuchung_Halle*
// @run-at document-idle
// @grant none
// ==/UserScript==

// Usage:
// A) Tampermonkey/Violentmonkey: install this file as a userscript.
// B) Without extension: open the page, F12 -> Console, paste everything below the header and press Enter.

(function () {
'use strict';
if (window.__tcVertical) return;
window.__tcVertical = true;

const HOUR_PX = 80; // height of one hour in the vertical view
const MIN_COL_PX = 170; // minimum width of a court column
const POLL_MS = 500; // how often the page is checked for changes

// ---------- styles ----------
const style = document.createElement('style');
style.textContent = `
.tc-hidden { height: 0 !important; overflow: hidden !important; }
#tc-vertical { margin: 10px 0; font-family: system-ui, Arial, sans-serif; }
#tc-vertical .tc-bar { display:flex; align-items:center; gap:12px; margin-bottom:6px; }
#tc-vertical .tc-bar b { font-size:15px; }
#tc-vertical button { cursor:pointer; padding:3px 10px; border:1px solid #888; border-radius:4px; background:#f3f3f3; }
#tc-vertical .tc-grid { display:grid; border:1px solid #ccc; background:#fff; overflow:auto; max-height:80vh; }
#tc-vertical .tc-head { position:sticky; top:0; z-index:5; background:#eef0f4; border-bottom:1px solid #ccc;
border-left:1px solid #ddd; padding:6px; text-align:center; font-weight:600; font-size:13px; }
#tc-vertical .tc-head img { width:36px; display:block; margin:0 auto 3px; }
#tc-vertical .tc-times { position:relative; }
#tc-vertical .tc-times span { position:absolute; right:6px; transform:translateY(-50%); font-size:12px; color:#555; }
#tc-vertical .tc-col { position:relative; border-left:1px solid #ddd; }
#tc-vertical .tc-ev { position:absolute; border-radius:4px; padding:3px 5px; color:#fff; font-size:12px;
line-height:1.25; overflow:hidden; box-shadow:0 1px 2px rgba(0,0,0,.3); box-sizing:border-box; }
#tc-vertical .tc-ev b { display:block; }
#tc-vertical .tc-badge { position:absolute; top:2px; right:3px; background:rgba(0,0,0,.4); border-radius:50%;
width:17px; height:17px; text-align:center; line-height:17px; font-size:11px; }
`;
document.head.appendChild(style);

// ---------- read the FullCalendar DOM ----------
function textLines(main) {
const clone = main.cloneNode(true);
const badge = clone.querySelector('.pbZweiteBuchungAmTagBadge');
const hasBadge = !!badge;
if (badge) badge.remove();
const b = clone.querySelector('b');
const title = b ? b.textContent.trim() : '';
if (b) b.remove();
const tmp = document.createElement('div');
tmp.innerHTML = clone.innerHTML.replace(/
/gi, '\n');
const lines = tmp.textContent.split('\n').map(s => s.trim()).filter(Boolean);
return { title, lines, hasBadge };
}

function readCalendar() {
const view = document.querySelector('.fc-resource-timeline');
if (!view) return null;

const slots = [...view.querySelectorAll('.fc-timeline-slot-lane[data-date]')];
if (slots.length < 2) return null;
const t0 = new Date(slots[0].dataset.date);
const step = (new Date(slots[1].dataset.date) - t0) / 60000; // minutes per slot
const totalMin = step * slots.length;
const startMin = t0.getHours() * 60 + t0.getMinutes();

const resources = [];
view.querySelectorAll('.fc-datagrid-body td[data-resource-id]').forEach(td => {
const img = td.querySelector('img');
const name = (td.querySelector('.font-12') || td).textContent.trim();
resources.push({ id: td.dataset.resourceId, name, img: img ? img.src : null, events: [] });
});

view.querySelectorAll('.fc-timeline-lane[data-resource-id]').forEach(lane => {
const res = resources.find(r => r.id === lane.dataset.resourceId);
const frame = lane.querySelector('.fc-timeline-events') || lane;
const lr = frame.getBoundingClientRect();
if (!res || !lr.width) return;
lane.querySelectorAll('.fc-timeline-event').forEach(a => {
const r = a.getBoundingClientRect();
const s = startMin + ((r.left - lr.left) / lr.width) * totalMin;
const e = startMin + ((r.right - lr.left) / lr.width) * totalMin;
const main = a.querySelector('.fc-event-main') || a;
const t = textLines(main);
res.events.push({
s: Math.round(s / 5) * 5,
e: Math.round(e / 5) * 5,
color: a.style.backgroundColor || '#3788d8',
...t
});
});
});

return { date: t0, startMin, endMin: startMin + totalMin, step, resources };
}

// ---------- helpers ----------
const pad = n => String(n).padStart(2, '0');
const hhmm = m => pad(Math.floor(m / 60)) + ':' + pad(m % 60);

// give overlapping events within one court their own sub-column
function layout(events) {
events.sort((a, b) => a.s - b.s || a.e - b.e);
let group = [], groupEnd = -1;
const flush = () => {
const colsEnd = [];
group.forEach(ev => {
let c = colsEnd.findIndex(end => end <= ev.s);
if (c < 0) { c = colsEnd.length; colsEnd.push(0); }
colsEnd[c] = ev.e; ev.col = c;
});
group.forEach(ev => (ev.cols = colsEnd.length));
group = [];
};
events.forEach(ev => {
if (group.length && ev.s >= groupEnd) { flush(); groupEnd = -1; }
group.push(ev); groupEnd = Math.max(groupEnd, ev.e);
});
if (group.length) flush();
}

// ---------- render ----------
function render(data) {
let root = document.getElementById('tc-vertical');
const harness = document.querySelector('.fc-view-harness');
if (!root) {
root = document.createElement('div');
root.id = 'tc-vertical';
harness.parentNode.insertBefore(root, harness);
root.dataset.showOriginal = '0';
}
harness.classList.toggle('tc-hidden', root.dataset.showOriginal !== '1');

const hours = (data.endMin - data.startMin) / 60;
const px = m => ((m - data.startMin) / 60) * HOUR_PX;
root.textContent = '';

// top bar
const bar = document.createElement('div'); bar.className = 'tc-bar';
const title = document.createElement('b');
title.textContent = data.date.toLocaleDateString('de-DE', { weekday: 'long', day: '2-digit', month: '2-digit', year: 'numeric' });
const btn = document.createElement('button');
btn.textContent = root.dataset.showOriginal === '1' ? 'Vertikale Ansicht' : 'Originalansicht';
btn.onclick = () => {
root.dataset.showOriginal = root.dataset.showOriginal === '1' ? '0' : '1';
harness.classList.toggle('tc-hidden', root.dataset.showOriginal !== '1');
btn.textContent = root.dataset.showOriginal === '1' ? 'Vertikale Ansicht' : 'Originalansicht';
root.querySelector('.tc-grid').style.display = root.dataset.showOriginal === '1' ? 'none' : 'grid';
};
bar.append(title, btn);
root.appendChild(bar);

// grid
const grid = document.createElement('div'); grid.className = 'tc-grid';
grid.style.gridTemplateColumns = `60px repeat(${data.resources.length}, minmax(${MIN_COL_PX}px, 1fr))`;
if (root.dataset.showOriginal === '1') grid.style.display = 'none';

const corner = document.createElement('div'); corner.className = 'tc-head'; corner.textContent = 'Zeit';
grid.appendChild(corner);
data.resources.forEach(r => {
const h = document.createElement('div'); h.className = 'tc-head';
if (r.img) { const i = document.createElement('img'); i.src = r.img; h.appendChild(i); }
h.appendChild(document.createTextNode(r.name));
grid.appendChild(h);
});

const times = document.createElement('div'); times.className = 'tc-times';
times.style.height = hours * HOUR_PX + 'px';
for (let m = data.startMin; m <= data.endMin; m += 60) {
const s = document.createElement('span');
s.textContent = hhmm(m); s.style.top = px(m) + 'px';
times.appendChild(s);
}
grid.appendChild(times);

data.resources.forEach(r => {
const col = document.createElement('div'); col.className = 'tc-col';
col.style.height = hours * HOUR_PX + 'px';
col.style.backgroundImage =
'linear-gradient(#ccc 1px, transparent 1px), linear-gradient(#eee 1px, transparent 1px)';
col.style.backgroundSize = `100% ${HOUR_PX}px, 100% ${HOUR_PX / 4}px`;
layout(r.events);
r.events.forEach(ev => {
const d = document.createElement('div'); d.className = 'tc-ev';
const w = 100 / ev.cols;
d.style.top = px(ev.s) + 'px';
d.style.height = Math.max(px(ev.e) - px(ev.s) - 2, 14) + 'px';
d.style.left = `calc(${ev.col * w}% + 2px)`;
d.style.width = `calc(${w}% - 4px)`;
d.style.background = ev.color;
d.title = `${hhmm(ev.s)}–${hhmm(ev.e)}\n${ev.title}\n${ev.lines.join('\n')}`;
const b = document.createElement('b'); b.textContent = ev.title; d.appendChild(b);
ev.lines.forEach((l, i) => { if (i) d.appendChild(document.createElement('br')); d.appendChild(document.createTextNode(l)); });
if (ev.hasBadge) { const bd = document.createElement('span'); bd.className = 'tc-badge'; bd.textContent = '2'; d.appendChild(bd); }
col.appendChild(d);
});
grid.appendChild(col);
});

root.appendChild(grid);
}

// ---------- keep it in sync with the page ----------
let lastSig = '';
function tick() {
try {
const data = readCalendar();
if (!data) return;
const sig = JSON.stringify(data.resources.map(r => [r.id, r.events])) + data.date;
if (sig === lastSig && document.getElementById('tc-vertical')) return;
lastSig = sig;
render(data);
} catch (err) {
console.error('[tc-vertical]', err);
}
}
tick();
setInterval(tick, POLL_MS);
})();

Kontakt
Die abgesendeten Daten werden nur zum Zweck der Bearbeitung Ihres Anliegens verarbeitet. Weitere Informationen finden Sie in unserer Datenschutzerklärung.
© 2026 Tennis-Club Goldscheuer e.V.74