overhaul gpx creation and usage
This commit is contained in:
+27
-3
@@ -456,7 +456,7 @@ button,
|
||||
left: 0;
|
||||
z-index: 40;
|
||||
display: grid;
|
||||
grid-template-columns: 3.75rem minmax(0, 1fr);
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
align-items: center;
|
||||
min-height: var(--footer-height);
|
||||
box-sizing: border-box;
|
||||
@@ -468,7 +468,8 @@ button,
|
||||
box-shadow: 0 -.25rem .8rem rgba(0, 0, 0, .2);
|
||||
backdrop-filter: blur(.4rem);
|
||||
}
|
||||
#navigation-arrow {
|
||||
#navigation-arrow,
|
||||
#route-navigation-arrow {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
fill: currentColor;
|
||||
@@ -484,7 +485,8 @@ button,
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#navigation-mode {
|
||||
#navigation-mode,
|
||||
#route-navigation-mode {
|
||||
overflow: hidden;
|
||||
font-size: .78rem;
|
||||
text-overflow: ellipsis;
|
||||
@@ -845,3 +847,25 @@ button,
|
||||
padding: .65rem;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-target {
|
||||
display: grid;
|
||||
grid-template-columns: 2.8rem minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: .35rem;
|
||||
min-width: 0;
|
||||
}
|
||||
.navigation-target svg { width: 2.7rem; height: 2.7rem; }
|
||||
#route-recording-control {
|
||||
position: fixed;
|
||||
top: calc(env(safe-area-inset-top) + var(--icon-button-size) + 1rem);
|
||||
left: max(.5rem, env(safe-area-inset-left));
|
||||
right: max(.5rem, env(safe-area-inset-right));
|
||||
z-index: 45;
|
||||
padding: .5rem;
|
||||
border-radius: .7rem;
|
||||
background: #f8f5eb;
|
||||
box-shadow: 0 .25rem 1rem rgba(0, 0, 0, .2);
|
||||
}
|
||||
#route-recording-status { display: block; margin-bottom: .35rem; }
|
||||
#route-recording-control button { min-height: 2.75rem; }
|
||||
|
||||
@@ -58,6 +58,17 @@
|
||||
color: #233326;
|
||||
box-shadow: 0 .8rem 2rem rgba(20, 32, 22, .28);
|
||||
touch-action: pan-y;
|
||||
transform-origin: top right;
|
||||
transform: scaleY(0);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: transform 180ms ease-out, opacity 180ms ease-out;
|
||||
}
|
||||
|
||||
.route-control-dropdown.is-open {
|
||||
transform: scaleY(1);
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.route-control-dropdown section + section {
|
||||
|
||||
+84
-57
@@ -94,7 +94,7 @@
|
||||
<p id="android-browser-hint" class="android-browser-hint" hidden></p>
|
||||
|
||||
<div class="privacy-summary">
|
||||
<p data-i18n="privacy.no-tracking">Hier gibt es keine Werbung. Wir verfolgen nicht, welche anderen Seiten du besuchst.</p>
|
||||
<p data-i18n="app.no-tracking">Hier gibt es keine Werbung. Wir verfolgen nicht, welche anderen Seiten du besuchst.</p>
|
||||
<label for="cookie-toggle-1" class="switch-row switch-disabled">
|
||||
<span>
|
||||
<strong data-i18n="progress.cookies-label">Optionale Cookies</strong>
|
||||
@@ -158,6 +158,11 @@
|
||||
</section>
|
||||
</div>
|
||||
<main id="app-shell" hidden>
|
||||
<aside id="route-recording-control" hidden>
|
||||
<span id="route-recording-status" aria-live="polite"></span>
|
||||
<button id="route-recording-pause" type="button" data-i18n="recorder.pause">Aufnahme pausieren</button>
|
||||
<button id="route-recording-stop" type="button" data-i18n="recorder.stop">Aufnahme beenden</button>
|
||||
</aside>
|
||||
<div class="route-control">
|
||||
<button id="route-control-button" class="route-control-button" type="button" aria-label="Strecke auswählen oder wechseln" title="Strecke auswählen oder wechseln" aria-haspopup="true" aria-expanded="false" aria-controls="route-control-dropdown" data-i18n-title="routes.open-menu" data-i18n-aria-label="routes.open-menu">
|
||||
<img src="images/icons/route-management.svg" alt="" aria-hidden="true">
|
||||
@@ -280,13 +285,21 @@
|
||||
</div>
|
||||
</section>
|
||||
<footer id="navigation-footer" hidden aria-live="polite">
|
||||
<svg id="navigation-arrow" viewbox="0 0 64 64" aria-hidden="true" focusable="false">
|
||||
<path d="M32 4 53 54 32 44 11 54Z"></path>
|
||||
</svg>
|
||||
<p>
|
||||
<span id="navigation-mode" data-i18n="navigation.station-direction">Richtung zum nächsten Station</span>
|
||||
<strong id="navigation-distance">–</strong>
|
||||
</p>
|
||||
<div class="navigation-target">
|
||||
<svg id="route-navigation-arrow" viewBox="0 0 64 64" aria-hidden="true" focusable="false">
|
||||
<path d="M32 4 53 54 32 44 11 54Z"></path>
|
||||
</svg>
|
||||
<p><span id="route-navigation-mode" data-i18n="recorder.path-direction">Dem Weg folgen</span></p>
|
||||
</div>
|
||||
<div id="station-navigation" class="navigation-target">
|
||||
<svg id="navigation-arrow" viewBox="0 0 64 64" aria-hidden="true" focusable="false">
|
||||
<path d="M32 4 53 54 32 44 11 54Z"></path>
|
||||
</svg>
|
||||
<p>
|
||||
<span id="navigation-mode" data-i18n="navigation.station-direction">Richtung zur nächsten Station</span>
|
||||
<strong id="navigation-distance">–</strong>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
<dialog id="info-dialog" class="info-dialog" aria-labelledby="info-dialog-title">
|
||||
@@ -296,62 +309,64 @@
|
||||
<button id="info-close" type="button" aria-label="Informationsfenster schließen" title="Schließen" data-i18n-title="info.close" data-i18n-aria-label="info.close-label">×</button>
|
||||
</header>
|
||||
<div class="info-dialog-content">
|
||||
<article class="info-page" data-info-page="privacy" hidden>
|
||||
<p class="legal-warning"><strong data-i18n="common.notice">Hinweis:</strong><span data-i18n="privacy.incomplete-notice">Diese Angaben sind noch nicht vollständig. Die Kontakte stammen von der Grundschule Herpf. Wer die Website betreibt, welche Verbindungsdaten gespeichert werden und wie lange sie bleiben, muss noch ergänzt werden.</span></p>
|
||||
<h3 data-i18n="privacy.controller-title">1. Verantwortliche Stelle und Datenschutzkontakt</h3>
|
||||
<article class="info-page" data-info-page="privacy" lang="de" hidden>
|
||||
<p class="legal-warning"><strong>Hinweis:</strong><span>Diese Angaben sind noch nicht vollständig. Die Kontakte stammen von der Grundschule Herpf. Wer die Website betreibt, welche Verbindungsdaten gespeichert werden und wie lange sie bleiben, muss noch ergänzt werden.</span></p>
|
||||
<h3>1. Verantwortliche Stelle und Datenschutzkontakt</h3>
|
||||
<p>
|
||||
<strong data-i18n="contacts.school.name">Staatliche Grundschule Herpf</strong><br><span data-i18n="contacts.school.address">Zum Eichig 3</span><br><span data-i18n="contacts.school.city">98617 Meiningen / OT Herpf</span><br><span data-i18n="contacts.school.phone">Telefon: (036943) 63722</span><br><span data-i18n="contacts.school.email">E-Mail: info@grundschule-herpf.de</span></p>
|
||||
<p><span data-i18n="contacts.school.privacy-label">Datenschutzangaben der Schule:</span><br>
|
||||
<strong data-i18n="contacts.privacy.name">Staatliches Schulamt Südthüringen</strong><br><span data-i18n="contacts.privacy.role">Datenschutzbeauftragter</span><br><span data-i18n="contacts.privacy.address">Hölderlinstraße 1</span><br><span data-i18n="contacts.privacy.city">98527 Suhl</span><br><span data-i18n="contacts.privacy.phone">Telefon: 03681 / 7341 25</span><br><span data-i18n="contacts.privacy.fax">Fax: 03681 / 7341 09</span><br><span data-i18n="contacts.privacy.email">E-Mail: datenschutz.suedthueriungen@schulamt.thueringen.de</span></p>
|
||||
<p data-i18n="contacts.privacy.postal-hint">Der Datenschutzbeauftragte kann außerdem über die Postadresse der Schule mit dem Zusatz „der Datenschutzbeauftragte“ erreicht werden.</p>
|
||||
<h3 data-i18n="privacy.connection-title">2. Wenn du Wegwichtel öffnest</h3>
|
||||
<p data-i18n="privacy.connection-data">Wenn du Wegwichtel öffnest, können Verbindungsdaten verarbeitet werden. Dazu gehören zum Beispiel die Internetadresse deines Geräts, Datum, Uhrzeit und Zeitzone, die aufgerufene Seite, übertragene Daten und ob der Aufruf geklappt hat. Auch die vorherige Seite und Angaben zu deinem Gerät, Internetbrowser und dessen Sprache können dazugehören. Diese Daten helfen dabei, die Website bereitzustellen, Fehler zu finden und sie zu schützen.</p>
|
||||
<p><span data-i18n="privacy.provider-label">Wer die Website bereitstellt und welche Verbindungsdaten wie lange gespeichert werden:</span><strong data-i18n="privacy.provider-placeholder">[Anbieter, Anschrift, gespeicherte Daten und Speicherdauer ergänzen]</strong></p>
|
||||
<h3 data-i18n="privacy.location-title">3. Standortdaten</h3>
|
||||
<p data-i18n="privacy.location-data">Du entscheidest, ob Wegwichtel deinen Standort nutzen darf. Damit findest du Strecken in deiner Nähe und siehst den Weg zur nächsten Station. Dein laufender Standort wird auf deinem Gerät verarbeitet. Wegwichtel speichert daraus keinen Verlauf auf der Website.</p>
|
||||
<h3 data-i18n="privacy.progress-title">4. Deinen Fortschritt merken</h3>
|
||||
<p data-i18n="privacy.progress-data">Wenn du „Meinen Fortschritt merken“ einschaltest, speichert Wegwichtel deine gewählte Strecke, besuchte und angesehene Stationen sowie angehörte Tonaufnahmen. Auch ob du unterwegs bist, eine Pause machst oder fertig bist und der Zeitpunkt werden gespeichert. Diese Angaben bleiben auf deinem Gerät und werden nicht an die Website gesendet.</p>
|
||||
<p data-i18n="privacy.progress-deletion">Wenn du deinen Fortschritt mindestens einen Tag lang nicht verändert hast, wird er beim nächsten Öffnen gelöscht. Beim Ausschalten wird er sofort gelöscht. Deine eigenen und für unterwegs gespeicherten Strecken bleiben erhalten.</p>
|
||||
<strong>Staatliche Grundschule Herpf</strong><br><span>Zum Eichig 3</span><br><span>98617 Meiningen / OT Herpf</span><br><span>Telefon: (036943) 63722</span><br><span>E-Mail: info@grundschule-herpf.de</span></p>
|
||||
<p><span>Datenschutzangaben der Schule:</span><br>
|
||||
<strong>Staatliches Schulamt Südthüringen</strong><br><span>Datenschutzbeauftragter</span><br><span>Hölderlinstraße 1</span><br><span>98527 Suhl</span><br><span>Telefon: 03681 / 7341 25</span><br><span>Fax: 03681 / 7341 09</span><br><span>E-Mail: datenschutz.suedthueriungen@schulamt.thueringen.de</span></p>
|
||||
<p>Der Datenschutzbeauftragte kann außerdem über die Postadresse der Schule mit dem Zusatz „der Datenschutzbeauftragte“ erreicht werden.</p>
|
||||
<h3>2. Wenn du Wegwichtel öffnest</h3>
|
||||
<p>Wenn du Wegwichtel öffnest, können Verbindungsdaten verarbeitet werden. Dazu gehören zum Beispiel die Internetadresse deines Geräts, Datum, Uhrzeit und Zeitzone, die aufgerufene Seite, übertragene Daten und ob der Aufruf geklappt hat. Auch die vorherige Seite und Angaben zu deinem Gerät, Internetbrowser und dessen Sprache können dazugehören. Diese Daten helfen dabei, die Website bereitzustellen, Fehler zu finden und sie zu schützen.</p>
|
||||
<p><span>Wer die Website bereitstellt und welche Verbindungsdaten wie lange gespeichert werden:</span><strong>[Anbieter, Anschrift, gespeicherte Daten und Speicherdauer ergänzen]</strong></p>
|
||||
<h3>3. Standortdaten</h3>
|
||||
<p>Du entscheidest, ob Wegwichtel deinen Standort nutzen darf. Damit findest du Strecken in deiner Nähe und siehst den Weg zur nächsten Station. Dein laufender Standort wird auf deinem Gerät verarbeitet. Wegwichtel speichert daraus keinen Verlauf auf der Website.</p>
|
||||
<h3>4. Deinen Fortschritt merken</h3>
|
||||
<p>Wenn du „Meinen Fortschritt merken“ einschaltest, speichert Wegwichtel deine gewählte Strecke, besuchte und angesehene Stationen sowie angehörte Tonaufnahmen. Auch ob du unterwegs bist, eine Pause machst oder fertig bist und der Zeitpunkt werden gespeichert. Diese Angaben bleiben auf deinem Gerät und werden nicht an die Website gesendet.</p>
|
||||
<p>Wenn du deinen Fortschritt mindestens einen Tag lang nicht verändert hast, wird er beim nächsten Öffnen gelöscht. Beim Ausschalten wird er sofort gelöscht. Deine eigenen und für unterwegs gespeicherten Strecken bleiben erhalten.</p>
|
||||
<label for="progress-storage-toggle-2" class="switch-row compact-switch">
|
||||
<span>
|
||||
<strong data-i18n="progress.remember">Meinen Fortschritt merken</strong>
|
||||
<small data-i18n="progress.choice-hint">Du entscheidest, ob sich Wegwichtel deinen Fortschritt merkt.</small>
|
||||
<strong>Meinen Fortschritt merken</strong>
|
||||
<small>Du entscheidest, ob sich Wegwichtel deinen Fortschritt merkt.</small>
|
||||
</span>
|
||||
<input id="progress-storage-toggle-2" class="progress-storage-toggle" type="checkbox" role="switch" aria-checked="false">
|
||||
<span class="switch-track" aria-hidden="true"></span>
|
||||
</label>
|
||||
<h3 data-i18n="privacy.drafts-title">5. Deine eigenen Strecken</h3>
|
||||
<p data-i18n="privacy.draft-data">Neue Strecken bleiben zuerst auf deinem Gerät. Gespeichert werden der Weg, die Orte der Stationen, Texte sowie ausgewählte Bilder und Tonaufnahmen.</p>
|
||||
<p data-i18n="privacy.draft-deletion">Deine Entwürfe bleiben erhalten, wenn alter Fortschritt gelöscht wird oder du „Meinen Fortschritt merken“ ausschaltest. Sie bleiben auf diesem Gerät, bis du sie löschst oder die gespeicherten Daten von Wegwichtel in deinem Internetbrowser entfernst. Nur wenn du „Zur Prüfung senden“ wählst, wird deine Strecke an die Website gesendet.</p>
|
||||
<h3 data-i18n="privacy.settings-title">6. Werbung und gespeicherte Einstellungen</h3>
|
||||
<p data-i18n="privacy.settings-data">Wegwichtel verwendet keine Cookies. Es zählt keine Besuche für Werbung und verfolgt nicht, welche anderen Seiten du besuchst. Auf deinem Gerät wird gespeichert, ob du „Meinen Fortschritt merken“ eingeschaltet hast.</p>
|
||||
<h3 data-i18n="privacy.children-title">7. Inhalte von Schülerinnen und Schülern</h3>
|
||||
<p data-i18n="privacy.children-permission">Bilder, Texte und Tonaufnahmen dürfen nur geteilt werden, wenn das erlaubt ist. Wenn Kinder auf Bildern oder in Aufnahmen erkannt werden können, müssen die Regeln der Schule beachtet werden. Auch die Eltern oder anderen Sorgeberechtigten müssen die nötige Erlaubnis geben.</p>
|
||||
<h3 data-i18n="privacy.rights-title">8. Deine Rechte</h3>
|
||||
<p data-i18n="privacy.rights-data">Du kannst fragen, welche Daten über dich gespeichert sind. Unter den gesetzlichen Voraussetzungen kannst du verlangen, dass sie berichtigt, gelöscht, nur noch eingeschränkt genutzt oder dir zur Weitergabe bereitgestellt werden. Du kannst der Nutzung widersprechen und eine erteilte Erlaubnis für die Zukunft zurücknehmen. Wenn du dich über den Umgang mit deinen Daten beschweren möchtest, kannst du dich an die folgende Datenschutzbehörde wenden.</p>
|
||||
<p><span data-i18n="contacts.authority.label">Zuständige Datenschutzaufsicht:</span><br>
|
||||
<strong data-i18n="contacts.authority.name">Thüringer Landesbeauftragter für den Datenschutz und die Informationsfreiheit (TlfDI)</strong><br><span data-i18n="contacts.authority.postal-address">Postfach 90 04 55, 99107 Erfurt</span><br><span data-i18n="contacts.authority.address">Häßlerstraße 8, 99096 Erfurt</span><br><span data-i18n="contacts.authority.phone">Telefon: 0361 / 57 311 29 00</span><br><span data-i18n="contacts.authority.fax">Telefax: 0361 / 57 311 29 04</span><br><span data-i18n="contacts.authority.email">E-Mail: poststelle@datenschutz.thueringen.de</span><br><span data-i18n="contacts.authority.website">Website: www.tlfdi.de</span></p>
|
||||
<h3>5. Deine eigenen Strecken</h3>
|
||||
<p>Neue Strecken bleiben zuerst auf deinem Gerät. Gespeichert werden der Weg, die Orte der Stationen, Texte sowie ausgewählte Bilder und Tonaufnahmen.</p>
|
||||
<p>Deine Entwürfe bleiben erhalten, wenn alter Fortschritt gelöscht wird oder du „Meinen Fortschritt merken“ ausschaltest. Sie bleiben auf diesem Gerät, bis du sie löschst oder die gespeicherten Daten von Wegwichtel in deinem Internetbrowser entfernst. Nur wenn du „Zur Prüfung senden“ wählst, wird deine Strecke an die Website gesendet.</p>
|
||||
<h3>6. Werbung und gespeicherte Einstellungen</h3>
|
||||
<p>Wegwichtel verwendet keine Cookies. Es zählt keine Besuche für Werbung und verfolgt nicht, welche anderen Seiten du besuchst. Auf deinem Gerät wird gespeichert, ob du „Meinen Fortschritt merken“ eingeschaltet hast.</p>
|
||||
<h3>7. Inhalte von Schülerinnen und Schülern</h3>
|
||||
<p>Bilder, Texte und Tonaufnahmen dürfen nur geteilt werden, wenn das erlaubt ist. Wenn Kinder auf Bildern oder in Aufnahmen erkannt werden können, müssen die Regeln der Schule beachtet werden. Auch die Eltern oder anderen Sorgeberechtigten müssen die nötige Erlaubnis geben.</p>
|
||||
<h3>8. Deine Rechte</h3>
|
||||
<p>Du kannst fragen, welche Daten über dich gespeichert sind. Unter den gesetzlichen Voraussetzungen kannst du verlangen, dass sie berichtigt, gelöscht, nur noch eingeschränkt genutzt oder dir zur Weitergabe bereitgestellt werden. Du kannst der Nutzung widersprechen und eine erteilte Erlaubnis für die Zukunft zurücknehmen. Wenn du dich über den Umgang mit deinen Daten beschweren möchtest, kannst du dich an die folgende Datenschutzbehörde wenden.</p>
|
||||
<p><span>Zuständige Datenschutzaufsicht:</span><br>
|
||||
<strong>Thüringer Landesbeauftragter für den Datenschutz und die Informationsfreiheit (TlfDI)</strong><br><span>Postfach 90 04 55, 99107 Erfurt</span><br><span>Häßlerstraße 8, 99096 Erfurt</span><br><span>Telefon: 0361 / 57 311 29 00</span><br><span>Telefax: 0361 / 57 311 29 04</span><br><span>E-Mail: poststelle@datenschutz.thueringen.de</span><br><span>Website: www.tlfdi.de</span></p>
|
||||
</article>
|
||||
<article class="info-page" data-info-page="imprint" hidden>
|
||||
<p class="legal-warning"><strong data-i18n="common.notice">Hinweis:</strong><span data-i18n="imprint.incomplete-notice">Diese Angaben stammen von der Grundschule Herpf. Vor der Veröffentlichung muss geprüft werden, ob für Wegwichtel noch weitere oder andere Angaben nötig sind.</span></p>
|
||||
<h3 data-i18n="imprint.controller-title">Wer für Wegwichtel verantwortlich ist</h3>
|
||||
<article class="info-page" data-info-page="imprint" lang="de" hidden>
|
||||
<p class="legal-warning"><strong>Hinweis:</strong><span>Diese Angaben stammen von der Grundschule Herpf. Vor der Veröffentlichung muss geprüft werden, ob für Wegwichtel noch weitere oder andere Angaben nötig sind.</span></p>
|
||||
<h3>Wer für Wegwichtel verantwortlich ist</h3>
|
||||
<p>
|
||||
<strong data-i18n="contacts.school.name">Staatliche Grundschule Herpf</strong><br><span data-i18n="contacts.school.address">Zum Eichig 3</span><br><span data-i18n="contacts.school.city">98617 Meiningen / OT Herpf</span></p>
|
||||
<h3 data-i18n="imprint.contact-title">Kontakt</h3>
|
||||
<p><span data-i18n="contacts.school.phone">Telefon: (036943) 63722</span><br><span data-i18n="contacts.school.fax">Telefax: (036943) 63843</span><br><span data-i18n="contacts.school.email">E-Mail: info@grundschule-herpf.de</span></p>
|
||||
<h3 data-i18n="imprint.head-title">Leitung der Schule</h3>
|
||||
<p data-i18n="contacts.school.head">Frau Wichert, Schulleiterin</p>
|
||||
<h3 data-i18n="imprint.sponsor-title">Schulträger</h3>
|
||||
<strong>Staatliche Grundschule Herpf</strong><br><span>Zum Eichig 3</span><br><span>98617 Meiningen / OT Herpf</span></p>
|
||||
<h3>Kontakt</h3>
|
||||
<p><span>Telefon: (036943) 63722</span><br><span>Telefax: (036943) 63843</span><br><span>E-Mail: info@grundschule-herpf.de</span></p>
|
||||
<h3>Leitung der Schule</h3>
|
||||
<p>Frau Wichert, Schulleiterin</p>
|
||||
<h3>Schulträger</h3>
|
||||
<p>
|
||||
<strong data-i18n="contacts.sponsor.name">Landkreis Schmalkalden-Meiningen</strong><br><span data-i18n="contacts.sponsor.role">Landratsamt</span><br><span data-i18n="contacts.sponsor.address">Obertshäuser Platz 1</span><br><span data-i18n="contacts.sponsor.city">98617 Meiningen</span></p>
|
||||
<h3 data-i18n="imprint.content-title">Inhaltlich verantwortlich</h3>
|
||||
<p data-i18n="contacts.school.content-owner">Frau Wichert</p>
|
||||
<h3 data-i18n="imprint.required-title">Weitere Pflichtangaben</h3>
|
||||
<p data-i18n="imprint.required-data">Je nachdem, wer Wegwichtel betreibt, können weitere Angaben nötig sein. Dazu gehören zum Beispiel die Verantwortlichen für den Betrieb der Website. Diese Angaben müssen noch geprüft werden.</p>
|
||||
<h3 data-i18n="imprint.liability-title">Haftung für Inhalte und Verweise</h3>
|
||||
<p data-i18n="imprint.liability-data">Die Inhalte werden sorgfältig erstellt und regelmäßig geprüft. Falls etwas falsch, veraltet oder nicht erlaubt ist, melde dich beim Kontakt oben. Für andere verlinkte Seiten sind deren Betreiber verantwortlich.</p>
|
||||
<h3 data-i18n="imprint.copyright-title">Urheber- und Nutzungsrechte</h3>
|
||||
<p data-i18n="imprint.copyright-data">Wenn nichts anderes angegeben ist, liegen die Rechte bei der Grundschule Herpf. Du darfst Texte, Bilder, Tonaufnahmen und Wege nur so nutzen, wie es jeweils erlaubt wurde. Auch die Rechte der beteiligten Kinder, Familien, Lehrkräfte und anderen Personen bleiben bestehen.</p>
|
||||
<strong>Landkreis Schmalkalden-Meiningen</strong><br><span>Landratsamt</span><br><span>Obertshäuser Platz 1</span><br><span>98617 Meiningen</span></p>
|
||||
<h3>Inhaltlich verantwortlich</h3>
|
||||
<p>Frau Wichert</p>
|
||||
<h3>Technisch verantwortlich</h3>
|
||||
<p>Florian Zumpe<br><span>[Anschrift von Florian Zumpe ergänzen]</span><br><span>E-Mail: [E-Mail-Adresse von Florian Zumpe ergänzen]</span></p>
|
||||
<h3>Weitere Pflichtangaben</h3>
|
||||
<p>Je nachdem, wer Wegwichtel betreibt, können weitere Angaben nötig sein. Dazu gehören zum Beispiel die Verantwortlichen für den Betrieb der Website. Diese Angaben müssen noch geprüft werden.</p>
|
||||
<h3>Haftung für Inhalte und Verweise</h3>
|
||||
<p>Die Inhalte werden sorgfältig erstellt und regelmäßig geprüft. Falls etwas falsch, veraltet oder nicht erlaubt ist, melde dich beim Kontakt oben. Für andere verlinkte Seiten sind deren Betreiber verantwortlich.</p>
|
||||
<h3>Urheber- und Nutzungsrechte</h3>
|
||||
<p>Wenn nichts anderes angegeben ist, liegen die Rechte bei der Grundschule Herpf. Du darfst Texte, Bilder, Tonaufnahmen und Wege nur so nutzen, wie es jeweils erlaubt wurde. Auch die Rechte der beteiligten Kinder, Familien, Lehrkräfte und anderen Personen bleiben bestehen.</p>
|
||||
</article>
|
||||
<article class="info-page" data-info-page="technology" hidden>
|
||||
<h3 data-i18n="storage-help.progress-title">Was merkt sich Wegwichtel?</h3>
|
||||
@@ -429,6 +444,12 @@
|
||||
<input id="editor-route-gpx" type="file" accept=".gpx,application/gpx+xml,text/xml,application/xml">
|
||||
</div>
|
||||
|
||||
<details id="editor-path-positions">
|
||||
<summary data-i18n="recorder.edit-path">Orte auf dem Weg ergänzen</summary>
|
||||
<p data-i18n="recorder.edit-help">Fehlende Orte kannst du später eintragen. Leere Felder bleiben gespeichert.</p>
|
||||
<div id="editor-recorded-positions"></div>
|
||||
<button id="editor-add-position" type="button" data-i18n="recorder.add-position">Ort auf dem Weg hinzufügen</button>
|
||||
</details>
|
||||
<p id="editor-route-activated" class="editor-muted" data-i18n="editor.new-draft-hint">Deine neue Strecke bleibt zuerst auf diesem Gerät. Mit „Zur Prüfung senden“ kannst du sie zur Freigabe einreichen.</p>
|
||||
|
||||
<div class="editor-form-actions">
|
||||
@@ -458,8 +479,13 @@
|
||||
<label for="editor-poi-description" data-i18n="editor.station-text">Text</label>
|
||||
<textarea id="editor-poi-description" rows="6"></textarea>
|
||||
|
||||
<input id="editor-poi-lat" type="hidden">
|
||||
<input id="editor-poi-lon" type="hidden">
|
||||
<details>
|
||||
<summary data-i18n="recorder.manual-location">Ort ergänzen oder ändern</summary>
|
||||
<label for="editor-poi-lat" data-i18n="recorder.latitude">Breitengrad</label>
|
||||
<input id="editor-poi-lat" type="number" step="any" min="-90" max="90">
|
||||
<label for="editor-poi-lon" data-i18n="recorder.longitude">Längengrad</label>
|
||||
<input id="editor-poi-lon" type="number" step="any" min="-180" max="180">
|
||||
</details>
|
||||
<input id="editor-poi-radius" type="hidden" value="25">
|
||||
|
||||
<div class="editor-media-actions" aria-label="Bilder und Ton zur Station hinzufügen" data-i18n-aria-label="editor.media-actions-label">
|
||||
@@ -500,6 +526,7 @@
|
||||
<script src="js/i18n.js?v=0.12.14"></script>
|
||||
<script src="js/user-messages.js?v=0.12.14"></script>
|
||||
<script src="js/local-routes.js?v=0.12.14"></script>
|
||||
<script src="js/route-recorder.js?v=0.12.14"></script>
|
||||
<script src="js/editor-ui.js?v=0.12.14"></script>
|
||||
<script src="js/privacy-storage.js?v=0.12.14"></script>
|
||||
<script src="js/legal-ui.js?v=0.12.14"></script>
|
||||
@@ -508,4 +535,4 @@
|
||||
<script src="js/offline-cache.js?v=0.12.14"></script>
|
||||
<script src="js/bootstrap-loader.js?v=0.12.14"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+40
-26
@@ -1,6 +1,10 @@
|
||||
(function (ns, $) {
|
||||
'use strict';
|
||||
|
||||
const DROPDOWN_ANIMATION_MS = 180;
|
||||
let routeControlOpen = false;
|
||||
let routeControlCloseTimer = null;
|
||||
|
||||
const state = {
|
||||
routes: [],
|
||||
localRoutes: [],
|
||||
@@ -319,6 +323,9 @@
|
||||
.prop('hidden', false)
|
||||
.text(ns.I18n.t("app.pause-hint"));
|
||||
showNavigation(ns.I18n.t("app.route-paused"), $('#navigation-distance').text() || '–');
|
||||
$('#navigation-arrow').prop('hidden', true);
|
||||
$('#route-navigation-arrow').prop('hidden', true);
|
||||
$('#route-navigation-mode').text(ns.I18n.t('app.route-paused'));
|
||||
updateRouteControls();
|
||||
}
|
||||
|
||||
@@ -421,7 +428,7 @@
|
||||
function poiMetrics(position) {
|
||||
if (!position || !state.route?.pois?.length) return [];
|
||||
const heading = effectiveHeading(position);
|
||||
return state.route.pois.map(poi => {
|
||||
return state.route.pois.filter(poi => Number.isFinite(poi.lat) && Number.isFinite(poi.lon)).map(poi => {
|
||||
const distance = ns.Distance.meters(position, poi);
|
||||
const bearing = ns.Distance.bearing(position, poi);
|
||||
return {
|
||||
@@ -498,49 +505,41 @@
|
||||
: ns.I18n.t("app.next-station", { value1: metric.poi.title }),
|
||||
`${distance} m`
|
||||
);
|
||||
$('#navigation-footer').attr(
|
||||
$('#station-navigation').attr(
|
||||
'aria-label',
|
||||
ns.I18n.t("app.next-station-distance", { value1: metric.poi.title, value2: distance })
|
||||
);
|
||||
}
|
||||
|
||||
function showRoutePointNavigation(position, progress) {
|
||||
const arrow = $('#route-navigation-arrow');
|
||||
const mode = $('#route-navigation-mode');
|
||||
if (!progress) {
|
||||
$('#navigation-arrow').css('transform', 'rotate(0deg)');
|
||||
showNavigation(ns.I18n.t("app.path.missing"), '–');
|
||||
arrow.css('transform', 'rotate(0deg)').prop('hidden', true);
|
||||
mode.text(ns.I18n.t('app.path.missing'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress.reached) {
|
||||
$('#navigation-arrow').css('transform', 'rotate(0deg)');
|
||||
showNavigation(ns.I18n.t("app.destination-reached"), '0 m');
|
||||
$('#navigation-footer').attr('aria-label', ns.I18n.t("app.destination-reached"));
|
||||
arrow.css('transform', 'rotate(0deg)').prop('hidden', true);
|
||||
mode.text(ns.I18n.t('app.destination-reached'));
|
||||
return;
|
||||
}
|
||||
const bearing = ns.Distance.bearing(position, progress.target);
|
||||
const heading = effectiveHeading(position);
|
||||
const rotation = heading == null
|
||||
? bearing
|
||||
: ns.Distance.normalizeDegrees(bearing - heading);
|
||||
const distance = Math.round(progress.distance);
|
||||
$('#navigation-arrow').css('transform', `rotate(${rotation.toFixed(1)}deg)`);
|
||||
showNavigation(
|
||||
heading == null ? ns.I18n.t("app.next-path-point-north") : ns.I18n.t("app.next-path-point"),
|
||||
`${distance} m`
|
||||
);
|
||||
$('#navigation-footer').attr(
|
||||
'aria-label',
|
||||
ns.I18n.t("app.next-path-point-distance", { value1: distance })
|
||||
);
|
||||
const rotation = heading == null ? bearing : ns.Distance.normalizeDegrees(bearing - heading);
|
||||
arrow.prop('hidden', false).css('transform', `rotate(${rotation.toFixed(1)}deg)`);
|
||||
mode.text(ns.I18n.t(heading == null ? 'app.next-path-point-north' : 'app.next-path-point'));
|
||||
}
|
||||
|
||||
function updateNavigation(position) {
|
||||
if (state.routeState !== 'running') return;
|
||||
const progress = updateRouteProgress(position);
|
||||
showRoutePointNavigation(position, progress);
|
||||
const metrics = updatePoiIndicators(position);
|
||||
const nextPoi = nearestPendingPoi(metrics);
|
||||
$('#navigation-arrow').prop('hidden', !nextPoi);
|
||||
if (nextPoi) showPoiNavigation(position, nextPoi);
|
||||
else showRoutePointNavigation(position, progress);
|
||||
else showNavigation(ns.I18n.t('recorder.no-station'), '–');
|
||||
}
|
||||
|
||||
function updateHeading(heading) {
|
||||
@@ -659,8 +658,23 @@
|
||||
}
|
||||
|
||||
function setRouteControlOpen(open) {
|
||||
$('#route-control-dropdown').prop('hidden', !open);
|
||||
$('#route-control-button').attr('aria-expanded', String(open));
|
||||
routeControlOpen = Boolean(open);
|
||||
globalThis.clearTimeout(routeControlCloseTimer);
|
||||
routeControlCloseTimer = null;
|
||||
const dropdown = $('#route-control-dropdown');
|
||||
$('#route-control-button').attr('aria-expanded', String(routeControlOpen));
|
||||
if (routeControlOpen) {
|
||||
dropdown.prop('hidden', false);
|
||||
const nextFrame = globalThis.requestAnimationFrame ?? (callback => callback());
|
||||
nextFrame(() => nextFrame(() => {
|
||||
if (routeControlOpen) dropdown.addClass('is-open');
|
||||
}));
|
||||
} else {
|
||||
dropdown.removeClass('is-open');
|
||||
routeControlCloseTimer = globalThis.setTimeout(() => {
|
||||
if (!routeControlOpen) dropdown.prop('hidden', true);
|
||||
}, DROPDOWN_ANIMATION_MS);
|
||||
}
|
||||
}
|
||||
|
||||
async function selectRoute(source, id) {
|
||||
@@ -718,7 +732,7 @@
|
||||
});
|
||||
|
||||
activate('#route-control-button', function () {
|
||||
setRouteControlOpen($('#route-control-dropdown').prop('hidden'));
|
||||
setRouteControlOpen(!routeControlOpen);
|
||||
});
|
||||
|
||||
activate('.route-control-actions #route-control-new', function () {
|
||||
@@ -731,7 +745,7 @@
|
||||
});
|
||||
|
||||
$(document).on('pointerup', event => {
|
||||
if ($('#route-control-dropdown').prop('hidden')) return;
|
||||
if (!routeControlOpen) return;
|
||||
if ($(event.target).closest('.route-control').length) return;
|
||||
setRouteControlOpen(false);
|
||||
});
|
||||
|
||||
+11
-11
@@ -495,6 +495,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function fillRouteForm(route) {
|
||||
setHidden(byId('editor-path-positions'), state.currentSource !== 'local');
|
||||
if (state.currentSource === 'local') ns.RouteRecorder?.renderPoints(route.gpx || ns.LocalRoutes.emptyGpx(route.name));
|
||||
byId(ids.routeId).value = routeId(route);
|
||||
byId(ids.routeName).value = routeName(route) === ns.I18n.t("editor.untitled-route") ? '' : routeName(route);
|
||||
byId(ids.routeDescription).value = text(route?.description);
|
||||
@@ -814,13 +816,15 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
async function saveLocalRoute(values) {
|
||||
const file = byId(ids.routeGpx)?.files?.[0];
|
||||
let gpx = state.currentRoute?.gpx || ns.LocalRoutes.emptyGpx(values.name);
|
||||
let gpx = ns.LocalRoutes.get?.(routeId(state.currentRoute))?.gpx || state.currentRoute?.gpx || ns.LocalRoutes.emptyGpx(values.name);
|
||||
if (file) {
|
||||
gpx = await ns.LocalRoutes.readFileAsText(file);
|
||||
const importedPois = ns.LocalRoutes.parseWaypoints(gpx);
|
||||
if (!state.pois.length && importedPois.length) state.pois = importedPois;
|
||||
}
|
||||
|
||||
gpx = ns.RouteRecorder?.editGpx(gpx, values.name) ?? gpx;
|
||||
const isNew = !routeId(state.currentRoute);
|
||||
const id = routeId(state.currentRoute) || ns.LocalRoutes.createRouteId();
|
||||
const saved = ns.LocalRoutes.save({
|
||||
id,
|
||||
@@ -835,6 +839,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
});
|
||||
state.currentRoute = { ...saved.route, id: saved.id, gpx: saved.gpx, _source: 'local' };
|
||||
state.currentSource = 'local';
|
||||
if (isNew) ns.RouteRecorder?.start(saved.id);
|
||||
state.pois = saved.pois;
|
||||
await loadRoutes();
|
||||
await loadRoute({ id: saved.id, _source: 'local' });
|
||||
@@ -989,17 +994,14 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function currentPosition() {
|
||||
if (ns.RouteRecorder?.routeId === routeId(state.currentRoute)) return ns.RouteRecorder.position;
|
||||
return typeof ns.App?.currentPosition === 'function' ? ns.App.currentPosition() : null;
|
||||
}
|
||||
|
||||
function newPoi() {
|
||||
const position = currentPosition();
|
||||
const lat = Number(position?.lat);
|
||||
const lon = Number(position?.lon);
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
|
||||
setStatus(ns.I18n.t("editor.error.location-required"), true);
|
||||
return;
|
||||
}
|
||||
const lat = position?.lat ?? null;
|
||||
const lon = position?.lon ?? null;
|
||||
|
||||
const accuracy = Number(position?.accuracy);
|
||||
state.currentPoi = null;
|
||||
@@ -1067,7 +1069,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const currentPoiId = poiId(state.currentPoi);
|
||||
const saved = ns.LocalRoutes.save({
|
||||
id,
|
||||
gpx: state.currentRoute.gpx,
|
||||
gpx: ns.LocalRoutes.get?.(routeId(state.currentRoute))?.gpx || state.currentRoute.gpx,
|
||||
route: state.currentRoute,
|
||||
pois: state.pois
|
||||
});
|
||||
@@ -1081,9 +1083,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
async function saveLocalPoi(values) {
|
||||
if (!Number.isFinite(values.lat) || !Number.isFinite(values.lon)) {
|
||||
throw new TypeError(ns.I18n.t("editor.error.station-location"));
|
||||
}
|
||||
|
||||
const currentId = numericPoiId(byId(ids.poiId).value);
|
||||
const identifier = currentId ?? nextLocalPoiId();
|
||||
byId(ids.poiId).value = String(identifier);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
}
|
||||
|
||||
ns.Geo = {
|
||||
current() {
|
||||
current(options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const service = geolocation();
|
||||
if (!service) {
|
||||
@@ -43,7 +43,8 @@
|
||||
{
|
||||
...WATCH_OPTIONS,
|
||||
timeout: ns.Config.geolocationTimeoutMs,
|
||||
maximumAge: 30000
|
||||
maximumAge: 30000,
|
||||
...options
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5,8 +5,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
const DROPDOWN_ANIMATION_MS = 180;
|
||||
const pageTitles = Object.freeze({
|
||||
get privacy() { return ns.I18n.t("info.privacy"); },
|
||||
get imprint() { return ns.I18n.t("info.imprint"); },
|
||||
privacy: 'Datenschutzerklärung',
|
||||
imprint: 'Impressum',
|
||||
get technology() { return ns.I18n.t("info.storage"); }
|
||||
});
|
||||
function menuEntries() { return [
|
||||
@@ -438,7 +438,12 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function updateDialogTitle(pageName) {
|
||||
if (elements?.title) elements.title.textContent = pageTitles[pageName] ?? ns.I18n.t("info.title");
|
||||
if (!elements?.title) return;
|
||||
const isLegalPage = pageName === 'privacy' || pageName === 'imprint';
|
||||
if (isLegalPage) delete elements.title.dataset.i18n;
|
||||
else elements.title.dataset.i18n = 'info.storage';
|
||||
setAttribute(elements.title, 'lang', isLegalPage ? 'de' : ns.I18n.language);
|
||||
elements.title.textContent = pageTitles[pageName] ?? ns.I18n.t("info.title");
|
||||
}
|
||||
|
||||
function focusSafely(element) {
|
||||
|
||||
+83
-20
@@ -298,7 +298,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function parseWaypoints(gpx) {
|
||||
const document = parseXml(gpx);
|
||||
return Array.from(document.getElementsByTagNameNS('*', 'wpt')).map((node, index) => ({
|
||||
return [...Array.from(document.getElementsByTagNameNS('*', 'wpt')), ...Array.from(document.getElementsByTagNameNS('*', 'pendingWaypoint'))].map((node, index) => ({
|
||||
id: waypointId(node),
|
||||
title: textOfChild(node, 'name') || ns.I18n.t("editor.station-number", { value1: index + 1 }),
|
||||
description: textOfChild(node, 'desc'),
|
||||
@@ -308,7 +308,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
sequence: index,
|
||||
audio: null,
|
||||
images: []
|
||||
})).filter(poi => poi.lat != null && poi.lon != null);
|
||||
}));
|
||||
}
|
||||
|
||||
function createElement(document, localName, text = null) {
|
||||
@@ -337,7 +337,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
let track = directChildrenByLocalName(root, 'trk')[0];
|
||||
if (!track) {
|
||||
track = createElement(document, 'trk');
|
||||
root.appendChild(track);
|
||||
root.insertBefore(track, directChildrenByLocalName(root, 'extensions')[0] || null);
|
||||
}
|
||||
|
||||
let trackName = directChildrenByLocalName(track, 'name')[0];
|
||||
@@ -364,24 +364,26 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const document = parseXml(gpx || emptyGpx(routeName));
|
||||
updateMetadataName(document, routeName);
|
||||
|
||||
// Wegwichtel verwaltet neue Stationen direkt als Punkte im GPX-Track.
|
||||
// Stationen sind Wegpunkte; aufgezeichnete Trackpunkte bleiben getrennt.
|
||||
// Fremde/importierte GPX-Punkte ohne Wegwichtel-ID bleiben erhalten.
|
||||
Array.from(document.getElementsByTagNameNS('*', 'wpt')).forEach(node => node.remove());
|
||||
Array.from(document.getElementsByTagNameNS('*', 'pendingWaypoint')).forEach(node => node.remove());
|
||||
Array.from(document.getElementsByTagNameNS('*', 'trkpt'))
|
||||
.filter(isManagedGpxPoint)
|
||||
.forEach(node => node.remove());
|
||||
|
||||
const segment = ensureTrackSegment(document, routeName);
|
||||
const root = document.documentElement;
|
||||
const following = Array.from(root.children).find(node => ['rte', 'trk', 'extensions'].includes(node.localName));
|
||||
const orderedPois = [...(pois || [])].sort((left, right) => Number(left.sequence) - Number(right.sequence));
|
||||
orderedPois.forEach((poi, index) => {
|
||||
const title = poi.title || ns.I18n.t("editor.station-number", { value1: index + 1 });
|
||||
if (!Number.isFinite(Number(poi.lat)) || !Number.isFinite(Number(poi.lon))) {
|
||||
throw new TypeError(ns.I18n.t("local.error.station-location", { value1: title }));
|
||||
const located = poi.lat != null && poi.lon != null && Number.isFinite(Number(poi.lat)) && Number.isFinite(Number(poi.lon));
|
||||
const gpxPoint = located ? createElement(document, 'wpt')
|
||||
: document.createElementNS(POI_NAMESPACE, 'wegwichtel:pendingWaypoint');
|
||||
if (located) {
|
||||
gpxPoint.setAttribute('lat', String(Number(poi.lat)));
|
||||
gpxPoint.setAttribute('lon', String(Number(poi.lon)));
|
||||
}
|
||||
|
||||
const gpxPoint = createElement(document, 'trkpt');
|
||||
gpxPoint.setAttribute('lat', String(Number(poi.lat)));
|
||||
gpxPoint.setAttribute('lon', String(Number(poi.lon)));
|
||||
gpxPoint.appendChild(createElement(document, 'name', title));
|
||||
if (poi.description) gpxPoint.appendChild(createElement(document, 'desc', poi.description));
|
||||
const extensions = createElement(document, 'extensions');
|
||||
@@ -389,12 +391,71 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
poiId.textContent = String(poi.id);
|
||||
extensions.appendChild(poiId);
|
||||
gpxPoint.appendChild(extensions);
|
||||
segment.appendChild(gpxPoint);
|
||||
if (located) root.insertBefore(gpxPoint, following || null);
|
||||
else {
|
||||
let pending = directChildrenByLocalName(root, 'extensions')[0];
|
||||
if (!pending) { pending = createElement(document, 'extensions'); root.appendChild(pending); }
|
||||
pending.appendChild(gpxPoint);
|
||||
}
|
||||
});
|
||||
|
||||
return new XMLSerializer().serializeToString(document);
|
||||
}
|
||||
|
||||
function appendTrackPoint(gpx, position, routeName) {
|
||||
const document = parseXml(gpx);
|
||||
appendPosition(document, position, routeName);
|
||||
return new XMLSerializer().serializeToString(document);
|
||||
}
|
||||
|
||||
function appendPosition(document, position, routeName) {
|
||||
const lat = position.lat == null ? NaN : Number(position.lat);
|
||||
const lon = position.lon == null ? NaN : Number(position.lon);
|
||||
const timestamp = new Date(position.timestamp ?? Date.now()).toISOString();
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lon) || Math.abs(lat) > 90 || Math.abs(lon) > 180) {
|
||||
const root = document.documentElement;
|
||||
let extensions = directChildrenByLocalName(root, 'extensions')[0];
|
||||
if (!extensions) { extensions = createElement(document, 'extensions'); root.appendChild(extensions); }
|
||||
const gap = document.createElementNS(POI_NAMESPACE, 'wegwichtel:gpsGap');
|
||||
gap.setAttribute('time', timestamp);
|
||||
extensions.appendChild(gap);
|
||||
return;
|
||||
}
|
||||
const point = createElement(document, 'trkpt');
|
||||
point.setAttribute('lat', String(lat));
|
||||
point.setAttribute('lon', String(lon));
|
||||
if (Number.isFinite(position.altitude)) point.appendChild(createElement(document, 'ele', position.altitude));
|
||||
point.appendChild(createElement(document, 'time', timestamp));
|
||||
ensureTrackSegment(document, routeName).appendChild(point);
|
||||
}
|
||||
|
||||
function recordedPositions(gpx) {
|
||||
const document = parseXml(gpx);
|
||||
const routes = Array.from(document.getElementsByTagNameNS('*', 'rtept'));
|
||||
const tracks = Array.from(document.getElementsByTagNameNS('*', 'trkpt')).filter(node => !isManagedGpxPoint(node));
|
||||
const nodes = routes.length ? routes : tracks;
|
||||
const positions = nodes.map(node => ({
|
||||
lat: numberAttribute(node, 'lat'), lon: numberAttribute(node, 'lon'),
|
||||
altitude: Number.parseFloat(textOfChild(node, 'ele')),
|
||||
timestamp: textOfChild(node, 'time') || null
|
||||
}));
|
||||
for (const node of Array.from(document.getElementsByTagNameNS('*', 'gpsGap'))) {
|
||||
positions.push({ lat: null, lon: null, altitude: null, timestamp: node.getAttribute('time') });
|
||||
}
|
||||
return positions.sort((left, right) => left.timestamp && right.timestamp ? Date.parse(left.timestamp) - Date.parse(right.timestamp) : 0);
|
||||
}
|
||||
|
||||
function replaceRecordedPositions(gpx, positions, routeName) {
|
||||
const document = parseXml(gpx);
|
||||
for (const name of ['trkpt', 'rtept', 'gpsGap']) {
|
||||
Array.from(document.getElementsByTagNameNS('*', name)).forEach(node => node.remove());
|
||||
}
|
||||
for (const position of positions) appendPosition(document, {
|
||||
...position, timestamp: position.timestamp ? Date.parse(position.timestamp) : Date.now()
|
||||
}, routeName);
|
||||
return new XMLSerializer().serializeToString(document);
|
||||
}
|
||||
|
||||
function readPackage(id) {
|
||||
const target = storage();
|
||||
const gpx = target.getItem(routeKey(id, 'gpx'));
|
||||
@@ -501,7 +562,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const document = parseXml(gpx);
|
||||
const gpxPoints = Array.from(document.getElementsByTagNameNS('*', 'trkpt'));
|
||||
const routePoints = Array.from(document.getElementsByTagNameNS('*', 'rtept'));
|
||||
const selected = gpxPoints.length ? gpxPoints : routePoints;
|
||||
const selected = routePoints.length ? routePoints : gpxPoints.filter(node => !isManagedGpxPoint(node));
|
||||
return selected.map(node => {
|
||||
const elevation = Number.parseFloat(textOfChild(node, 'ele'));
|
||||
return {
|
||||
@@ -515,7 +576,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function gpxForUpload(routePackage) {
|
||||
if (!routePackage?.gpx) throw new Error(ns.I18n.t("local.error.path-missing"));
|
||||
if (!routePoints(routePackage.gpx).length) {
|
||||
if (!routePoints(routePackage.gpx).length && !parseWaypoints(routePackage.gpx).length && !recordedPositions(routePackage.gpx).length) {
|
||||
throw new Error(ns.I18n.t("local.error.path-empty"));
|
||||
}
|
||||
return routePackage.gpx;
|
||||
@@ -579,8 +640,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
id: Number(poi.id),
|
||||
title: poi.title || ns.I18n.t("editor.untitled-station"),
|
||||
description: poi.description || '',
|
||||
lat: Number(poi.lat),
|
||||
lon: Number(poi.lon),
|
||||
lat: poi.lat == null ? null : Number(poi.lat),
|
||||
lon: poi.lon == null ? null : Number(poi.lon),
|
||||
triggerRadiusM: Number(poi.triggerRadiusM) || 25,
|
||||
sequence: Number(poi.sequence) || 0,
|
||||
audioUrl: poi.audio?.url || poi.audio?.dataUrl || null,
|
||||
@@ -596,10 +657,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
function toAppRoute(routePackage) {
|
||||
const pois = (routePackage.pois || []).map(appPoi).sort((left, right) => left.sequence - right.sequence);
|
||||
const parsedPoints = routePoints(routePackage.gpx);
|
||||
const points = parsedPoints.length
|
||||
? parsedPoints
|
||||
: pois.map(poi => ({ lat: poi.lat, lon: poi.lon, elevation: null, recordedAt: null }));
|
||||
const routeMetrics = metrics(points);
|
||||
const points = parsedPoints;
|
||||
const routeMetrics = metrics(points.length ? points : pois.filter(poi => poi.lat != null && poi.lon != null));
|
||||
if (!points.length) { routeMetrics.distanceM = 0; routeMetrics.elevationGainM = 0; }
|
||||
return {
|
||||
id: String(routePackage.id),
|
||||
source: 'local',
|
||||
@@ -664,6 +724,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
ns.LocalRoutes = Object.freeze({
|
||||
STORAGE_PREFIX,
|
||||
appendTrackPoint,
|
||||
recordedPositions,
|
||||
replaceRecordedPositions,
|
||||
createPoiId,
|
||||
createRouteId,
|
||||
emptyGpx,
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
globalThis.Wegwichtel ??= {};
|
||||
(function (ns) {
|
||||
'use strict';
|
||||
const INTERVAL_MS = 30000;
|
||||
let id = null;
|
||||
let status = 'idle';
|
||||
let timer = null;
|
||||
let generation = 0;
|
||||
let pending = false;
|
||||
let message = '';
|
||||
let manualFields = [];
|
||||
let lastPosition = null;
|
||||
|
||||
function render() {
|
||||
const control = document.getElementById('route-recording-control');
|
||||
if (!control) return;
|
||||
control.hidden = status === 'idle';
|
||||
document.getElementById('route-recording-status').textContent = status === 'idle' ? '' : message || ns.I18n.t(`recorder.${status}`);
|
||||
document.getElementById('route-recording-pause').textContent = ns.I18n.t(status === 'paused' ? 'recorder.resume' : 'recorder.pause');
|
||||
}
|
||||
|
||||
async function sample() {
|
||||
if (pending || status !== 'recording') return;
|
||||
pending = true;
|
||||
const currentGeneration = generation;
|
||||
try {
|
||||
let position;
|
||||
try { position = await ns.Geo.current({ maximumAge: 0 }); }
|
||||
catch { position = { timestamp: Date.now() }; }
|
||||
if (currentGeneration !== generation || status !== 'recording') return;
|
||||
lastPosition = Number.isFinite(position.lat) && Number.isFinite(position.lon) ? position : null;
|
||||
const route = ns.LocalRoutes.get(id);
|
||||
if (!route) { stop(); return; }
|
||||
const gpx = ns.LocalRoutes.appendTrackPoint(route.gpx, position, route.route.name);
|
||||
ns.LocalRoutes.save({ ...route, gpx });
|
||||
message = ns.I18n.t(Number.isFinite(position.lat) && Number.isFinite(position.lon) ? 'recorder.recording' : 'recorder.no-location');
|
||||
} catch (error) {
|
||||
pause();
|
||||
ns.StorageUsage?.reportError(error);
|
||||
message = ns.I18n.t('recorder.save-error');
|
||||
} finally {
|
||||
pending = false;
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
function clearTimer() {
|
||||
if (timer !== null) globalThis.clearInterval(timer);
|
||||
timer = null;
|
||||
generation += 1;
|
||||
}
|
||||
|
||||
function resume() {
|
||||
if (!id) return;
|
||||
clearTimer();
|
||||
status = 'recording';
|
||||
message = '';
|
||||
timer = globalThis.setInterval(sample, INTERVAL_MS);
|
||||
sample();
|
||||
render();
|
||||
}
|
||||
|
||||
function pause() {
|
||||
clearTimer();
|
||||
status = id ? 'paused' : 'idle';
|
||||
message = '';
|
||||
render();
|
||||
}
|
||||
|
||||
function stop() {
|
||||
clearTimer();
|
||||
id = null;
|
||||
lastPosition = null;
|
||||
status = 'idle';
|
||||
message = '';
|
||||
render();
|
||||
}
|
||||
|
||||
function start(routeId) {
|
||||
lastPosition = null;
|
||||
id = String(routeId);
|
||||
resume();
|
||||
}
|
||||
|
||||
function addPositionField(position = {}, index = null) {
|
||||
const container = document.getElementById('editor-recorded-positions');
|
||||
if (!container) return;
|
||||
const row = document.createElement('fieldset');
|
||||
const legend = document.createElement('legend');
|
||||
legend.textContent = ns.I18n.t('recorder.position-number', { number: manualFields.length + 1 });
|
||||
row.appendChild(legend);
|
||||
const fields = {};
|
||||
for (const [key, textKey, minimum, maximum] of [['lat', 'latitude', -90, 90], ['lon', 'longitude', -180, 180]]) {
|
||||
const label = document.createElement('label');
|
||||
const input = document.createElement('input');
|
||||
input.id = `recorded-position-${manualFields.length}-${key}`;
|
||||
label.setAttribute('for', input.id);
|
||||
label.textContent = ns.I18n.t(`recorder.${textKey}`);
|
||||
input.type = 'number'; input.step = 'any'; input.min = minimum; input.max = maximum;
|
||||
input.value = position[key] == null ? '' : String(position[key]);
|
||||
row.appendChild(label); row.appendChild(input);
|
||||
fields[key] = input;
|
||||
}
|
||||
manualFields.push({ index, original: position, ...fields });
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
function renderPoints(gpx) {
|
||||
const container = document.getElementById('editor-recorded-positions');
|
||||
if (!container) return;
|
||||
container.replaceChildren();
|
||||
manualFields = [];
|
||||
ns.LocalRoutes.recordedPositions(gpx).forEach(addPositionField);
|
||||
}
|
||||
|
||||
function editGpx(gpx, routeName) {
|
||||
let changed = false;
|
||||
const positions = ns.LocalRoutes.recordedPositions(gpx);
|
||||
for (const field of manualFields) {
|
||||
const values = ['lat', 'lon'].map(key => field[key].value.trim() === '' ? null : Number(field[key].value));
|
||||
const [lat, lon] = values;
|
||||
if ((lat === null) !== (lon === null) || (lat !== null && (!Number.isFinite(lat) || !Number.isFinite(lon) || Math.abs(lat) > 90 || Math.abs(lon) > 180))) {
|
||||
throw new Error(ns.I18n.t('editor.error.station-location'));
|
||||
}
|
||||
if (field.index !== null && lat === field.original.lat && lon === field.original.lon) continue;
|
||||
const point = { ...field.original, lat, lon };
|
||||
if (field.index === null) positions.push(point);
|
||||
else positions[field.index] = point;
|
||||
changed = true;
|
||||
}
|
||||
return changed ? ns.LocalRoutes.replaceRecordedPositions(gpx, positions, routeName) : gpx;
|
||||
}
|
||||
|
||||
function bind() {
|
||||
const activate = (elementId, action) => {
|
||||
const element = document.getElementById(elementId);
|
||||
element?.addEventListener('pointerup', event => {
|
||||
if (event.isPrimary === false || (event.pointerType === 'mouse' && event.button !== 0)) return;
|
||||
event.preventDefault();
|
||||
action();
|
||||
});
|
||||
element?.addEventListener('keydown', event => {
|
||||
if (event.key !== 'Enter' && event.key !== ' ') return;
|
||||
event.preventDefault();
|
||||
action();
|
||||
});
|
||||
};
|
||||
activate('route-recording-pause', () => status === 'recording' ? pause() : resume());
|
||||
activate('route-recording-stop', stop);
|
||||
activate('editor-add-position', () => addPositionField({ timestamp: new Date().toISOString() }));
|
||||
document.addEventListener('wegwichtel:local-routes-changed', () => {
|
||||
if (id && !ns.LocalRoutes.get(id)) stop();
|
||||
});
|
||||
}
|
||||
|
||||
ns.RouteRecorder = Object.freeze({ start, pause, resume, stop, renderPoints, editGpx, get status() { return status; }, get routeId() { return id; }, get position() { return lastPosition; } });
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', bind, { once: true });
|
||||
else bind();
|
||||
}(globalThis.Wegwichtel));
|
||||
+20
-77
@@ -7,6 +7,7 @@ globalThis.Wegwichtel ??= {};
|
||||
static messages = Object.freeze(
|
||||
{
|
||||
"app": {
|
||||
"no-tracking": "Hier gibt es keine Werbung. Wir verfolgen nicht, welche anderen Seiten du besuchst.",
|
||||
"resume-hint": "Du kannst dort weitermachen, wo du aufgehört hast.",
|
||||
"draft": "Eigener Entwurf",
|
||||
"choose-route": "Strecke wählen",
|
||||
@@ -367,29 +368,6 @@ globalThis.Wegwichtel ??= {};
|
||||
"experiences": "Erlebnisse"
|
||||
}
|
||||
},
|
||||
"privacy": {
|
||||
"no-tracking": "Hier gibt es keine Werbung. Wir verfolgen nicht, welche anderen Seiten du besuchst.",
|
||||
"incomplete-notice": "Diese Angaben sind noch nicht vollständig. Die Kontakte stammen von der Grundschule Herpf. Wer die Website betreibt, welche Verbindungsdaten gespeichert werden und wie lange sie bleiben, muss noch ergänzt werden.",
|
||||
"controller-title": "1. Verantwortliche Stelle und Datenschutzkontakt",
|
||||
"connection-title": "2. Wenn du Wegwichtel öffnest",
|
||||
"connection-data": "Wenn du Wegwichtel öffnest, können Verbindungsdaten verarbeitet werden. Dazu gehören zum Beispiel die Internetadresse deines Geräts, Datum, Uhrzeit und Zeitzone, die aufgerufene Seite, übertragene Daten und ob der Aufruf geklappt hat. Auch die vorherige Seite und Angaben zu deinem Gerät, Internetbrowser und dessen Sprache können dazugehören. Diese Daten helfen dabei, die Website bereitzustellen, Fehler zu finden und sie zu schützen.",
|
||||
"provider-label": "Wer die Website bereitstellt und welche Verbindungsdaten wie lange gespeichert werden:",
|
||||
"provider-placeholder": "[Anbieter, Anschrift, gespeicherte Daten und Speicherdauer ergänzen]",
|
||||
"location-title": "3. Standortdaten",
|
||||
"location-data": "Du entscheidest, ob Wegwichtel deinen Standort nutzen darf. Damit findest du Strecken in deiner Nähe und siehst den Weg zur nächsten Station. Dein laufender Standort wird auf deinem Gerät verarbeitet. Wegwichtel speichert daraus keinen Verlauf auf der Website.",
|
||||
"progress-title": "4. Deinen Fortschritt merken",
|
||||
"progress-data": "Wenn du „Meinen Fortschritt merken“ einschaltest, speichert Wegwichtel deine gewählte Strecke, besuchte und angesehene Stationen sowie angehörte Tonaufnahmen. Auch ob du unterwegs bist, eine Pause machst oder fertig bist und der Zeitpunkt werden gespeichert. Diese Angaben bleiben auf deinem Gerät und werden nicht an die Website gesendet.",
|
||||
"progress-deletion": "Wenn du deinen Fortschritt mindestens einen Tag lang nicht verändert hast, wird er beim nächsten Öffnen gelöscht. Beim Ausschalten wird er sofort gelöscht. Deine eigenen und für unterwegs gespeicherten Strecken bleiben erhalten.",
|
||||
"drafts-title": "5. Deine eigenen Strecken",
|
||||
"draft-data": "Neue Strecken bleiben zuerst auf deinem Gerät. Gespeichert werden der Weg, die Orte der Stationen, Texte sowie ausgewählte Bilder und Tonaufnahmen.",
|
||||
"draft-deletion": "Deine Entwürfe bleiben erhalten, wenn alter Fortschritt gelöscht wird oder du „Meinen Fortschritt merken“ ausschaltest. Sie bleiben auf diesem Gerät, bis du sie löschst oder die gespeicherten Daten von Wegwichtel in deinem Internetbrowser entfernst. Nur wenn du „Zur Prüfung senden“ wählst, wird deine Strecke an die Website gesendet.",
|
||||
"settings-title": "6. Werbung und gespeicherte Einstellungen",
|
||||
"settings-data": "Wegwichtel verwendet keine Cookies. Es zählt keine Besuche für Werbung und verfolgt nicht, welche anderen Seiten du besuchst. Auf deinem Gerät wird gespeichert, ob du „Meinen Fortschritt merken“ eingeschaltet hast.",
|
||||
"children-title": "7. Inhalte von Schülerinnen und Schülern",
|
||||
"children-permission": "Bilder, Texte und Tonaufnahmen dürfen nur geteilt werden, wenn das erlaubt ist. Wenn Kinder auf Bildern oder in Aufnahmen erkannt werden können, müssen die Regeln der Schule beachtet werden. Auch die Eltern oder anderen Sorgeberechtigten müssen die nötige Erlaubnis geben.",
|
||||
"rights-title": "8. Deine Rechte",
|
||||
"rights-data": "Du kannst fragen, welche Daten über dich gespeichert sind. Unter den gesetzlichen Voraussetzungen kannst du verlangen, dass sie berichtigt, gelöscht, nur noch eingeschränkt genutzt oder dir zur Weitergabe bereitgestellt werden. Du kannst der Nutzung widersprechen und eine erteilte Erlaubnis für die Zukunft zurücknehmen. Wenn du dich über den Umgang mit deinen Daten beschweren möchtest, kannst du dich an die folgende Datenschutzbehörde wenden."
|
||||
},
|
||||
"progress": {
|
||||
"cookies-label": "Optionale Cookies",
|
||||
"cookies-unused": "Diese Funktion wird nicht verwendet.",
|
||||
@@ -428,60 +406,7 @@ globalThis.Wegwichtel ??= {};
|
||||
"unsupported": "Dieses Gerät kann den Ton leider nicht abspielen."
|
||||
},
|
||||
"navigation": {
|
||||
"station-direction": "Richtung zum nächsten Station"
|
||||
},
|
||||
"contacts": {
|
||||
"school": {
|
||||
"address": "Zum Eichig 3",
|
||||
"city": "98617 Meiningen / OT Herpf",
|
||||
"phone": "Telefon: (036943) 63722",
|
||||
"email": "E-Mail: info@grundschule-herpf.de",
|
||||
"name": "Staatliche Grundschule Herpf",
|
||||
"privacy-label": "Datenschutzangaben der Schule:",
|
||||
"fax": "Telefax: (036943) 63843",
|
||||
"head": "Frau Wichert, Schulleiterin",
|
||||
"content-owner": "Frau Wichert"
|
||||
},
|
||||
"privacy": {
|
||||
"role": "Datenschutzbeauftragter",
|
||||
"address": "Hölderlinstraße 1",
|
||||
"city": "98527 Suhl",
|
||||
"phone": "Telefon: 03681 / 7341 25",
|
||||
"fax": "Fax: 03681 / 7341 09",
|
||||
"email": "E-Mail: datenschutz.suedthueriungen@schulamt.thueringen.de",
|
||||
"name": "Staatliches Schulamt Südthüringen",
|
||||
"postal-hint": "Der Datenschutzbeauftragte kann außerdem über die Postadresse der Schule mit dem Zusatz „der Datenschutzbeauftragte“ erreicht werden."
|
||||
},
|
||||
"authority": {
|
||||
"label": "Zuständige Datenschutzaufsicht:",
|
||||
"postal-address": "Postfach 90 04 55, 99107 Erfurt",
|
||||
"address": "Häßlerstraße 8, 99096 Erfurt",
|
||||
"phone": "Telefon: 0361 / 57 311 29 00",
|
||||
"fax": "Telefax: 0361 / 57 311 29 04",
|
||||
"email": "E-Mail: poststelle@datenschutz.thueringen.de",
|
||||
"website": "Website: www.tlfdi.de",
|
||||
"name": "Thüringer Landesbeauftragter für den Datenschutz und die Informationsfreiheit (TlfDI)"
|
||||
},
|
||||
"sponsor": {
|
||||
"role": "Landratsamt",
|
||||
"address": "Obertshäuser Platz 1",
|
||||
"city": "98617 Meiningen",
|
||||
"name": "Landkreis Schmalkalden-Meiningen"
|
||||
}
|
||||
},
|
||||
"imprint": {
|
||||
"incomplete-notice": "Diese Angaben stammen von der Grundschule Herpf. Vor der Veröffentlichung muss geprüft werden, ob für Wegwichtel noch weitere oder andere Angaben nötig sind.",
|
||||
"controller-title": "Wer für Wegwichtel verantwortlich ist",
|
||||
"contact-title": "Kontakt",
|
||||
"head-title": "Leitung der Schule",
|
||||
"sponsor-title": "Schulträger",
|
||||
"content-title": "Inhaltlich verantwortlich",
|
||||
"required-title": "Weitere Pflichtangaben",
|
||||
"required-data": "Je nachdem, wer Wegwichtel betreibt, können weitere Angaben nötig sein. Dazu gehören zum Beispiel die Verantwortlichen für den Betrieb der Website. Diese Angaben müssen noch geprüft werden.",
|
||||
"liability-title": "Haftung für Inhalte und Verweise",
|
||||
"liability-data": "Die Inhalte werden sorgfältig erstellt und regelmäßig geprüft. Falls etwas falsch, veraltet oder nicht erlaubt ist, melde dich beim Kontakt oben. Für andere verlinkte Seiten sind deren Betreiber verantwortlich.",
|
||||
"copyright-title": "Urheber- und Nutzungsrechte",
|
||||
"copyright-data": "Wenn nichts anderes angegeben ist, liegen die Rechte bei der Grundschule Herpf. Du darfst Texte, Bilder, Tonaufnahmen und Wege nur so nutzen, wie es jeweils erlaubt wurde. Auch die Rechte der beteiligten Kinder, Familien, Lehrkräfte und anderen Personen bleiben bestehen."
|
||||
"station-direction": "Richtung zur nächsten Station"
|
||||
},
|
||||
"storage-help": {
|
||||
"progress-title": "Was merkt sich Wegwichtel?",
|
||||
@@ -521,6 +446,24 @@ globalThis.Wegwichtel ??= {};
|
||||
"read": {
|
||||
"failed": "Die Datei konnte nicht geöffnet werden. Wähle sie noch einmal aus."
|
||||
}
|
||||
},
|
||||
"recorder": {
|
||||
"recording": "Dein Weg wird aufgenommen.",
|
||||
"paused": "Die Aufnahme macht eine Pause.",
|
||||
"pause": "Aufnahme pausieren",
|
||||
"resume": "Weiter aufnehmen",
|
||||
"stop": "Aufnahme beenden",
|
||||
"no-location": "Dein Standort fehlt gerade. Die Aufnahme läuft weiter.",
|
||||
"save-error": "Die Aufnahme wurde pausiert. Schaffe Platz auf deinem Gerät und versuche es erneut.",
|
||||
"manual-location": "Ort ergänzen oder ändern",
|
||||
"latitude": "Breitengrad",
|
||||
"longitude": "Längengrad",
|
||||
"path-direction": "Dem Weg folgen",
|
||||
"no-station": "Keine weitere Station mit bekanntem Ort",
|
||||
"edit-path": "Orte auf dem Weg ergänzen",
|
||||
"edit-help": "Fehlende Orte kannst du später eintragen. Leere Felder bleiben gespeichert.",
|
||||
"add-position": "Ort auf dem Weg hinzufügen",
|
||||
"position-number": "Ort {number}"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
+19
-76
@@ -7,6 +7,7 @@ globalThis.Wegwichtel ??= {};
|
||||
static messages = Object.freeze(
|
||||
{
|
||||
"app": {
|
||||
"no-tracking": "There are no adverts here. We do not track which other websites you visit.",
|
||||
"resume-hint": "You can carry on where you left off.",
|
||||
"draft": "My draft",
|
||||
"choose-route": "Choose a trail",
|
||||
@@ -367,29 +368,6 @@ globalThis.Wegwichtel ??= {};
|
||||
"experiences": "Adventures"
|
||||
}
|
||||
},
|
||||
"privacy": {
|
||||
"no-tracking": "There are no adverts here. We do not track which other websites you visit.",
|
||||
"incomplete-notice": "This information is not complete yet. The contact details are from Grundschule Herpf. The website operator, the connection data stored and how long it is kept still need to be added.",
|
||||
"controller-title": "1. Who is responsible and the privacy contact",
|
||||
"connection-title": "2. When you open Wegwichtel",
|
||||
"connection-data": "When you open Wegwichtel, connection data may be processed. This may include your device’s internet address, the date, time and time zone, the page you opened, data transferred and whether the request worked. It may also include the previous page and details of your device, internet app and its language. This data helps to provide the website, find problems and keep it safe.",
|
||||
"provider-label": "Who provides the website, which connection data is stored and how long it is kept:",
|
||||
"provider-placeholder": "[Add provider, address, stored data and retention period]",
|
||||
"location-title": "3. Location data",
|
||||
"location-data": "You decide whether Wegwichtel may use your location. This helps you find trails nearby and see the way to the next stop. Your current location is processed on your device. Wegwichtel does not save a history of your movements on the website.",
|
||||
"progress-title": "4. Remembering your progress",
|
||||
"progress-data": "When you turn on “Remember my progress”, Wegwichtel saves your selected trail, stops you have reached or viewed and recordings you have listened to. It also saves whether you are on the trail, taking a break or finished, and the time. This information stays on your device and is not sent to the website.",
|
||||
"progress-deletion": "If your progress has not changed for at least one day, it is deleted the next time you open the app. Turning the switch off deletes it straight away. Your own trails and trails saved for your trip are kept.",
|
||||
"drafts-title": "5. Your own trails",
|
||||
"draft-data": "New trails stay on your device for now. The path, stop locations, text and selected pictures and recordings are saved.",
|
||||
"draft-deletion": "Your drafts are kept when old progress is deleted or you turn off “Remember my progress”. They stay on this device until you delete them or clear Wegwichtel’s saved data in your internet app. Your trail is only sent to the website when you choose “Send for review”.",
|
||||
"settings-title": "6. Adverts and saved settings",
|
||||
"settings-data": "Wegwichtel does not use cookies. It does not count visits for advertising or track which other websites you visit. Your device saves whether you have turned on “Remember my progress”.",
|
||||
"children-title": "7. Content from schoolchildren",
|
||||
"children-permission": "Pictures, text and recordings may only be shared when permission has been given. If children can be recognised in pictures or recordings, the school’s rules must be followed. Parents or other people with parental responsibility must also give the necessary permission.",
|
||||
"rights-title": "8. Your rights",
|
||||
"rights-data": "You can ask what data about you is stored. Where the law allows, you can ask for it to be corrected, deleted, used only in a limited way or provided to you so you can pass it on. You can object to its use and withdraw permission for future use. If you want to complain about how your data is handled, you can contact the data protection authority below."
|
||||
},
|
||||
"progress": {
|
||||
"cookies-label": "Optional cookies",
|
||||
"cookies-unused": "This feature is not used.",
|
||||
@@ -430,59 +408,6 @@ globalThis.Wegwichtel ??= {};
|
||||
"navigation": {
|
||||
"station-direction": "Direction to the next stop"
|
||||
},
|
||||
"contacts": {
|
||||
"school": {
|
||||
"address": "Zum Eichig 3",
|
||||
"city": "98617 Meiningen / OT Herpf",
|
||||
"phone": "Phone: (036943) 63722",
|
||||
"email": "Email: info@grundschule-herpf.de",
|
||||
"name": "Staatliche Grundschule Herpf",
|
||||
"privacy-label": "The school’s privacy contact:",
|
||||
"fax": "Fax: (036943) 63843",
|
||||
"head": "Ms Wichert, headteacher",
|
||||
"content-owner": "Ms Wichert"
|
||||
},
|
||||
"privacy": {
|
||||
"role": "Data protection officer",
|
||||
"address": "Hölderlinstraße 1",
|
||||
"city": "98527 Suhl",
|
||||
"phone": "Phone: 03681 / 7341 25",
|
||||
"fax": "Fax: 03681 / 7341 09",
|
||||
"email": "Email: datenschutz.suedthueriungen@schulamt.thueringen.de",
|
||||
"name": "Staatliches Schulamt Südthüringen",
|
||||
"postal-hint": "You can also contact the data protection officer by writing to the school’s postal address and adding “der Datenschutzbeauftragte”."
|
||||
},
|
||||
"authority": {
|
||||
"label": "Responsible data protection authority:",
|
||||
"postal-address": "Postfach 90 04 55, 99107 Erfurt",
|
||||
"address": "Häßlerstraße 8, 99096 Erfurt",
|
||||
"phone": "Phone: 0361 / 57 311 29 00",
|
||||
"fax": "Fax: 0361 / 57 311 29 04",
|
||||
"email": "Email: poststelle@datenschutz.thueringen.de",
|
||||
"website": "Website: www.tlfdi.de",
|
||||
"name": "Thüringer Landesbeauftragter für den Datenschutz und die Informationsfreiheit (TlfDI)"
|
||||
},
|
||||
"sponsor": {
|
||||
"role": "District administration",
|
||||
"address": "Obertshäuser Platz 1",
|
||||
"city": "98617 Meiningen",
|
||||
"name": "Landkreis Schmalkalden-Meiningen"
|
||||
}
|
||||
},
|
||||
"imprint": {
|
||||
"incomplete-notice": "This information comes from Grundschule Herpf. Before publication, check whether Wegwichtel needs any additional or different information.",
|
||||
"controller-title": "Who is responsible for Wegwichtel",
|
||||
"contact-title": "Contact",
|
||||
"head-title": "School leadership",
|
||||
"sponsor-title": "School authority",
|
||||
"content-title": "Responsible for content",
|
||||
"required-title": "Further required information",
|
||||
"required-data": "Depending on who operates Wegwichtel, further information may be required. This may include the people responsible for operating the website. These details still need to be checked.",
|
||||
"liability-title": "Responsibility for content and links",
|
||||
"liability-data": "The content is prepared carefully and checked regularly. If something is wrong, out of date or not allowed, please use the contact details above to let us know. Other website operators are responsible for their own linked pages.",
|
||||
"copyright-title": "Copyright and rights of use",
|
||||
"copyright-data": "Unless stated otherwise, the rights belong to Grundschule Herpf. You may only use text, pictures, recordings and paths in the ways permitted for each item. The rights of the children, families, teachers and other people involved remain in place."
|
||||
},
|
||||
"storage-help": {
|
||||
"progress-title": "What does Wegwichtel remember?",
|
||||
"progress-data": "You can save your progress on this device. Next time you open Wegwichtel, it will know which stops you have visited or viewed and which recordings you have listened to.",
|
||||
@@ -521,6 +446,24 @@ globalThis.Wegwichtel ??= {};
|
||||
"read": {
|
||||
"failed": "The file could not be opened. Choose it again."
|
||||
}
|
||||
},
|
||||
"recorder": {
|
||||
"recording": "Your trail is being recorded.",
|
||||
"paused": "Recording is paused.",
|
||||
"pause": "Pause recording",
|
||||
"resume": "Resume recording",
|
||||
"stop": "Finish recording",
|
||||
"no-location": "Your location is unavailable. Recording will continue.",
|
||||
"save-error": "Recording was paused. Free up space on your device and try again.",
|
||||
"manual-location": "Add or change the location",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Longitude",
|
||||
"path-direction": "Follow the trail",
|
||||
"no-station": "No further stop with a known location",
|
||||
"edit-path": "Add locations along the trail",
|
||||
"edit-help": "You can fill in missing locations later. Empty fields remain saved.",
|
||||
"add-position": "Add a location along the trail",
|
||||
"position-number": "Location {number}"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user