Swedish adaptation: Instegscertifikat and HAREC
- Editions replaced by INSTEG, HAREC and UPPGRADERING (Instegscertifikat -> HAREC) - Question pool optional; simulator, homework tool and solutions switch off without one - All UI strings, templates, renderers and project JS localised to sv-SE (decimal comma, Swedish non-breaking-space rules, Å/Ä/Ö in Morse table) - DARC branding, membership CTA and German links removed; attribution footer added - Page names centralised in src/pages.py - README and docs rewritten in Swedish Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@@ -167,4 +167,7 @@ test/acceptanceTestSlides.html
|
||||
.DS_Store
|
||||
.envrc
|
||||
config/config.json
|
||||
tmp/
|
||||
tmp/
|
||||
# local build artefacts
|
||||
/build/
|
||||
/config/config.json
|
||||
|
||||
@@ -1,63 +1,128 @@
|
||||
# 50ohm.de
|
||||
# 50Ω – svensk adaption
|
||||
|
||||
50ohm.de ist die Ausbildungsplattform des DARC e.V.
|
||||
Generator för en svensk webbplats för självstudier inför **Instegscertifikatet** och **HAREC**. Projektet är en oberoende svensk adaption av [50ohm.de](https://50ohm.de) och drivs varken av DARC e.V. eller av SSA.
|
||||
|
||||
Dieses Repository enthält den Generator für die Seite [50ohm.de](https://50ohm.de), der mit einem andern [Repository](https://github.com/DARC-e-V/50ohm-contents-dl/) als Quelle für die Inhalte arbeitet.
|
||||
## Licens, attribution och ändringsmeddelande
|
||||
|
||||
## Überblick
|
||||
Det här repot är baserat på generatorn bakom [50ohm.de](https://50ohm.de) (DARC e.V.), originalet finns i repot [DARC-e-V/50ohm](https://github.com/DARC-e-V/50ohm) (grenen `main`). Generatorns kod är licensierad under AGPL-3.0 (se [`LICENSE`](LICENSE)); innehållet på 50ohm.de är licensierat under CC BY 4.0 och måste tillskrivas DARC e.V. Licensfilerna ska behållas.
|
||||
|
||||
Die Ausbildungsmaterialien von 50ohm.de werden in einem erweiterten Markdownformat geschrieben, intern als DARCdown bezeichnet. Kern des Generators ist ein Parser, der auf [mistletoe](https://github.com/miyuchina/mistletoe) basiert und um zusätzliche Syntax und Ausgabeformate erweitert wurde.
|
||||
**Ändringar:** Generatorn har översatts till svenska (gränssnitt, bildtexter, LaTeX, enhets- och typografiregler enligt svensk praxis), kurserna har ersatts av Instegscertifikat, HAREC och uppgradering från Instegscertifikat till HAREC, den tyska frågebanken är valfri, och all DARC-/tysk branding och alla länkar till tyska tjänster har tagits bort.
|
||||
|
||||
Die möglichen Ausgabeformate sind:
|
||||
Detta är en oberoende adaption. Den är **inte godkänd av DARC eller SSA**.
|
||||
|
||||
## Översikt
|
||||
|
||||
Utbildningsmaterialet skrivs i ett utökat markdown-format, internt kallat DARCdown. Kärnan i generatorn är en parser baserad på [mistletoe](https://github.com/miyuchina/mistletoe) som har utökats med extra syntax och utdataformat. Formatet beskrivs i `README-FORMAT.md` i innehållsrepot.
|
||||
|
||||
Utdataformat:
|
||||
- HTML: [`fifty_ohm_html_renderer.py`](renderer/fifty_ohm_html_renderer.py)
|
||||
- LaTeX: [`fifty_ohm_latex_renderer`](renderer/fifty_ohm_latex_renderer.py)
|
||||
- HTML für Slides mit reveal.js: [`fifty_ohm_html_slide_renderer.py`](renderer/fifty_ohm_html_slide_renderer.py)
|
||||
- LaTeX: [`fifty_ohm_latex_renderer.py`](renderer/fifty_ohm_latex_renderer.py)
|
||||
- HTML för presentationer med reveal.js: [`fifty_ohm_html_slide_renderer.py`](renderer/fifty_ohm_html_slide_renderer.py)
|
||||
|
||||
Prinzipiell lassen sich diese Generatoren auch für andere Quell-Repositories verwenden. Dies ist insbesondere für andere IARU-Verbände interessant, welche auch 50ohm als Ausbildungsseite implementieren wollen. Der eigentliche Teil des Generators liegt in `src`, insbesondere das Skript ([`build.py`](src/build.py)). In dieser Datei finden sich außerdem weitere Begleitfunktionen zum Renderprozess, z.B. das Übersetzen von Fragennummern in Fragen oder das Kopieren von Assets.
|
||||
Själva generatorn finns i `src`, framför allt skriptet [`build.py`](src/build.py). Namnen på webbplatsens sidor definieras på ett ställe: [`src/pages.py`](src/pages.py).
|
||||
|
||||
## Mitmachen und Kontakt
|
||||
## Kurser (Edition)
|
||||
|
||||
Aktuell wird 50ohm durch ein kleines ehrenamtliches Entwicklerteam beim DARC e.V. betreut und weiterentwickelt. Falls du einen Fehler oder einen Funktionswunsch hast, schreibe gerne ein Issue. Auch über einen PR freuen wir uns!
|
||||
Wenn du inhaltliche Beiträge hast, kannst du diese über dieses [Repository](https://github.com/DARC-e-V/50ohm-contents-dl) einreichen.
|
||||
Tre kurser byggs. Varje kurs har en innehållsförteckning (toc) i innehållsrepot:
|
||||
|
||||
Bei Anfragen bitte die Email-Adresse [50ohm@darc.de](mailto:50ohm@darc.de) nutzen. Weiterhin findet man viele der Beitragenden im Matrix-Kanal [50ohm Contribution](https://matrix.to/#/#50ohm-contribution:darc.de).
|
||||
| Edition (`--edition`) | Kurs | Fil |
|
||||
|---|---|---|
|
||||
| `INSTEG` | Instegscertifikat | `toc/INSTEG.json` |
|
||||
| `HAREC` | HAREC | `toc/HAREC.json` |
|
||||
| `UPPGRADERING` | Uppgradering: Instegscertifikat till HAREC | `toc/UPPGRADERING.json` |
|
||||
|
||||
### Python einrichten und Abhängigkeiten installieren
|
||||
Utan `--edition` byggs alla tre. Alternativet kan anges flera gånger:
|
||||
|
||||
Dieses Projekt wurde mit [`uv`](https://docs.astral.sh/uv/) aufgesetzt, ist aber genauso mit `pip` und `venv` kompatibel.
|
||||
|
||||
Wichtig ist, mit der richtigen Python-Version aus der `.python-version` zu arbeiten. Mit `uv` geht das ganz einfach:
|
||||
```console
|
||||
$ uv venv
|
||||
Using CPython 3.12.7
|
||||
Creating virtual environment at .venv
|
||||
$ source .venv/bin/activate
|
||||
$ python main.py --edition INSTEG --edition HAREC
|
||||
```
|
||||
|
||||
Die Dependencies müssen aus der `requirements.txt` installiert werden:
|
||||
## Innehållsrepot
|
||||
|
||||
Generatorn läser sitt innehåll från ett separat repo med följande struktur:
|
||||
|
||||
```
|
||||
toc/<EDITION>.json innehållsförteckning per kurs
|
||||
contents/sections/<ident>.md text för ett avsnitt
|
||||
contents/slides/<ident>.md presentation för ett avsnitt (valfri)
|
||||
contents/snippets/*.md korta texter för startsidan
|
||||
contents/static/<sida>.html statiska sidor (+ <sida>_sidebar.html, valfri)
|
||||
contents/drawings, photos, html bilder, foton och inbäddad HTML
|
||||
contents/questions/question_pool.json frågebank (valfri, se nedan)
|
||||
contents/questions/metadata.json bildmetadata för frågorna (valfri)
|
||||
contents/solutions/<frågenummer>.md lösningsvägar (valfria)
|
||||
```
|
||||
|
||||
### Statiska sidor och snippets
|
||||
|
||||
Följande sidnamn används (se `src/pages.py`): `prov`, `info`, `sok`, `kurser_karta`, `kurser_lista`, `mentorer`. För de tre sista används en generell mall om innehållsrepot saknar motsvarande statiska sida. Saknade snippets ger tom text, bygget misslyckas inte.
|
||||
|
||||
Snippets som används på startsidan: `index_title`, `index_teaser`, `index_content`, `index_btn_start`, `index_btn_vad_ar_amatorradio`, `lernen_selbst_title`, `lernen_selbst_teaser`, `lernen_selbst_btn_instegs`, `lernen_selbst_btn_harec`, `lernen_selbst_btn_uppgradering`, `lernen_kurs_*` och `lernen_mentor_*` (`title`, `teaser`, `btn`).
|
||||
|
||||
### Frågebank (valfri)
|
||||
|
||||
Det finns ingen svensk frågebank. Om `contents/questions/question_pool.json` saknas hoppar generatorn över provsimulatorn, övningsverktyget, lösningssidorna och `question_index.json`, och alla länkar dit döljs i mallarna (Jinja-variabeln `has_question_pool`). Finns frågebanken byggs allt som förut. `metadata.json` är valfri; saknas en fråga där används standardvärden.
|
||||
|
||||
## Kom igång
|
||||
|
||||
### Installera Python och beroenden
|
||||
|
||||
Projektet är uppsatt med [`uv`](https://docs.astral.sh/uv/) men fungerar lika bra med `pip` och `venv`. Använd Python-versionen i `.python-version`.
|
||||
|
||||
```console
|
||||
$ uv venv
|
||||
$ source .venv/bin/activate
|
||||
$ uv pip sync requirements.txt
|
||||
```
|
||||
|
||||
### Ausführen
|
||||
|
||||
Um 50ohm ausführen zu können, muss der Pfad zu einem lokal ausgechecktem Content-Repository in die `config/config.json` eingetragen werden. Ein Beispiel-Content-Repository für deutsche Inhalte findet sich hier: [50ohm-contents-dl](https://github.com/DARC-e-V/50ohm-contents-dl).
|
||||
|
||||
Die 50ohm.de-Website wird mit folgendem Befehl vollständig gebaut:
|
||||
Med `venv` och `pip`:
|
||||
|
||||
```console
|
||||
$ python3 ./build.py
|
||||
$ python3 -m venv .venv
|
||||
$ source .venv/bin/activate
|
||||
$ pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Starten
|
||||
Der Einstiegspunkt ist in `build/index.html` zu finden.
|
||||
Alle Seiten sind auch in `build/build.zip` gepackt enthalten.
|
||||
### Bygga
|
||||
|
||||
Um auch die Suchfunktion auf der Seite nutzen zu können, muss ein lokaler Webserver gestartet werden:
|
||||
Ange sökvägen till ett utcheckat innehållsrepo, antingen i `config/config.json` (se `config/config.json.example`), som miljövariabel `OHM_INPUT` eller på kommandoraden:
|
||||
|
||||
```console
|
||||
$ python main.py -i ../50ohm-contents-dl -o build
|
||||
```
|
||||
|
||||
Flaggor: `--input/-i` (innehåll), `--output/-o` (målkatalog, standard `./build`), `--edition` (kurs, se ovan), `--no-render-editions`, `--no-render-solutions`, `--build-zip`. `python build.py` bygger allt och packar `build/build.zip`.
|
||||
|
||||
### Testa lokalt
|
||||
|
||||
Startsidan är `build/index.html`. För att sökfunktionen ska fungera krävs en lokal webbserver:
|
||||
|
||||
```console
|
||||
$ cd build/
|
||||
$ python3 -m http.server 8000
|
||||
```
|
||||
|
||||
Anschließend kann die Webseite unter [`http://localhost:8000/index.html`](http://localhost:8000/index.html) aufgerufen werden.
|
||||
Öppna sedan [`http://localhost:8000/index.html`](http://localhost:8000/index.html).
|
||||
|
||||
### Hosting
|
||||
|
||||
Resultatet är rent statiska filer. Kopiera innehållet i `build/` till valfri webbserver (nginx, Apache, GitHub Pages, ...). Alla länkar är relativa. Ett Docker-bygge finns i `docker/Dockerfile`:
|
||||
|
||||
```console
|
||||
$ docker build -f docker/Dockerfile -t 50ohm-sv .
|
||||
$ docker run --rm -v ../50ohm-contents-dl:/content -v $PWD/build:/build 50ohm-sv -i /content -o /build
|
||||
```
|
||||
|
||||
Webbplatsens sidfot innehåller en platshållare för driftansvarigs egna utgivar-/kontaktuppgifter och integritetspolicy (`templates/html/page.html`, markerad med `TODO`). Den måste fyllas i innan webbplatsen publiceras.
|
||||
|
||||
### Tester och kodstil
|
||||
|
||||
```console
|
||||
$ pip install pytest ruff
|
||||
$ python -m pytest
|
||||
$ ruff check . && ruff format --check .
|
||||
```
|
||||
|
||||
## Presentationer
|
||||
|
||||
Se [`doc/Slides.md`](doc/Slides.md).
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/* Minimal CSS for floating CTA positioning/animation only. Uses Bootstrap button styles. */
|
||||
|
||||
.darc-floating {
|
||||
position: fixed;
|
||||
bottom: 1.25rem;
|
||||
z-index: 9999;
|
||||
transform: translateY(140%);
|
||||
opacity: 0;
|
||||
transition: transform .35s cubic-bezier(.2, .8, .2, 1), opacity .35s ease;
|
||||
}
|
||||
|
||||
.darc-floating--right { right: 1.25rem; }
|
||||
.darc-floating--left { left: 1.25rem; }
|
||||
|
||||
.darc-floating.is-visible {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.darc-floating[hidden] { display: none; }
|
||||
|
||||
.darc-floating__link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
.darc-floating__icon {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.darc-floating__icon svg {
|
||||
width: 1.1rem;
|
||||
height: 1.1rem;
|
||||
}
|
||||
|
||||
.darc-floating__close {
|
||||
min-width: 2.5rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.darc-floating { left: 1rem; right: 1rem; }
|
||||
.darc-floating .btn-group { width: 100%; }
|
||||
.darc-floating .btn { flex: 1 1 auto; }
|
||||
.darc-floating__close { flex: 0 0 auto; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.darc-floating { transition: none; }
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* DARC Mitgliedsantrag – Floating CTA
|
||||
*
|
||||
* Blendet den mitlaufenden Button automatisch nach kurzer Verzögerung ein,
|
||||
* damit er auch auf großen Bildschirmen / kurzen Seiten ohne Scrollen sichtbar
|
||||
* ist. Wird vorher gescrollt, erscheint er sofort.
|
||||
*
|
||||
* Es werden KEINE personenbezogenen Daten und keine dauerhaften Marker
|
||||
* gespeichert – nur ein sessionStorage-Flag pro Element, das beim Schließen des
|
||||
* Tabs verfällt.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var REVEAL_DELAY = 800; // ms: spätestens nach dieser Zeit einblenden.
|
||||
var REVEAL_AFTER = 200; // px Scroll-Tiefe, ab der sofort eingeblendet wird.
|
||||
|
||||
function storageKey(el) {
|
||||
return 'darcFloatingDismissed_' + (el.getAttribute('data-uid') || '0');
|
||||
}
|
||||
|
||||
function isDismissed(el) {
|
||||
if (el.getAttribute('data-dismissible') !== '1') {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return window.sessionStorage.getItem(storageKey(el)) === '1';
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function dismiss(el) {
|
||||
el.classList.remove('is-visible');
|
||||
window.setTimeout(function () { el.setAttribute('hidden', 'hidden'); }, 350);
|
||||
try {
|
||||
window.sessionStorage.setItem(storageKey(el), '1');
|
||||
} catch (e) { /* sessionStorage nicht verfügbar – egal */ }
|
||||
}
|
||||
|
||||
function reveal(el) {
|
||||
el.removeAttribute('hidden');
|
||||
// Doppeltes rAF, damit der Display-Wechsel die Transition auslöst.
|
||||
window.requestAnimationFrame(function () {
|
||||
window.requestAnimationFrame(function () { el.classList.add('is-visible'); });
|
||||
});
|
||||
}
|
||||
|
||||
function setup(el) {
|
||||
if (isDismissed(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var closeBtn = el.querySelector('.darc-floating__close');
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', function () { dismiss(el); });
|
||||
}
|
||||
|
||||
var shown = false;
|
||||
var timer = null;
|
||||
|
||||
function show() {
|
||||
if (shown) {
|
||||
return;
|
||||
}
|
||||
shown = true;
|
||||
window.removeEventListener('scroll', onScroll);
|
||||
if (timer) {
|
||||
window.clearTimeout(timer);
|
||||
}
|
||||
reveal(el);
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
if ((window.pageYOffset || document.documentElement.scrollTop) > REVEAL_AFTER) {
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
// Garantierte Einblendung nach kurzer Verzögerung (auch ohne Scrollen).
|
||||
timer = window.setTimeout(show, REVEAL_DELAY);
|
||||
// Früher einblenden, sobald der Besucher scrollt.
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
}
|
||||
|
||||
function init() {
|
||||
var elements = Array.prototype.slice.call(
|
||||
document.querySelectorAll('[data-darc-floating]')
|
||||
);
|
||||
elements.forEach(setup);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
@@ -6,27 +6,28 @@
|
||||
var QUESTION_COUNT = 25;
|
||||
var ANSWER_LABELS = ["A", "B", "C", "D"];
|
||||
|
||||
// TODO: Adapt exam parts and passing thresholds once a Swedish question pool exists.
|
||||
var PART_DEFINITIONS = {
|
||||
B: { label: "Betriebliche Kenntnisse", minutes: 45 },
|
||||
V: { label: "Kenntnisse von Vorschriften", minutes: 45 },
|
||||
N: { label: "Technische Kenntnisse Klasse N", minutes: 45 },
|
||||
E: { label: "Technische Kenntnisse Klasse E", minutes: 45 },
|
||||
A: { label: "Technische Kenntnisse Klasse A", minutes: 60 },
|
||||
H: { label: "Hausaufgabe", minutes: null }
|
||||
B: { label: "Operativa kunskaper", minutes: 45 },
|
||||
V: { label: "Kunskaper om föreskrifter", minutes: 45 },
|
||||
N: { label: "Tekniska kunskaper, nivå N", minutes: 45 },
|
||||
E: { label: "Tekniska kunskaper, nivå E", minutes: 45 },
|
||||
A: { label: "Tekniska kunskaper, nivå A", minutes: 60 },
|
||||
H: { label: "Övning", minutes: null }
|
||||
};
|
||||
|
||||
var EXAM_CHOICES = [
|
||||
{ id: "N", group: "primary", label: "Klasse N", detail: "B + V + N", parts: ["B", "V", "N"], color: "#47ABE8" },
|
||||
{ id: "E", group: "primary", label: "Klasse E", detail: "B + V + N + E", parts: ["B", "V", "N", "E"], color: "#FE756C" },
|
||||
{ id: "A", group: "primary", label: "Klasse A", detail: "B + V + N + E + A", parts: ["B", "V", "N", "E", "A"], color: "#3BB583" },
|
||||
{ id: "N-E", group: "upgrade", label: "N → E", detail: "Technik E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "N-A", group: "upgrade", label: "N → A", detail: "Technik E + A", parts: ["E", "A"], color: "#3BB583" },
|
||||
{ id: "E-A", group: "upgrade", label: "E → A", detail: "Technik A", parts: ["A"], color: "#3BB583" },
|
||||
{ id: "part-B", group: "single", label: "B", detail: "Betriebliche Kenntnisse", parts: ["B"], color: "#47ABE8" },
|
||||
{ id: "part-V", group: "single", label: "V", detail: "Kenntnisse von Vorschriften", parts: ["V"], color: "#47ABE8" },
|
||||
{ id: "part-N", group: "single", label: "N", detail: "Technik Klasse N", parts: ["N"], color: "#47ABE8" },
|
||||
{ id: "part-E", group: "single", label: "E", detail: "Technik Klasse E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "part-A", group: "single", label: "A", detail: "Technik Klasse A", parts: ["A"], color: "#3BB583" }
|
||||
{ id: "N", group: "primary", label: "Nivå N", detail: "B + V + N", parts: ["B", "V", "N"], color: "#47ABE8" },
|
||||
{ id: "E", group: "primary", label: "Nivå E", detail: "B + V + N + E", parts: ["B", "V", "N", "E"], color: "#FE756C" },
|
||||
{ id: "A", group: "primary", label: "Nivå A", detail: "B + V + N + E + A", parts: ["B", "V", "N", "E", "A"], color: "#3BB583" },
|
||||
{ id: "N-E", group: "upgrade", label: "N → E", detail: "Teknik E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "N-A", group: "upgrade", label: "N → A", detail: "Teknik E + A", parts: ["E", "A"], color: "#3BB583" },
|
||||
{ id: "E-A", group: "upgrade", label: "E → A", detail: "Teknik A", parts: ["A"], color: "#3BB583" },
|
||||
{ id: "part-B", group: "single", label: "B", detail: "Operativa kunskaper", parts: ["B"], color: "#47ABE8" },
|
||||
{ id: "part-V", group: "single", label: "V", detail: "Kunskaper om föreskrifter", parts: ["V"], color: "#47ABE8" },
|
||||
{ id: "part-N", group: "single", label: "N", detail: "Teknik nivå N", parts: ["N"], color: "#47ABE8" },
|
||||
{ id: "part-E", group: "single", label: "E", detail: "Teknik nivå E", parts: ["E"], color: "#FE756C" },
|
||||
{ id: "part-A", group: "single", label: "A", detail: "Teknik nivå A", parts: ["A"], color: "#3BB583" }
|
||||
];
|
||||
|
||||
function queryValue(name) {
|
||||
@@ -72,7 +73,7 @@
|
||||
input.select();
|
||||
var copied = document.execCommand("copy");
|
||||
input.remove();
|
||||
return copied ? Promise.resolve() : Promise.reject(new Error("Kopieren nicht möglich"));
|
||||
return copied ? Promise.resolve() : Promise.reject(new Error("Det gick inte att kopiera"));
|
||||
}
|
||||
|
||||
function shuffled(values) {
|
||||
@@ -149,7 +150,7 @@
|
||||
|
||||
function balancedSample(pool, count) {
|
||||
if (!Array.isArray(pool) || pool.length < count) {
|
||||
throw new Error("Für diesen Prüfungsteil stehen nicht genügend Fragen zur Verfügung.");
|
||||
throw new Error("Det finns inte tillräckligt många frågor för den här provdelen.");
|
||||
}
|
||||
return pickFromTree(buildCategoryTree(pool), count);
|
||||
}
|
||||
@@ -196,7 +197,7 @@
|
||||
var currentChoice = computed(function () {
|
||||
if (!session.value) return null;
|
||||
if (session.value.mode === "homework") {
|
||||
return { id: "H", label: "Hausaufgabe", parts: ["H"] };
|
||||
return { id: "H", label: "Övning", parts: ["H"] };
|
||||
}
|
||||
return EXAM_CHOICES.find(function (choice) { return choice.id === session.value.choiceId; });
|
||||
});
|
||||
@@ -256,17 +257,17 @@
|
||||
return { homework: "task_alt", passed: "verified", oral: "record_voice_over", failed: "cancel", incomplete: "stop_circle" }[overallState.value];
|
||||
});
|
||||
var overallTitle = computed(function () {
|
||||
return { homework: "Hausaufgabe ausgewertet", passed: "Prüfung bestanden", oral: "Mündliche Nachprüfung möglich", failed: "Prüfung nicht bestanden", incomplete: "Prüfung vorzeitig beendet" }[overallState.value];
|
||||
return { homework: "Övningen är rättad", passed: "Provet godkänt", oral: "Muntlig komplettering möjlig", failed: "Provet inte godkänt", incomplete: "Provet avslutades i förtid" }[overallState.value];
|
||||
});
|
||||
var overallText = computed(function () {
|
||||
if (overallState.value === "homework") {
|
||||
var homeworkPart = session.value.parts[0];
|
||||
return homeworkPart.score + " von " + homeworkPart.questions.length + " Fragen wurden richtig beantwortet.";
|
||||
return homeworkPart.score + " av " + homeworkPart.questions.length + " frågor besvarades rätt.";
|
||||
}
|
||||
if (overallState.value === "passed") return "Gratulation! Du hast jeden Prüfungsteil mit mindestens 19 Punkten bestanden.";
|
||||
if (overallState.value === "oral") return "In genau einem Prüfungsteil wurden 17 oder 18 Punkte erreicht; nach den Prüfungsregeln kann eine mündliche Nachprüfung möglich sein.";
|
||||
if (overallState.value === "failed") return "Mindestens ein Prüfungsteil wurde nicht bestanden.";
|
||||
return evaluatedParts().length + " von " + session.value.parts.length + " Prüfungsteilen wurden abgeschlossen.";
|
||||
if (overallState.value === "passed") return "Grattis! Du har klarat varje provdel med minst 19 poäng.";
|
||||
if (overallState.value === "oral") return "I exakt en provdel nåddes 17 eller 18 poäng; enligt provreglerna kan en muntlig komplettering vara möjlig.";
|
||||
if (overallState.value === "failed") return "Minst en provdel är inte godkänd.";
|
||||
return evaluatedParts().length + " av " + session.value.parts.length + " provdelar har slutförts.";
|
||||
});
|
||||
|
||||
function questionData(questionState) {
|
||||
@@ -331,9 +332,9 @@
|
||||
function createHomeworkPart(questionIds) {
|
||||
var questions = questionIds.map(function (questionId) { return catalog.value[questionId]; }).filter(Boolean);
|
||||
if (questions.length !== questionIds.length) {
|
||||
throw new Error("Mindestens eine Frage aus dem Hausaufgabenlink ist nicht im aktuellen Fragenkatalog enthalten.");
|
||||
throw new Error("Minst en fråga i övningslänken finns inte i den aktuella frågebanken.");
|
||||
}
|
||||
if (questions.length === 0) throw new Error("Der Hausaufgabenlink enthält keine gültigen Fragen.");
|
||||
if (questions.length === 0) throw new Error("Övningslänken innehåller inga giltiga frågor.");
|
||||
return {
|
||||
code: "H",
|
||||
status: "pending",
|
||||
@@ -481,8 +482,8 @@
|
||||
function requestSubmit() {
|
||||
var unanswered = currentQuestionCount.value - answeredCount.value;
|
||||
var text = unanswered > 0
|
||||
? "Du hast " + unanswered + " Fragen nicht beantwortet. Möchtest du " + (isHomework.value ? "die Hausaufgabe" : "den Prüfungsteil") + " trotzdem abgeben?"
|
||||
: "Möchtest du " + (isHomework.value ? "die Hausaufgabe" : "diesen Prüfungsteil") + " jetzt verbindlich abgeben?";
|
||||
? "Du har inte besvarat " + unanswered + " frågor. Vill du lämna in " + (isHomework.value ? "övningen" : "provdelen") + " ändå?"
|
||||
: "Vill du lämna in " + (isHomework.value ? "övningen" : "den här provdelen") + " nu? Det går inte att ångra.";
|
||||
if (window.confirm(text)) submitPart(false);
|
||||
}
|
||||
|
||||
@@ -502,7 +503,7 @@
|
||||
}
|
||||
|
||||
function finishExamEarly() {
|
||||
if (!window.confirm("Möchtest du die Prüfung wirklich hier beenden? Nicht bearbeitete Teile gelten dann als nicht abgeschlossen.")) return;
|
||||
if (!window.confirm("Vill du verkligen avsluta provet här? Delar som inte har gjorts räknas som ej slutförda.")) return;
|
||||
showSummary();
|
||||
}
|
||||
|
||||
@@ -540,22 +541,22 @@
|
||||
}
|
||||
|
||||
function abortExam() {
|
||||
var noun = isHomework.value ? "Hausaufgabe" : "Simulation";
|
||||
if (!window.confirm("Möchtest du diese " + noun + " abbrechen? Der gespeicherte Stand wird gelöscht.")) return;
|
||||
var noun = isHomework.value ? "övningen" : "simuleringen";
|
||||
if (!window.confirm("Vill du avbryta " + noun + "? Det sparade läget raderas.")) return;
|
||||
resetExam();
|
||||
window.history.replaceState(null, "", "simulation.html");
|
||||
window.history.replaceState(null, "", "simulering.html");
|
||||
}
|
||||
|
||||
function newExam() {
|
||||
resetExam();
|
||||
window.history.replaceState(null, "", "simulation.html");
|
||||
window.history.replaceState(null, "", "simulering.html");
|
||||
}
|
||||
|
||||
function retryHomework() {
|
||||
var questionIds = session.value && session.value.homeworkIds;
|
||||
if (!questionIds) return;
|
||||
clearStoredSession();
|
||||
var homeworkUrl = new URL("simulation.html", window.location.href);
|
||||
var homeworkUrl = new URL("simulering.html", window.location.href);
|
||||
homeworkUrl.search = "?homework=" + questionIds.join("+");
|
||||
window.history.replaceState(null, "", homeworkUrl.toString());
|
||||
startHomework(questionIds);
|
||||
@@ -568,10 +569,10 @@
|
||||
}
|
||||
|
||||
function resultLabel(part) {
|
||||
if (part.code === "H") return "Ausgewertet";
|
||||
if (part.score >= 19) return "Bestanden";
|
||||
if (part.score >= 17) return "Nachprüfung möglich";
|
||||
return "Nicht bestanden";
|
||||
if (part.code === "H") return "Rättad";
|
||||
if (part.score >= 19) return "Godkänd";
|
||||
if (part.score >= 17) return "Komplettering möjlig";
|
||||
return "Inte godkänd";
|
||||
}
|
||||
|
||||
function resultAlertClass(part) {
|
||||
@@ -596,11 +597,11 @@
|
||||
}
|
||||
|
||||
function resultDescription(part) {
|
||||
if (part.code === "H") return part.score + " von " + part.questions.length + " Fragen wurden richtig beantwortet.";
|
||||
var prefix = part.autoSubmitted ? "Die Zeit ist abgelaufen und der Prüfungsteil wurde automatisch abgegeben. " : "";
|
||||
if (part.score >= 19) return prefix + "Die erforderlichen 19 Punkte wurden erreicht.";
|
||||
if (part.score >= 17) return prefix + "Mit 17 oder 18 Punkten kann nach den Prüfungsregeln eine mündliche Nachprüfung möglich sein.";
|
||||
return prefix + "Die erforderlichen 19 Punkte wurden nicht erreicht.";
|
||||
if (part.code === "H") return part.score + " av " + part.questions.length + " frågor besvarades rätt.";
|
||||
var prefix = part.autoSubmitted ? "Tiden gick ut och provdelen lämnades in automatiskt. " : "";
|
||||
if (part.score >= 19) return prefix + "De nödvändiga 19 poängen uppnåddes.";
|
||||
if (part.score >= 17) return prefix + "Med 17 eller 18 poäng kan en muntlig komplettering vara möjlig enligt provreglerna.";
|
||||
return prefix + "De nödvändiga 19 poängen uppnåddes inte.";
|
||||
}
|
||||
|
||||
function encodedResult(result) {
|
||||
@@ -608,30 +609,6 @@
|
||||
return "1." + result.choice.id + "." + result.scores.join(".");
|
||||
}
|
||||
|
||||
function resultImageCode(result) {
|
||||
if (!result) return "";
|
||||
if (result.kind === "homework") return result.score === result.total ? "aenbv" : "";
|
||||
if (!result.passed) return "";
|
||||
var order = ["A", "E", "N", "B", "V"];
|
||||
return order.filter(function (part) {
|
||||
return result.choice.parts.indexOf(part) !== -1;
|
||||
}).join("").toLowerCase();
|
||||
}
|
||||
|
||||
function shareableSessionResult() {
|
||||
if (!session.value) return null;
|
||||
if (isHomework.value) {
|
||||
return { kind: "homework", score: session.value.parts[0].score, total: session.value.parts[0].questions.length };
|
||||
}
|
||||
if (session.value.parts.some(function (part) { return part.status !== "evaluated"; })) return null;
|
||||
return {
|
||||
kind: "exam",
|
||||
choice: currentChoice.value,
|
||||
scores: session.value.parts.map(function (part) { return part.score; }),
|
||||
passed: overallState.value === "passed"
|
||||
};
|
||||
}
|
||||
|
||||
var resultForSharing = computed(function () {
|
||||
if (sharedResult.value) return sharedResult.value;
|
||||
if (view.value !== "summary") return null;
|
||||
@@ -640,8 +617,7 @@
|
||||
|
||||
function buildResultUrl(result) {
|
||||
if (!result) return "";
|
||||
var imageCode = resultImageCode(result);
|
||||
var url = new URL(imageCode ? "result-" + imageCode + ".html" : "result.html", window.location.href);
|
||||
var url = new URL("resultat.html", window.location.href);
|
||||
url.search = "?result=" + encodedResult(result);
|
||||
return url.toString();
|
||||
}
|
||||
@@ -654,19 +630,19 @@
|
||||
return buildResultUrl(resultForSharing.value);
|
||||
});
|
||||
|
||||
// There are no result images for sharing.
|
||||
var resultImageUrl = computed(function () {
|
||||
var imageCode = resultImageCode(resultForSharing.value);
|
||||
return imageCode ? "assets/images/exam-" + imageCode + ".jpeg" : "";
|
||||
return "";
|
||||
});
|
||||
|
||||
var shareText = computed(function () {
|
||||
var result = resultForSharing.value;
|
||||
if (!result) return "";
|
||||
if (result.kind === "homework") {
|
||||
return "Meine 50ohm.de-Hausaufgabe: " + result.score + " von " + result.total + " Fragen richtig.";
|
||||
return "Min övning på 50Ω: " + result.score + " av " + result.total + " frågor rätt.";
|
||||
}
|
||||
var scores = result.choice.parts.map(function (part, index) { return part + ": " + result.scores[index] + "/25"; }).join(", ");
|
||||
return "Meine 50ohm.de-Prüfungssimulation " + result.choice.label + ": " + scores + " – " + (result.passed ? "bestanden!" : "noch nicht bestanden.");
|
||||
return "Min provsimulering på 50Ω " + result.choice.label + ": " + scores + " – " + (result.passed ? "godkänd!" : "ännu inte godkänd.");
|
||||
});
|
||||
|
||||
var socialShareLinks = computed(function () {
|
||||
@@ -681,8 +657,8 @@
|
||||
|
||||
function copyResultLink() {
|
||||
copyText(resultShareUrl.value)
|
||||
.then(function () { shareMessage.value = "Ergebnislink kopiert."; })
|
||||
.catch(function () { shareMessage.value = "Der Link konnte nicht automatisch kopiert werden."; });
|
||||
.then(function () { shareMessage.value = "Resultatlänken kopierades."; })
|
||||
.catch(function () { shareMessage.value = "Länken kunde inte kopieras automatiskt."; });
|
||||
}
|
||||
|
||||
function shareNative() {
|
||||
@@ -690,7 +666,7 @@
|
||||
copyResultLink();
|
||||
return;
|
||||
}
|
||||
navigator.share({ title: "50ohm.de-Ergebnis", text: shareText.value, url: resultShareUrl.value }).catch(function () {});
|
||||
navigator.share({ title: "Resultat från 50Ω", text: shareText.value, url: resultShareUrl.value }).catch(function () {});
|
||||
}
|
||||
|
||||
function restoreSession(homeworkQuestionIds, allowHomeworkResult) {
|
||||
@@ -758,24 +734,24 @@
|
||||
|
||||
function loadCatalog() {
|
||||
Promise.all([
|
||||
fetch("assets/fragenkatalog.json"),
|
||||
fetch("assets/question_pool.json"),
|
||||
fetch("assets/metadata.json"),
|
||||
fetch("assets/question_index.json")
|
||||
])
|
||||
.then(function (responses) {
|
||||
var names = ["Fragenkatalog", "Metadaten", "Fragenindex"];
|
||||
var names = ["Frågebanken", "Metadata", "Frågeindex"];
|
||||
responses.forEach(function (response, index) {
|
||||
if (!response.ok) throw new Error(names[index] + " nicht gefunden (HTTP " + response.status + ").");
|
||||
if (!response.ok) throw new Error(names[index] + " hittades inte (HTTP " + response.status + ").");
|
||||
});
|
||||
return Promise.all(responses.map(function (response) { return response.json(); }));
|
||||
})
|
||||
.then(function (data) {
|
||||
catalog.value = window.FiftyOhmQuestions.normalizeCatalog(data[0], data[1] || {}, data[2] || {});
|
||||
if (Object.keys(catalog.value).length === 0) throw new Error("Der Fragenkatalog ist leer.");
|
||||
if (Object.keys(catalog.value).length === 0) throw new Error("Frågebanken är tom.");
|
||||
var parsedResult = parseSharedResult();
|
||||
var homeworkQuestionIds = parseHomeworkQuestionIds();
|
||||
if (queryValue("result")) {
|
||||
if (!parsedResult) throw new Error("Der Ergebnislink ist ungültig.");
|
||||
if (!parsedResult) throw new Error("Resultatlänken är ogiltig.");
|
||||
restoreSession([], true);
|
||||
var storedResult = shareableSessionResult();
|
||||
if (storedResult && encodedResult(storedResult) === queryValue("result")) {
|
||||
@@ -794,7 +770,7 @@
|
||||
renderMathSoon(Vue);
|
||||
})
|
||||
.catch(function (error) {
|
||||
loadError.value = error.message || "Unbekannter Ladefehler";
|
||||
loadError.value = error.message || "Okänt fel vid laddning";
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"use strict";
|
||||
|
||||
var COURSE_CHOICES = [
|
||||
{ edition: "N", label: "N-Kurs", detail: "N", color: "#47ABE8" },
|
||||
{ edition: "NE", label: "E-Kurs", detail: "N + E", color: "#FE756C" },
|
||||
{ edition: "NEA", label: "A-Kurs", detail: "N + E + A", color: "#3BB583" },
|
||||
{ edition: "INSTEG", label: "Instegscertifikat", detail: "Instegskurs", color: "#47ABE8" },
|
||||
{ edition: "HAREC", label: "HAREC", detail: "HAREC-kurs", color: "#FE756C" },
|
||||
{ edition: "UPPGRADERING", label: "Uppgradering", detail: "Instegscertifikat → HAREC", color: "#3BB583" },
|
||||
{ edition: "E", label: "Aufstockung N → E", detail: "E", color: "#FE756C" },
|
||||
{ edition: "EA", label: "Aufstockung N → A", detail: "E + A", color: "#3BB583" },
|
||||
{ edition: "A", label: "Aufstockung E → A", detail: "A", color: "#3BB583" }
|
||||
@@ -28,7 +28,7 @@
|
||||
input.select();
|
||||
var copied = document.execCommand("copy");
|
||||
input.remove();
|
||||
return copied ? Promise.resolve() : Promise.reject(new Error("Kopieren nicht möglich"));
|
||||
return copied ? Promise.resolve() : Promise.reject(new Error("Det gick inte att kopiera"));
|
||||
}
|
||||
|
||||
var app = Vue.createApp({
|
||||
@@ -55,8 +55,8 @@
|
||||
var stepLabels = [
|
||||
{ number: 1, label: "Kurs" },
|
||||
{ number: 2, label: "Kapitel" },
|
||||
{ number: 3, label: "Sektionen" },
|
||||
{ number: 4, label: "Fragen" },
|
||||
{ number: 3, label: "Avsnitt" },
|
||||
{ number: 4, label: "Frågor" },
|
||||
{ number: 5, label: "Link" }
|
||||
];
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
loading.value = true;
|
||||
fetch("assets/toc/" + course.edition + ".json")
|
||||
.then(function (response) {
|
||||
if (!response.ok) throw new Error("Inhaltsverzeichnis nicht gefunden (HTTP " + response.status + ").");
|
||||
if (!response.ok) throw new Error("Innehållsförteckningen hittades inte (HTTP " + response.status + ").");
|
||||
return response.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
@@ -147,7 +147,7 @@
|
||||
goToStep(2);
|
||||
})
|
||||
.catch(function (error) {
|
||||
loadError.value = error.message || "Unbekannter Ladefehler";
|
||||
loadError.value = error.message || "Okänt fel vid laddning";
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
@@ -181,19 +181,19 @@
|
||||
|
||||
function copyLink() {
|
||||
copyText(generatedUrl.value)
|
||||
.then(function () { copyMessage.value = "Der Hausaufgabenlink wurde kopiert."; })
|
||||
.catch(function () { copyMessage.value = "Der Link konnte nicht automatisch kopiert werden. Bitte kopiere ihn aus dem Feld."; });
|
||||
.then(function () { copyMessage.value = "Övningslänken kopierades."; })
|
||||
.catch(function () { copyMessage.value = "Länken kunde inte kopieras automatiskt. Kopiera den från fältet."; });
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
fetch("assets/fragenkatalog.json"),
|
||||
fetch("assets/question_pool.json"),
|
||||
fetch("assets/metadata.json"),
|
||||
fetch("assets/question_index.json")
|
||||
])
|
||||
.then(function (responses) {
|
||||
var names = ["Fragenkatalog", "Metadaten", "Fragenindex"];
|
||||
var names = ["Frågebanken", "Metadata", "Frågeindex"];
|
||||
responses.forEach(function (response, index) {
|
||||
if (!response.ok) throw new Error(names[index] + " nicht gefunden (HTTP " + response.status + ").");
|
||||
if (!response.ok) throw new Error(names[index] + " hittades inte (HTTP " + response.status + ").");
|
||||
});
|
||||
return Promise.all(responses.map(function (response) { return response.json(); }));
|
||||
})
|
||||
@@ -204,7 +204,7 @@
|
||||
loading.value = false;
|
||||
})
|
||||
.catch(function (error) {
|
||||
loadError.value = error.message || "Unbekannter Ladefehler";
|
||||
loadError.value = error.message || "Okänt fel vid laddning";
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="154.22mm" height="33.74mm" version="1.1" viewBox="0 0 154.22 33.74" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-25.261 -186.85)"><path d="m102.39 187.78v1.6061c7.7358 0.5131 13.83 6.0078 14.69 13.197h1.6971c-0.68965-7.6776-7.3078-14.249-16.387-14.803zm0 3.2572v1.4263c5.8837 0.47241 10.531 4.4265 11.192 10.12h1.8071c-0.73398-6.5152-6.1553-11.071-12.999-11.546zm0 2.853v1.712c3.9021 0.49061 6.8991 3.3428 7.5799 6.981h1.6955c-0.67496-4.6123-4.4348-8.1826-9.2754-8.693z" fill="#b2e6fa"/><path d="m60.864 203.7q0 2.1167 0.381 3.8523 0.381 1.7357 1.0583 3.0057 0.71967 1.27 1.6933 1.9897 0.97367 0.67734 2.2013 0.67734 1.1853 0 2.159-0.67734 1.016-0.71966 1.6933-1.9897t1.0583-3.0057q0.381-1.7357 0.381-3.8523 0-2.0743-0.381-3.81-0.381-1.778-1.0583-3.0057-0.67733-1.27-1.6933-1.9473-0.97367-0.71967-2.159-0.71967-1.2277 0-2.2013 0.71967-0.97367 0.67733-1.6933 1.9473-0.67733 1.2277-1.0583 3.0057-0.381 1.7357-0.381 3.81zm-8.2127 0q0-3.81 0.97367-6.9003 1.016-3.1327 2.794-5.334 1.8203-2.2013 4.2757-3.3867 2.4977-1.2277 5.5033-1.2277 2.9633 0 5.461 1.2277 2.4977 1.1853 4.2757 3.3867t2.7517 5.334q1.016 3.0903 1.016 6.9003 0 3.81-1.016 6.9427-0.97367 3.0903-2.7517 5.334-1.778 2.2013-4.2757 3.429-2.4977 1.1853-5.461 1.1853-3.0057 0-5.5033-1.1853-2.4553-1.2277-4.2757-3.429-1.778-2.2437-2.794-5.334-0.97367-3.1327-0.97367-6.9427z" fill="#00adef"/><path d="m46.724 194.81h-11.049l-0.55033 3.5137q0.762-0.0847 1.397-0.127 0.635-0.0847 1.3123-0.0847 2.413 0 4.4873 0.84666 2.0743 0.84667 3.556 2.3283 1.4817 1.4817 2.3283 3.556t0.84667 4.5297q0 2.5823-0.97367 4.6567-0.93133 2.0743-2.667 3.556-1.7357 1.4393-4.2333 2.2013-2.4977 0.80433-5.5457 0.80433-2.8787 0-5.5033-0.71967-2.5823-0.67733-4.8683-2.1167l1.2277-7.7893q2.1167 1.8203 4.318 2.794 2.2013 0.93133 4.191 0.93133 2.54 0 4.0217-1.3547 1.4817-1.397 1.4817-3.429 0-2.3707-1.9897-3.81-1.9897-1.4817-5.207-1.4817-1.4393 0-2.9633 0.33866-1.524 0.29634-3.0057 0.97367l2.667-17.145h16.722z" fill="#00adef"/><path d="m101.15 187.74c-2.54 0-4.8826 0.43769-7.0275 1.3126-2.1449 0.84666-4.0073 2.0177-5.5878 3.5135-1.5804 1.4676-2.8222 3.189-3.7254 5.1645-0.87488 1.9473-1.3126 4.0079-1.3126 6.181 0 0.70555 0.08492 1.5238 0.25425 2.4552 0.19755 0.9031 0.49372 1.8346 0.88883 2.7941 0.39511 0.93133 0.90305 1.8345 1.5239 2.7094 0.62089 0.87488 1.3689 1.6224 2.2438 2.2433h-5.5454v6.4771h15.875v-7.1117c-0.95956-0.28222-1.8344-0.71991-2.6246-1.3126-0.79022-0.62089-1.4821-1.3406-2.0748-2.159-0.56445-0.84666-1.0158-1.764-1.3544-2.7518-0.31044-1.016-0.4656-2.0319-0.4656-3.0479 0-1.2136 0.22592-2.3421 0.67747-3.3864 0.47978-1.0442 1.1146-1.9616 1.9048-2.7518 0.81844-0.79022 1.7641-1.4114 2.8365-1.8629 1.1007-0.45155 2.2858-0.67696 3.5558-0.67696 4e-3 0 8e-3 5.1e-4 0.0114 5.2e-4v-7.7892c-0.0181-5e-5 -0.0356-1e-3 -0.0537-1e-3zm8.9509 15.97c9e-3 0.1656 0.0238 0.32876 0.0238 0.49764 0 1.016-0.16931 2.0319-0.50798 3.0479-0.31044 0.98778-0.76177 1.9051-1.3544 2.7518-0.56444 0.81844-1.2564 1.5382-2.0748 2.159-0.79023 0.59267-1.6651 1.0304-2.6246 1.3126v7.1117h15.917v-6.4771h-5.503c0.87489-0.62089 1.6224-1.3684 2.2433-2.2433 0.62089-0.87489 1.1152-1.7781 1.4821-2.7094 0.39511-0.95955 0.67713-1.891 0.84646-2.7941 0.19756-0.93134 0.29663-1.7496 0.29663-2.4552 0-0.0676-4e-3 -0.13415-5e-3 -0.20154z" fill="#00adef"/><path d="m162.56 186.85-16.87 16.87 16.87 16.87 16.87-16.87zm14.19 16.87-6.8472 6.8472c0.14889-0.34733 0.24808-0.74424 0.24808-1.1412 0-1.29-0.8931-2.4312-2.6297-2.7786l-1.2404-0.24807c-0.64503-0.0992-0.89312-0.44655-0.89312-0.89312 0-0.49616 0.49619-0.99233 1.2404-0.99233 1.0916 0 1.4389 0.69464 1.5382 1.0916l1.7862-0.74426c-0.29771-1.042-1.1908-2.1831-3.2747-2.1831-0.79387 0-1.4885 0.24809-2.0839 0.64502 0.69463-0.94272 1.4389-1.8854 2.2328-2.6793 2.332-2.332 3.622-3.0266 3.9198-3.1259zm-7.5418-7.5418c-0.24809 0.14889-1.5877 0.84348-3.9198 3.1259-1.1908 1.1908-2.2328 2.6793-3.2747 4.1678l-1.1412-2.332c0.94272-0.54578 1.3397-1.5877 1.3397-2.5801 0-1.6374-1.1412-2.8778-2.977-2.8778h-2.8282l6.1526-6.1525zm-9.0799 2.4312c0 0.64502-0.44656 1.0916-1.29 1.0916h-1.1908v-2.2328h1.1908c0.84349 0 1.29 0.44656 1.29 1.1412zm-11.759 5.1106 7.1945-7.1945v8.3853h2.0343v-3.4236h1.2404l1.8358 3.8205c-0.54578 0.69464-1.0916 1.3396-1.687 1.935-2.332 2.332-3.7213 3.0266-3.9694 3.1259zm8.1372 8.0876c0.19846-0.0992 1.6374-0.79386 3.9694-3.1259 1.1412-1.1412 2.0839-2.4312 3.0266-3.7213-0.0497 0.24809-0.0992 0.49616-0.0992 0.79387 0 1.3397 0.94272 2.3816 2.4808 2.6793l1.2404 0.24811c0.59541 0.0992 0.99236 0.44654 0.99236 0.9427 0 0.5458-0.49619 0.94273-1.2901 0.94273-1.2404 0-1.7862-0.69462-1.8855-1.5381l-1.8358 0.74428c0.29769 1.2404 1.3893 2.5801 3.6716 2.5801 0.69465 0 1.2404-0.14889 1.7366-0.39691l-5.9044 5.9044z" fill="#b5b9bc" stroke-width=".49617"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 26 KiB |
@@ -1 +0,0 @@
|
||||
<svg width="164.98" height="195.26" version="1.1" viewBox="0 0 164.98 195.26" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(0 1.3333 1.3333 0 -18.027 17.009)"><g transform="matrix(0 .087301 -.087301 0 134.14 13.301)"><path d="m581.34 340.63h-251.7v1006.5h251.7v335.46h-578.82v-1677.5h578.82c432.67 0 789.28 327.91 833.76 749.05h-338.42c-42.5-235.17-248.08-413.54-495.34-413.54" fill="#00adef"/><g fill="#b2e6fa"><path d="m1352.7 849.82h67.13c-3.03 430.22-329.75 783.26-748.59 828v-67.67c381.13-44.33 678.43-368.01 681.46-760.33"/><path d="m1218.5 849.82h67.13c-3.04 355.26-270.4 648.79-614.38 692.73v-67.69c307.07-43.41 544.29-306.63 547.25-625.04"/><path d="m671.25 1407v-68.15c233.2-41.89 410.12-244.54 413-489.07h67.11c-2.93 281.29-209.94 514.45-480.11 557.22"/></g></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 815 B |
|
Before Width: | Height: | Size: 314 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 326 KiB |
|
Before Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 324 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 68 68"
|
||||
version="1.1"
|
||||
id="svg3"
|
||||
sodipodi:docname="rus-logo.svg"
|
||||
width="68"
|
||||
height="68"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<sodipodi:namedview
|
||||
id="namedview3"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.8973384"
|
||||
inkscape:cx="22.288136"
|
||||
inkscape:cy="42.904661"
|
||||
inkscape:window-width="1392"
|
||||
inkscape:window-height="1212"
|
||||
inkscape:window-x="2240"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg3" />
|
||||
<path
|
||||
fill="#b5b9bc"
|
||||
d="M 34,0 0,34 34,68 68,34 Z M 62.6,34 48.8,47.8 c 0.3,-0.7 0.5,-1.5 0.5,-2.3 0,-2.6 -1.8,-4.9 -5.3,-5.6 l -2.5,-0.5 c -1.3,-0.2 -1.8,-0.9 -1.8,-1.8 0,-1 1,-2 2.5,-2 2.2,0 2.9,1.4 3.1,2.2 l 3.6,-1.5 c -0.6,-2.1 -2.4,-4.4 -6.6,-4.4 -1.6,0 -3,0.5 -4.2,1.3 1.4,-1.9 2.9,-3.8 4.5,-5.4 4.7,-4.7 7.3,-6.1 7.9,-6.3 z M 47.4,18.8 c -0.5,0.3 -3.2,1.7 -7.9,6.3 -2.4,2.4 -4.5,5.4 -6.6,8.4 l -2.3,-4.7 c 1.9,-1.1 2.7,-3.2 2.7,-5.2 0,-3.3 -2.3,-5.8 -6,-5.8 H 21.6 L 34,5.4 Z m -18.3,4.9 c 0,1.3 -0.9,2.2 -2.6,2.2 h -2.4 v -4.5 h 2.4 c 1.7,0 2.6,0.9 2.6,2.3 z M 5.4,34 19.9,19.5 V 36.4 H 24 v -6.9 h 2.5 l 3.7,7.7 c -1.1,1.4 -2.2,2.7 -3.4,3.9 -4.7,4.7 -7.5,6.1 -8,6.3 z m 16.4,16.3 c 0.4,-0.2 3.3,-1.6 8,-6.3 2.3,-2.3 4.2,-4.9 6.1,-7.5 -0.1,0.5 -0.2,1 -0.2,1.6 0,2.7 1.9,4.8 5,5.4 l 2.5,0.5 c 1.2,0.2 2,0.9 2,1.9 0,1.1 -1,1.9 -2.6,1.9 -2.5,0 -3.6,-1.4 -3.8,-3.1 l -3.7,1.5 c 0.6,2.5 2.8,5.2 7.4,5.2 1.4,0 2.5,-0.3 3.5,-0.8 L 34.1,62.5 Z"
|
||||
id="path1" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -37,14 +37,14 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
s = s.slice(1);
|
||||
}
|
||||
|
||||
// Find decimal point (last . or ,)
|
||||
// Find decimal separator (last . or ,). Swedish convention: always a decimal comma.
|
||||
let intPart = s;
|
||||
let fracSep = "";
|
||||
let fracDigits = "";
|
||||
const decMatch = s.match(/([.,])(\d+)$/);
|
||||
if (decMatch) {
|
||||
intPart = s.slice(0, decMatch.index);
|
||||
fracSep = decMatch[1];
|
||||
fracSep = ",";
|
||||
fracDigits = decMatch[2];
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
"\\mega": "\\text{M}",
|
||||
"\\kilo": "\\text{k}",
|
||||
"\\dezi": "\\text{d}",
|
||||
"\\deci": "\\text{d}",
|
||||
"\\centi": "\\text{c}",
|
||||
"\\milli": "\\text{m}",
|
||||
"\\micro": "\\text{μ}",
|
||||
@@ -144,12 +145,13 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
"\\Ohm": "\\Omega",
|
||||
"\\weber": "\\text{Wb}",
|
||||
"\\tesla": "\\text{T}",
|
||||
"\\bit": "\\text{Bit}",
|
||||
"\\bit": "\\text{bit}",
|
||||
"\\baud": "\\text{Bd}",
|
||||
"\\sample": "\\text{S}",
|
||||
"\\degreeCelsius": "\\,\\degree\\text{C}",
|
||||
"\\liter": "\\text{l}",
|
||||
"\\oszidiv": "\\text{div}",
|
||||
"\\scopediv": "\\text{div}",
|
||||
"\\sps": "\\text{sps}",
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ function answer(el, correct) {
|
||||
btn.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
btn.classList.toggle("btn-primary", on);
|
||||
btn.classList.toggle("btn-secondary", !on);
|
||||
btn.title = on ? "Alles anzeigen" : "Nur Fragen anzeigen";
|
||||
btn.title = on ? "Visa allt" : "Visa endast frågor";
|
||||
}
|
||||
|
||||
function setQuizMode(on) {
|
||||
@@ -68,7 +68,7 @@ function answer(el, correct) {
|
||||
var btn = document.getElementById("quiz-mode-toggle");
|
||||
if (btn) updateButton(btn, on);
|
||||
if (on && !hasQ) {
|
||||
showNotice("Keine Fragen auf dieser Seite gefunden.");
|
||||
showNotice("Inga frågor hittades på den här sidan.");
|
||||
} else {
|
||||
hideNotice();
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ span.formula {
|
||||
}
|
||||
|
||||
.course .margin.tip:before {
|
||||
content: "Tipp";
|
||||
content: "Tips";
|
||||
background-color: #b8eaff;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
|
||||
}
|
||||
@@ -370,13 +370,13 @@ span.formula {
|
||||
}
|
||||
|
||||
.course .margin.unit:before {
|
||||
content: "Neue Einheit";
|
||||
content: "Ny enhet";
|
||||
background-color: #b5e8d3;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M208-120q-37 0-62.5-25.5T120-208v-548q0-29 27-40.5t47 8.5l90 90-54 54 28 28 54-54 104 104-54 54 28 28 54-54 104 104-54 54 28 28 54-54 104 104-54 54 28 28 54-54 80 80q20 20 8.5 47T756-120H208Zm32-120h332L240-572v332Z"/></svg>');
|
||||
}
|
||||
|
||||
.course .margin.indepth:before {
|
||||
content: "Vertiefung";
|
||||
content: "Fördjupning";
|
||||
background-color: #ddd;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-80q-26 0-47-12.5T400-126q-33 0-56.5-23.5T320-206v-142q-59-39-94.5-103T190-590q0-121 84.5-205.5T480-880q121 0 205.5 84.5T770-590q0 77-35.5 140T640-348v142q0 33-23.5 56.5T560-126q-12 21-33 33.5T480-80Zm-80-126h160v-36H400v36Zm0-76h160v-38H400v38Zm-8-118h58v-108l-88-88 42-42 76 76 76-76 42 42-88 88v108h58q54-26 88-76.5T690-590q0-88-61-149t-149-61q-88 0-149 61t-61 149q0 63 34 113.5t88 76.5Zm88-162Zm0-38Z"/></svg>');
|
||||
}
|
||||
@@ -386,7 +386,7 @@ span.formula {
|
||||
}
|
||||
|
||||
.course .margin.attention:before {
|
||||
content: "Achtung";
|
||||
content: "Observera";
|
||||
background-color: #ffe5a9;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-280q17 0 28.5-11.5T520-320q0-17-11.5-28.5T480-360q-17 0-28.5 11.5T440-320q0 17 11.5 28.5T480-280Zm-40-160h80v-240h-80v240Zm40 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
|
||||
}
|
||||
@@ -396,7 +396,7 @@ span.formula {
|
||||
}
|
||||
|
||||
.course .margin.danger:before {
|
||||
content: "Gefahr";
|
||||
content: "Fara";
|
||||
background-color: #ffcfcc;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m40-120 440-760 440 760H40Zm138-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm-40-120h80v-200h-80v200Zm40-100Z"/></svg>');
|
||||
}
|
||||
|
||||
@@ -158,37 +158,10 @@ h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.fiftyohm-darc-logo {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.fiftyohm-logo {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.darc-logo {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.fiftyohm-darc-logo path.background {
|
||||
fill: #00ADEF;
|
||||
}
|
||||
|
||||
.fiftyohm-darc-logo path.foreground {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
@media (min-width: 940px) {
|
||||
.fiftyohm-darc-logo {
|
||||
width: 56px;
|
||||
left: auto;
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.fiftyohm-brand {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* DARC Theme based on:
|
||||
* Theme based on:
|
||||
* A simple theme for reveal.js presentations, similar
|
||||
* to the default theme. The accent color is darkblue.
|
||||
*
|
||||
@@ -386,12 +386,12 @@ section.has-dark-background h6 {
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* OWN ADDITIONS TO DARC THEME
|
||||
* OWN ADDITIONS TO THE THEME
|
||||
*********************************************/
|
||||
|
||||
/* Scalable Logo on bottom left */
|
||||
body:after {
|
||||
background-image: url(images/50ohm_rus.svg);
|
||||
background-image: url(images/50ohm_gray.svg);
|
||||
background-size: 8.5em 5em;
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import src.build as build
|
||||
import src.config as config
|
||||
from src.edition import Edition
|
||||
|
||||
conf = config.Config()
|
||||
|
||||
# Build Everything:
|
||||
bd = build.Build(conf)
|
||||
bd.build_website()
|
||||
bd.build_edition("SWL")
|
||||
bd.build_edition("N")
|
||||
bd.build_edition("E")
|
||||
bd.build_edition("A")
|
||||
bd.build_edition("NE")
|
||||
bd.build_edition("EA")
|
||||
bd.build_edition("NEA")
|
||||
for edition in Edition:
|
||||
bd.build_edition(edition)
|
||||
bd.build_assets()
|
||||
bd.build_solutions()
|
||||
bd.build_question_index()
|
||||
|
||||
@@ -1,114 +1,107 @@
|
||||
# Erstellen von Folien
|
||||
# Skapa presentationer
|
||||
|
||||
Das Erstellen von Folien ist direkt im Directus möglich. Wir verwenden reveal.js als Framework, um die Inhalte darzustellen.
|
||||
Presentationerna skrivs som markdown-filer i innehållsrepot (`contents/slides/<ident>.md`, en fil per avsnitt). Vi använder reveal.js som ramverk för att visa innehållet.
|
||||
|
||||
## Directus
|
||||
## Format som stöds
|
||||
|
||||
Im Directus gibt es zu jeder Sektion ein Feld _Slide_ in dem vereinfacht die Inhalte von Folien eingegeben werden können.
|
||||
### Bildbyte
|
||||
|
||||
## Unterstützte Formate
|
||||
Varje bild (utom den första) börjar med `---`. Det skapar en ny bild.
|
||||
|
||||
### Folientrennung
|
||||
#### Särskilda bilder
|
||||
|
||||
Jede Folie (außer die erste) beginnt mit `---`. Dadurch wird eine neue Folie erzeugt.
|
||||
|
||||
#### Spezielle Folien
|
||||
|
||||
Reveal.js erlaubt es, Folien bestimmte Attribute, wie beispielsweise die Hintergrundfarbe zu übermitteln. Das kann direkt beim Erstellen einer Folie angegeben werden.
|
||||
Reveal.js låter dig ge bilder särskilda attribut, till exempel bakgrundsfärg. Det anges direkt när bilden skapas.
|
||||
|
||||
``` MarkDown
|
||||
--- data-background="#FF0000"
|
||||
```
|
||||
|
||||
Dadurch wird die Folie in knallrot gefärbt. Das sollte nur in Ausnahmen verwendet werden.
|
||||
Då blir bilden knallröd. Det bör bara användas i undantagsfall.
|
||||
|
||||
Alternativ werden drei Begriffe ausgewertet, die bereits auf der Webseitenansicht zum Einsatz kommen.
|
||||
Dessutom tolkas tre nyckelord som även används i webbvyn.
|
||||
|
||||
``` MarkDown
|
||||
--- unit
|
||||
```
|
||||
|
||||
Wird verwendet, um eine neue Einheit einzuführen.
|
||||
Färbt die Folie hellgrün ein.
|
||||
Används för att introducera en ny enhet. Färgar bilden ljusgrön.
|
||||
|
||||
``` MarkDown
|
||||
--- attention
|
||||
```
|
||||
|
||||
Wird verwendet, um die Aufmerksamkeit zu erregen. Beispielsweise bei Hinweisen auf die Gültigkeit bei Inkrafttreten der AfuV.
|
||||
Färbt die Folie hellblau ein.
|
||||
Används för att fånga uppmärksamheten, till exempel vid hänvisningar till föreskrifternas giltighet. Färgar bilden ljusblå.
|
||||
|
||||
``` attention
|
||||
``` MarkDown
|
||||
--- danger
|
||||
```
|
||||
|
||||
Wird verwendet, um auf Gefahren hinzuweisen. Beispielsweise beim Umgang mit elektrischem Strom.
|
||||
Färbt die Folie hellrot ein.
|
||||
Används för att varna för faror, till exempel vid hantering av elektrisk ström. Färgar bilden ljusröd.
|
||||
|
||||
### Überschriften
|
||||
### Rubriker
|
||||
|
||||
Überschriften werden mit dem `#`-Zeichen eingeleitet. Dabei gibt die Häufigkeit des Zeichens die Ebene der Überschrift an.
|
||||
Rubriker inleds med tecknet `#`. Antalet tecken anger rubrikens nivå.
|
||||
|
||||
``` MarkDown
|
||||
# Überschrift 1
|
||||
## Überschrift 2
|
||||
### Überschrift 3
|
||||
# Rubrik 1
|
||||
## Rubrik 2
|
||||
### Rubrik 3
|
||||
```
|
||||
|
||||
Die maximale Ebene ist 6.
|
||||
Den högsta nivån är 6.
|
||||
|
||||
### Listen
|
||||
### Listor
|
||||
|
||||
Häufig sind auf Folien Listen zu sehen. Diese lassen sich mit `*` einleiten.
|
||||
På bilder förekommer ofta listor. De inleds med `*`.
|
||||
|
||||
``` MarkDown
|
||||
* Listenpunkt
|
||||
* Noch ein Listenpunkt
|
||||
* Listpunkt
|
||||
* Ännu en listpunkt
|
||||
```
|
||||
|
||||
TODO: Verschachtelte Listen sind noch nicht möglich
|
||||
TODO: Nästlade listor stöds ännu inte.
|
||||
|
||||
### Tabellen
|
||||
### Tabeller
|
||||
|
||||
Tabellen werden mit Zeichen `|` zur Unterteilung der Spalten gesetzt. Die erste Spalte ist eine Kopfspalte. In ihr kann angegeben werden, ob der Inhalt der Spalte linksbündig (`l`), rechtsbündig (`r`) oder mittig (`c`) ausgerichtet sein soll.
|
||||
Tabeller skrivs med tecknet `|` som kolumnavgränsare. Den första raden är en rubrikrad. Där kan du ange om kolumnens innehåll ska vara vänsterjusterat (`l`), högerjusterat (`r`) eller centrerat (`c`).
|
||||
|
||||
``` Markdown
|
||||
| l: Wert | l: Bereich | l: Bedeutung | l: Englisch |
|
||||
| R | 1 - 5 | Lesbarkeit | Readability |
|
||||
| S | 1 - 9 | Signalstärke | Signal Strength |
|
||||
| T | 1 - 9 | Tonqualität | Tone |
|
||||
[table:n_rst:Die Bestandteile des RST-Rapports]
|
||||
| l: Värde | l: Intervall | l: Betydelse | l: Engelska |
|
||||
| R | 1 - 5 | Läsbarhet | Readability |
|
||||
| S | 1 - 9 | Signalstyrka | Signal Strength |
|
||||
| T | 1 - 9 | Tonkvalitet | Tone |
|
||||
[table:n_rst:Delarna i en RST-rapport]
|
||||
```
|
||||
|
||||
Die Tabelle muss mit `[table:referenz:Beschreibung]` abgeschlossen werden. Dadurch wird intern eine Referenz gesetzt, auf die verwiesen werden kann.
|
||||
Tabellen måste avslutas med `[table:referens:Beskrivning]`. Det skapar en intern referens som kan länkas till.
|
||||
|
||||
### Textauszeichnung
|
||||
### Textformatering
|
||||
|
||||
Es kann einfache Textauszeichnung, wie _hervorgehoben_ oder <u>unterstrichen</u> verwendet werden.
|
||||
Enkel textformatering som _betonad_ eller <u>understruken</u> text kan användas.
|
||||
|
||||
``` MarkDown
|
||||
Es kann einfache Textauszeichnung, wie *hervorgehoben* oder <u>unterstrichen</u> verwendet werden.
|
||||
Enkel textformatering som *betonad* eller <u>understruken</u> text kan användas.
|
||||
```
|
||||
|
||||
### Bilder
|
||||
|
||||
Bilder werden mit einer Referenz auf das Bild in der Datenbank eingefügt.
|
||||
Bilder infogas med en referens till bilden i innehållsrepot.
|
||||
|
||||
``` MarkDown
|
||||
[photo:123:n_rst_s-meter:Display eines IC9700-Transceivers, hervorgehoben ist das S-Meter, das den aktuellen Empfangspegel anzeigt]
|
||||
[photo:123:n_rst_s-meter:Display på en IC-9700, S-metern som visar aktuell mottagningsnivå är markerad]
|
||||
```
|
||||
|
||||
Es kann `photo` oder `picture` verwendet werden, je nach Datenbanktabelle in der das Bild abgelegt ist. Als nächstes wird die Nummer des Bildes angegeben. Darauf folgt eine Referenz für Verweise. Und abschließend die Beschreibung, die unter dem Bild angezeigt wird. Die Bilder werden pro Dokument durchnummeriert.
|
||||
Antingen `photo` eller `picture` används, beroende på var bilden ligger (`contents/photos` eller `contents/drawings`). Därefter anges bildens nummer, sedan en referens för länkar och till sist beskrivningen som visas under bilden. Bilderna numreras per dokument.
|
||||
|
||||
### Fragen aus dem Prüfungskatalog
|
||||
### Frågor ur frågebanken
|
||||
|
||||
Fragen aus dem Fragenkatalog können durch eine Referenz auf die Fragennummer eingefügt werden.
|
||||
Om innehållsrepot har en frågebank (se README) kan frågor infogas med en referens till frågenumret.
|
||||
|
||||
``` Markdown
|
||||
[question:2482]
|
||||
```
|
||||
|
||||
Fragen sollten auf einer eigenen Folie angezeigt werden, da sie in der Regel sehr groß sind.
|
||||
Frågor bör visas på en egen bild eftersom de oftast är stora.
|
||||
|
||||
``` Markdown
|
||||
---
|
||||
@@ -116,119 +109,119 @@ Fragen sollten auf einer eigenen Folie angezeigt werden, da sie in der Regel seh
|
||||
---
|
||||
```
|
||||
|
||||
Die Antworten werden beim Erstellen der Folien in eine zufällige Reihenfolge gebracht, sodass nicht wie im Prüfungskatalog die erste Antwort die richtige ist.
|
||||
Svarsalternativen blandas när presentationen byggs, så att inte första svaret alltid är rätt som i frågebanken.
|
||||
|
||||
### QSO
|
||||
|
||||
Ein beispielhaftes QSO kann folgendermaßen hinzugefügt werden:
|
||||
Ett exempel-QSO kan läggas till så här:
|
||||
|
||||
``` Markdown
|
||||
<qso>
|
||||
Ist diese Frequenz frei? DL1PZ
|
||||
> *(keine Antwort)*
|
||||
Ist diese Frequenz frei? DL1PZ
|
||||
> *(keine Antwort)*
|
||||
CQ CQ hier ist DL1PZ mit einem allgemeinen Anruf, hier ist DL1PZ und hört.
|
||||
> DL1PZ hier ist DL9MJ bitte kommen
|
||||
Är frekvensen ledig? SM5ABC
|
||||
> *(inget svar)*
|
||||
Är frekvensen ledig? SM5ABC
|
||||
> *(inget svar)*
|
||||
CQ CQ, här är SM5ABC med ett allmänt anrop, här är SM5ABC och lyssnar.
|
||||
> SM5ABC, här är SM0XYZ, varsågod
|
||||
</qso>
|
||||
```
|
||||
|
||||
Jede Zeile ist eine Sprechblase. Die einzelnen Sprechblasen werden nacheinander aufgedeckt. Zeilen, die mit `>` beginnen, werden als Teil der Gegenstelle angezeigt.
|
||||
Varje rad är en pratbubbla. Bubblorna visas en efter en. Rader som börjar med `>` visas som motstationens bidrag.
|
||||
|
||||
### Einblendeeffekt
|
||||
### Inblandningseffekt
|
||||
|
||||
Soll ein Teil der Folie erst später aufgedeckt werden, kann dieser in `<fragment>` eingebettet werden.
|
||||
Om en del av bilden ska visas först senare kan den läggas i `<fragment>`.
|
||||
|
||||
``` MarkDown
|
||||
<fragment>
|
||||
Dieser Text erscheint erst später.
|
||||
Den här texten visas först senare.
|
||||
</fragment>
|
||||
```
|
||||
|
||||
Mehrere `<fragment>`-Abschnitte nacheinander sorgen dafür, dass die Inhalte Schritt für Schritt aufgedeckt werden.
|
||||
Flera `<fragment>`-avsnitt efter varandra gör att innehållet avslöjas steg för steg.
|
||||
|
||||
### Notizen
|
||||
### Anteckningar
|
||||
|
||||
Es ist möglich, Notizen für den oder die Vortragende hinzuzufügen. Die sind nur in der "Speaker-Ansicht" (Taste 's' drücken) sichtbar.
|
||||
Du kan lägga till anteckningar för föredragshållaren. De syns bara i talarvyn (tryck på ”s”).
|
||||
|
||||
Sinnvoll sind kurze Hinweise auf die Erklärungen, die in der Webseitenversion gegeben werden oder Hintergrundinformationen. Die brauchen nicht auf die Folien. Und kurze Hinweise sollten für Funkamateure ausreichend sein, um die Notiz zu verstehen und den Inhalt zu vermitteln.
|
||||
Det är lämpligt med korta hänvisningar till förklaringarna i webbversionen eller bakgrundsinformation. Sådant behöver inte stå på bilderna. Korta anteckningar bör räcka för en radioamatör att förstå och förmedla innehållet.
|
||||
|
||||
``` MarkDown
|
||||
<note>
|
||||
Die Notiz wird nur in der Speaker-Ansicht angezeigt
|
||||
* Listen sind auch möglich
|
||||
* Am besten kurz halten
|
||||
* Der Platz ist begrenzt
|
||||
Anteckningen visas bara i talarvyn
|
||||
* Listor går också bra
|
||||
* Håll dem helst korta
|
||||
* Utrymmet är begränsat
|
||||
</note>
|
||||
```
|
||||
|
||||
### Formeln
|
||||
### Formler
|
||||
|
||||
Es können Formeln im LaTeX-Stil angegeben werden. Diese werden in `$` gesetzt.
|
||||
Formler i LaTeX-stil kan anges. De skrivs inom `$`.
|
||||
|
||||
``` MarkDown
|
||||
$\lambda[[\text{m}]] = \dfrac{300}{f[[\text{MHz}]]} = \dfrac{300}{145,3 \ \text{MHz}} \approx 2,06 \ \text{m}$
|
||||
```
|
||||
|
||||
Abweichend von LaTeX müssen die rechteckigen Klammern gedoppelt werden.
|
||||
Till skillnad från LaTeX måste hakparenteser dubbleras. Använd decimalkomma. Enheter kan skrivas med `\qty{145,3}{\mega\hertz}`.
|
||||
|
||||
### Links
|
||||
### Länkar
|
||||
|
||||
Es können Links eingefügt werden.
|
||||
Länkar kan infogas.
|
||||
|
||||
``` MarkDown
|
||||
[Link zum DARC](https://darc.de/)
|
||||
[Länk till SSA](https://www.ssa.se/)
|
||||
```
|
||||
|
||||
### Zwei Spalten
|
||||
### Två kolumner
|
||||
|
||||
Manchmal ist es sinnvoll, zwei Spalten zu verwenden. Beispielsweise bei einem Bild mit Beschreibung. Dazu gibt es die beiden Tags `<left>` und `<right>`.
|
||||
Ibland är två kolumner praktiskt, till exempel för en bild med beskrivning. Då används taggarna `<left>` och `<right>`.
|
||||
|
||||
``` MarkDown
|
||||
<left>
|
||||
[photo:167:rufzeichen_flugzeug:Flugzeug mit dem Rufzeichen DEBPF]
|
||||
[photo:167:rufzeichen_flugzeug:Flygplan med anropssignalen SE-ABC]
|
||||
</left>
|
||||
<right>
|
||||
* Funkstationen verwenden Rufzeichen, um sich zu identifizieren
|
||||
* Folge von Buchstaben und Ziffern
|
||||
* Jedes mit Funk ausgerüstete Flugzeug und Schiff hat ein Rufzeichen
|
||||
* Radiostationer använder anropssignaler för att identifiera sig
|
||||
* En följd av bokstäver och siffror
|
||||
* Varje flygplan och fartyg med radioutrustning har en anropssignal
|
||||
</right>
|
||||
```
|
||||
|
||||
### Webseite interaktiv einbetten
|
||||
### Bädda in en webbsida interaktivt
|
||||
|
||||
Es kann eine ganze Webseite interaktiv eingebettet werden, sodass darin agiert werden kann. Zusätzlich sind die Navigationspfeile und der Speaker-View erhalten.
|
||||
En hel webbsida kan bäddas in interaktivt så att man kan använda den. Navigeringspilarna och talarvyn finns kvar.
|
||||
|
||||
``` MarkDown
|
||||
--- data-background-iframe="https://f5len.org/tools/locator/" data-background-interactive
|
||||
|
||||
<note>
|
||||
* Es wird eine interaktive Karte mit Maidenhead-Locator gezeigt.
|
||||
* En interaktiv karta med Maidenhead-lokator visas.
|
||||
</note>
|
||||
```
|
||||
|
||||
Zusätzlich eine Speaker-Note einzufügen ist sinnvoll, um keine leere Slide zu erzeugen und den Speaker darauf hinzuweisen, dass die Webseite nur vom Hauptbildschirm bedient werden kann.
|
||||
Det är bra att lägga till en anteckning så att bilden inte blir tom och för att påminna föredragshållaren om att webbsidan bara kan styras från huvudskärmen.
|
||||
|
||||
### Kleinere Schrift
|
||||
### Mindre text
|
||||
|
||||
In ganz seltenen Ausnahmen kann eine kleinere Schrift verwendet werden. Das kann dann angewandt werden, wenn ein oder zwei Zeilen einer Tabelle nicht mehr auf die Folie passen.
|
||||
I mycket sällsynta undantag kan mindre text användas, till exempel när en eller två rader i en tabell inte längre får plats på bilden.
|
||||
|
||||
``` MarkDown
|
||||
--- style="font-size: smaller;"
|
||||
|
||||
* Längere
|
||||
* Liste
|
||||
* Längre
|
||||
* lista
|
||||
```
|
||||
|
||||
### Direkter Übergang
|
||||
### Direkt övergång
|
||||
|
||||
Ohne verschieben der Folie zur nächsten Schalten. Das kann als Effekt genutzt werden, damit auf der Folie ein Austauscheffekt stattfindet.
|
||||
Byt till nästa bild utan övergångseffekt. Det kan användas för att få ett utbyteseffekt på bilden.
|
||||
|
||||
```MarkDown
|
||||
---
|
||||
## Folie
|
||||
Mit Text
|
||||
## Bild
|
||||
Med text
|
||||
--- data-transition="none"
|
||||
## Folie
|
||||
Mit anderem Text
|
||||
## Bild
|
||||
Med annan text
|
||||
```
|
||||
|
||||
@@ -4,6 +4,6 @@ WORKDIR /app
|
||||
COPY requirements.txt requirements.txt
|
||||
RUN pip3 install -r requirements.txt
|
||||
|
||||
COPY --parents api assets latex renderer src templates main.py LICENSE ./
|
||||
COPY --parents assets latex renderer src templates main.py LICENSE ./
|
||||
|
||||
ENTRYPOINT ["python3", "main.py"]
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
\disable@package@load{physics}{}
|
||||
|
||||
\LoadClass[ngerman, 10pt,twocolumn=true,fontsize=9pt,parskip=half-,listof=leveldown,bibliography=leveldown]{scrreprt}
|
||||
\LoadClass[swedish, 10pt,twocolumn=true,fontsize=9pt,parskip=half-,listof=leveldown,bibliography=leveldown]{scrreprt}
|
||||
\deftocheading{toc}{\section*{\contentsname}}
|
||||
|
||||
\input{settings-pre.tex}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
\RequirePackage{mathtools}
|
||||
\@fleqnfalse
|
||||
|
||||
\PassOptionsToPackage{ngerman}{babel}
|
||||
\PassOptionsToPackage{swedish}{babel}
|
||||
\RequirePackage{babel}
|
||||
\RequirePackage{microtype}
|
||||
|
||||
@@ -264,21 +264,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
\newcommand{\MarginBoxDanger}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=danger-title,colframe=danger-frame, title=\faExclamationTriangle\space Gefahr]#1\end{tcolorbox}}
|
||||
\newcommand{\MarginBoxDanger}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=danger-title,colframe=danger-frame, title=\faExclamationTriangle\space Fara]#1\end{tcolorbox}}
|
||||
|
||||
\newcommand{\MarginBoxAttention}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=attention-title,colframe=attention-frame,title=\faExclamationCircle\space Achtung]#1\end{tcolorbox}}
|
||||
\newcommand{\MarginBoxAttention}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=attention-title,colframe=attention-frame,title=\faExclamationCircle\space Observera]#1\end{tcolorbox}}
|
||||
|
||||
\newcommand{\MarginBoxTip}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=hint-title,colframe=hint-frame,title=\faInfoCircle\space Tipp]#1\end{tcolorbox}}
|
||||
\newcommand{\MarginBoxTip}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=hint-title,colframe=hint-frame,title=\faInfoCircle\space Tips]#1\end{tcolorbox}}
|
||||
|
||||
\newcommand{\WebBoxTip}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=hint-title,colframe=hint-frame,title=\faInfoCircle\space Tipp]#1\end{tcolorbox}
|
||||
\newcommand{\WebBoxTip}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=hint-title,colframe=hint-frame,title=\faInfoCircle\space Tips]#1\end{tcolorbox}
|
||||
|
||||
}
|
||||
|
||||
\newcommand{\MarginBoxUnit}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=unit-title,colframe=unit-frame, title=\faRuler\space Neue Einheit]#1\end{tcolorbox}}
|
||||
\newcommand{\MarginBoxUnit}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=unit-title,colframe=unit-frame, title=\faRuler\space Ny enhet]#1\end{tcolorbox}}
|
||||
|
||||
\newcommand{\MarginBoxInDepth}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=advanced-title,colframe=advanced-frame,title={\faLightbulb[regular]\space Vertiefung}]#1\end{tcolorbox}}
|
||||
\newcommand{\MarginBoxInDepth}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=advanced-title,colframe=advanced-frame,title={\faLightbulb[regular]\space Fördjupning}]#1\end{tcolorbox}}
|
||||
|
||||
\newcommand{\BoxInDepth}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=advanced-title,colframe=advanced-frame,title={\faLightbulb[regular]\space Vertiefung}]#1\end{tcolorbox}
|
||||
\newcommand{\BoxInDepth}[1]{\begin{tcolorbox}[marginboxstyle,colbacktitle=advanced-title,colframe=advanced-frame,title={\faLightbulb[regular]\space Fördjupning}]#1\end{tcolorbox}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
\NewDocumentCommand{\DARCimage}{sO{Bild~zur~Prüfungsfrage~\l_ptxcd_question_tl}mm}{
|
||||
\NewDocumentCommand{\DARCimage}{sO{Bild~till~provfrågan~\l_ptxcd_question_tl}mm}{
|
||||
\par\smallskip
|
||||
\begingroup
|
||||
\ptxcd_image_autoscale_setup:nnn {#1} {#3} {#4}
|
||||
|
||||
@@ -11,14 +11,10 @@ app = typer.Typer()
|
||||
|
||||
@app.command()
|
||||
def main(
|
||||
edition: Annotated[list[Edition], typer.Option(help="Edition to build, can be specified multiple times.")] = [ # noqa: B006 -- default value is required for typer
|
||||
Edition.swl,
|
||||
Edition.n,
|
||||
Edition.e,
|
||||
Edition.a,
|
||||
Edition.ne,
|
||||
Edition.ea,
|
||||
Edition.nea,
|
||||
edition: Annotated[list[Edition], typer.Option(help="Course to build, can be specified multiple times.")] = [ # noqa: B006 -- default value is required for typer
|
||||
Edition.instegs,
|
||||
Edition.harec,
|
||||
Edition.uppgradering,
|
||||
],
|
||||
input: Annotated[str | None, typer.Option("--input", "-i", help="Content source directory.")] = None,
|
||||
output: Annotated[str | None, typer.Option("--output", "-o", help="Destination directory to build to.")] = None,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "50ohm-de"
|
||||
version = "0.1.0"
|
||||
description = "Generator für 50ohm.de, die Ausbildungsplattform des DARC e.V."
|
||||
description = "Generator för en svensk webbplats för utbildning inför Instegscertifikatet och HAREC (anpassad från 50ohm.de)"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
|
||||
@@ -103,7 +103,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
|
||||
return None
|
||||
|
||||
def render_quote(self, token):
|
||||
return f"„{self.render_inner(token)}“"
|
||||
return f"”{self.render_inner(token)}”"
|
||||
|
||||
def render_underline(self, token):
|
||||
return f"<u>{self.render_inner(token)}</u>"
|
||||
@@ -111,8 +111,8 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
|
||||
@classmethod
|
||||
def render_unit(cls, token: Unit):
|
||||
unit = token.prefix + cls.convert_unit_helper(token.unit)
|
||||
if token.unit in ["°", "%"]:
|
||||
# Special cases with no space between value and unit.
|
||||
if token.unit == "°":
|
||||
# Special case with no space between value and unit.
|
||||
return f"{token.value}{unit}"
|
||||
else:
|
||||
# Default case is rendered with a narrow no-break space.
|
||||
@@ -120,6 +120,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
|
||||
|
||||
units = {
|
||||
"Ohm": "Ω",
|
||||
"ohm": "Ω",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -234,7 +235,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
|
||||
return (
|
||||
f'<figure class="picture" id="ref_{marker}" name="{marker}">\n'
|
||||
f' <img src="pictures/{id}.svg" alt="{alt_text}">\n'
|
||||
f" <figcaption>Abbildung {label}: {text}</figcaption>\n"
|
||||
f" <figcaption>Figur {label}: {text}</figcaption>\n"
|
||||
"</figure>\n"
|
||||
)
|
||||
|
||||
@@ -243,7 +244,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
|
||||
return f"""
|
||||
<figure class="photo" id="ref_{ref}" name="{ref}">
|
||||
<img src="photos/{id}.png" alt="{alt_text}">
|
||||
<figcaption>Abbildung {label}: {text}</figcaption>
|
||||
<figcaption>Figur {label}: {text}</figcaption>
|
||||
</figure>
|
||||
"""
|
||||
|
||||
@@ -276,7 +277,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
|
||||
caption_text = token.caption
|
||||
label = self._format_reference_label(token.name)
|
||||
if label:
|
||||
caption_text = f"Tabelle {label}: {token.caption}"
|
||||
caption_text = f"Tabell {label}: {token.caption}"
|
||||
table += f"<caption>{caption_text}</caption>\n"
|
||||
|
||||
table += "</table>"
|
||||
|
||||
@@ -5,11 +5,11 @@ from mistletoe.span_token import SpanToken
|
||||
|
||||
class HalfwidthSpaces(SpanToken):
|
||||
"""
|
||||
Insert halfwidth space into span token (Z. B.)
|
||||
Identifies "z.B.", "d.h." and "D.h." with and without space in between.
|
||||
Insert halfwidth space into span token (t. ex.)
|
||||
Identifies "t.ex." and "T.ex." with and without space in between.
|
||||
"""
|
||||
|
||||
pattern = re.compile(r"\b(z|Z|d|D)\.\s?(B|h)\.")
|
||||
pattern = re.compile(r"\b(t|T)\.\s?(ex)\.")
|
||||
|
||||
def __init__(self, match_object):
|
||||
self.first = match_object.group(1)
|
||||
|
||||
@@ -9,8 +9,8 @@ class Image(ReferencedToken):
|
||||
"""
|
||||
Block token for pictures and photos.
|
||||
Examples:
|
||||
[picture:727:amplitude_periode_halbwellen:Positive und negative Halbwellen einer Sinusschwingung]
|
||||
[photo:123:n_wasserfalldiagramm_trx_collage:Ansichten verschiedener Transceiver]
|
||||
[picture:727:amplitude_period_halvvagor:Positiva och negativa halvvågor hos en sinusvåg]
|
||||
[photo:123:n_vattenfall_trx_collage:Vyer av olika transceivrar]
|
||||
"""
|
||||
|
||||
pattern = re.compile(r"^\[(?P<kind>picture|photo):(?P<id>\d+):(?P<marker>[^:\]]+):(?P<text>[^:\]]+)\]$")
|
||||
|
||||
@@ -42,10 +42,10 @@ class Morse(SpanToken):
|
||||
"x": [dah, dit, dit, dah],
|
||||
"y": [dah, dit, dah, dah],
|
||||
"z": [dah, dah, dit, dit],
|
||||
"å": [dit, dah, dah, dit, dah],
|
||||
"ä": [dit, dah, dit, dah],
|
||||
"ö": [dah, dah, dah, dit],
|
||||
"ü": [dit, dit, dah, dah],
|
||||
"ß": [dit, dit, dit, dah, dah, dit, dit],
|
||||
"é": [dit, dit, dah, dit, dit],
|
||||
"0": [dah, dah, dah, dah, dah],
|
||||
"1": [dit, dah, dah, dah, dah],
|
||||
"2": [dit, dit, dah, dah, dah],
|
||||
|
||||
@@ -5,15 +5,16 @@ from mistletoe.span_token import SpanToken
|
||||
|
||||
class NonbreakingSpaces(SpanToken):
|
||||
"""
|
||||
Insert unbreakable space into span token (§ 3)
|
||||
Identifies "§$number", "Abs.$number", "Klasse [A,E,N]" w/ and without space between.
|
||||
Insert unbreakable space into span token (3 §)
|
||||
Identifies "$number §", "$number kap.", "$number st.", "$number mom." as well as
|
||||
"PTSFS $number", "Report $number", "Rec. $number" and "Bilaga $number" w/ and without space between.
|
||||
"""
|
||||
|
||||
pattern = re.compile(r"(§|Abs\.|Klasse)\s?(\d|[NEA])")
|
||||
pattern = re.compile(r"(?:\b(\d+)\s?(§|kap\.|st\.|mom\.)|\b(PTSFS|Report|Rec\.|Bilaga|bilaga)\s?(\d))")
|
||||
|
||||
def __init__(self, match_object):
|
||||
self.first = match_object.group(1)
|
||||
self.second = match_object.group(2)
|
||||
self.first = match_object.group(1) or match_object.group(3)
|
||||
self.second = match_object.group(2) or match_object.group(4)
|
||||
|
||||
|
||||
class NonbreakingSpacesDots(SpanToken):
|
||||
|
||||
@@ -9,8 +9,8 @@ class Unit(SpanToken):
|
||||
"Ah",
|
||||
"A/mm²",
|
||||
"baud",
|
||||
"Bit",
|
||||
"Bit/s",
|
||||
"bit",
|
||||
"bit/s",
|
||||
"dB",
|
||||
"dBi",
|
||||
"dBm",
|
||||
@@ -23,6 +23,7 @@ class Unit(SpanToken):
|
||||
"m",
|
||||
"m²",
|
||||
"Ohm",
|
||||
"ohm",
|
||||
"ppm",
|
||||
"pps",
|
||||
"s",
|
||||
|
||||
@@ -16,6 +16,8 @@ from renderer.fifty_ohm_html_slide_renderer import FiftyOhmHtmlSlideRenderer
|
||||
from renderer.index import Index
|
||||
|
||||
from .config import Config
|
||||
from .edition import Edition
|
||||
from .pages import EXAM_RESULT, EXAM_SIMULATOR, HOMEWORK, PAGES, page_urls
|
||||
|
||||
|
||||
class Build:
|
||||
@@ -24,33 +26,19 @@ class Build:
|
||||
|
||||
self.env = Environment(loader=FileSystemLoader(self.config.p_templates))
|
||||
self.env.filters["shuffle_answers"] = self.__filter_shuffle_answers
|
||||
with self.config.p_data_fragenkatalog.open(encoding="utf-8") as file:
|
||||
self.fragenkatalog = json.load(file)
|
||||
self.has_question_pool = self.config.has_question_pool
|
||||
self.env.globals["has_question_pool"] = self.has_question_pool
|
||||
self.env.globals["pages"] = page_urls()
|
||||
|
||||
supplemental_questions = {}
|
||||
if self.config.p_data_fragenkatalog_swl.exists():
|
||||
with self.config.p_data_fragenkatalog_swl.open(encoding="utf-8") as file:
|
||||
swl_fragenkatalog = json.load(file)
|
||||
supplemental_questions = self.__parse_katalog(swl_fragenkatalog)
|
||||
self.fragenkatalog["sections"].extend(swl_fragenkatalog.get("sections", []))
|
||||
|
||||
with self.config.p_data_metadata.open(encoding="utf-8") as file:
|
||||
self.question_metadata = json.load(file)
|
||||
self.questions = self.__parse_katalog(self.fragenkatalog)
|
||||
|
||||
for number in supplemental_questions:
|
||||
self.question_metadata.setdefault(
|
||||
number,
|
||||
{
|
||||
"directus_id": "",
|
||||
"picture_question": "",
|
||||
"picture_a": "",
|
||||
"picture_b": "",
|
||||
"picture_c": "",
|
||||
"picture_d": "",
|
||||
"layout": "",
|
||||
},
|
||||
)
|
||||
self.question_pool = {"sections": []}
|
||||
self.question_metadata = {}
|
||||
if self.has_question_pool:
|
||||
with self.config.p_data_question_pool.open(encoding="utf-8") as file:
|
||||
self.question_pool = json.load(file)
|
||||
if self.config.p_data_metadata.exists():
|
||||
with self.config.p_data_metadata.open(encoding="utf-8") as file:
|
||||
self.question_metadata = json.load(file)
|
||||
self.questions = self.__parse_question_pool(self.question_pool)
|
||||
|
||||
self.question_index = {}
|
||||
self.question_token_pattern = re.compile(r"^\s*\[question:([\w\d]+)\]", re.MULTILINE)
|
||||
@@ -58,8 +46,18 @@ class Build:
|
||||
self.index_entries = {}
|
||||
self.index_token_pattern = Index.pattern
|
||||
|
||||
__default_metadata = {
|
||||
"directus_id": "",
|
||||
"picture_question": "",
|
||||
"picture_a": "",
|
||||
"picture_b": "",
|
||||
"picture_c": "",
|
||||
"picture_d": "",
|
||||
"layout": "",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def __parse_katalog(fragenkatalog):
|
||||
def __parse_question_pool(question_pool):
|
||||
questions = {}
|
||||
|
||||
def collect(section):
|
||||
@@ -68,28 +66,27 @@ class Build:
|
||||
for child in section.get("sections", []):
|
||||
collect(child)
|
||||
|
||||
for exam_part in fragenkatalog["sections"]:
|
||||
for exam_part in question_pool["sections"]:
|
||||
collect(exam_part)
|
||||
return questions
|
||||
|
||||
def __build_question(self, number, template_file="html/question.html"):
|
||||
"""Combines the original question dataset from BNetzA with our internal metadata"""
|
||||
"""Combines the question pool with our internal metadata"""
|
||||
|
||||
if not self.has_question_pool:
|
||||
tqdm.write(f"\033[31mQuestion #{number} is referenced, but there is no question pool\033[0m")
|
||||
return ""
|
||||
|
||||
question_template = self.env.get_template(template_file)
|
||||
|
||||
question = self.questions.get(number)
|
||||
metadata = self.question_metadata.get(number)
|
||||
metadata = self.question_metadata.get(number, self.__default_metadata)
|
||||
|
||||
if question is None or metadata is None:
|
||||
tqdm.write(
|
||||
f"\033[31mQuestion #{number} is missing"
|
||||
+ (" (Question not in question pool)" if question is None else "")
|
||||
+ (" (Question not in metadata)" if metadata is None else "")
|
||||
+ "\033[0m"
|
||||
)
|
||||
if question is None:
|
||||
tqdm.write(f"\033[31mQuestion #{number} is missing (Question not in question pool)\033[0m")
|
||||
metadata = {"layout": "not-found", "picture_a": ""}
|
||||
question = {"question": f"Frågan {number} hittades inte"}
|
||||
number = 404
|
||||
question = {"question": f"Frage {input} nicht gefunden"}
|
||||
|
||||
if "answer_a" in question:
|
||||
answers = [question["answer_a"], question["answer_b"], question["answer_c"], question["answer_d"]]
|
||||
@@ -164,9 +161,12 @@ class Build:
|
||||
)
|
||||
|
||||
def __build_exam_simulator(self):
|
||||
if not self.has_question_pool:
|
||||
return
|
||||
|
||||
self.config.p_build_assets.mkdir(parents=True, exist_ok=True)
|
||||
with (self.config.p_build_assets / "fragenkatalog.json").open("w", encoding="utf-8") as file:
|
||||
json.dump(self.fragenkatalog, file, ensure_ascii=False, indent=4)
|
||||
with (self.config.p_build_assets / "question_pool.json").open("w", encoding="utf-8") as file:
|
||||
json.dump(self.question_pool, file, ensure_ascii=False, indent=4)
|
||||
with (self.config.p_build_assets / "metadata.json").open("w", encoding="utf-8") as file:
|
||||
json.dump(self.question_metadata, file, ensure_ascii=False, indent=4)
|
||||
(self.config.p_build_assets / "exam-questions.json").unlink(missing_ok=True)
|
||||
@@ -192,33 +192,22 @@ class Build:
|
||||
"assets/exam-simulator.js?ts=20260901",
|
||||
],
|
||||
)
|
||||
with (self.config.p_build / "simulation.html").open("w", encoding="utf-8") as file:
|
||||
with (self.config.p_build / f"{EXAM_SIMULATOR}.html").open("w", encoding="utf-8") as file:
|
||||
file.write(page)
|
||||
with (self.config.p_build / "result.html").open("w", encoding="utf-8") as file:
|
||||
with (self.config.p_build / f"{EXAM_RESULT}.html").open("w", encoding="utf-8") as file:
|
||||
file.write(page)
|
||||
|
||||
for social_image in sorted((self.config.p_assets / "images").glob("exam-*.jpeg")):
|
||||
result_page = self.__build_page(
|
||||
content,
|
||||
page_stylesheets=["assets/exam-simulator.css?ts=20260806"],
|
||||
page_scripts=[
|
||||
"assets/vue.global.prod.js",
|
||||
"assets/question-catalog.js?ts=20260806",
|
||||
"assets/exam-simulator.js?ts=20260901",
|
||||
],
|
||||
social_image=f"assets/images/{social_image.name}",
|
||||
)
|
||||
result_name = f"result-{social_image.stem.removeprefix('exam-')}.html"
|
||||
with (self.config.p_build / result_name).open("w", encoding="utf-8") as file:
|
||||
file.write(result_page)
|
||||
|
||||
def __build_homework_tool(self):
|
||||
if not self.has_question_pool:
|
||||
return
|
||||
|
||||
toc_target = self.config.p_build_assets / "toc"
|
||||
toc_target.mkdir(parents=True, exist_ok=True)
|
||||
for edition in ("N", "NE", "NEA", "E", "EA", "A"):
|
||||
for edition in Edition:
|
||||
source = self.config.p_data_toc / f"{edition}.json"
|
||||
if not source.exists():
|
||||
source = self.config.p_data_toc / f"{edition.lower()}.json"
|
||||
tqdm.write(f"\033[31mtoc/{edition}.json not found, homework tool will not offer it\033[0m")
|
||||
continue
|
||||
shutil.copyfile(source, toc_target / f"{edition}.json")
|
||||
|
||||
homework_template = self.env.get_template("html/homework.html")
|
||||
@@ -231,7 +220,7 @@ class Build:
|
||||
"assets/homework.js?ts=202608271",
|
||||
],
|
||||
)
|
||||
with (self.config.p_build / "hausaufgabe.html").open("w", encoding="utf-8") as file:
|
||||
with (self.config.p_build / f"{HOMEWORK}.html").open("w", encoding="utf-8") as file:
|
||||
file.write(page)
|
||||
|
||||
def __copy_picture(self, id):
|
||||
@@ -243,7 +232,7 @@ class Build:
|
||||
shutil.copyfile(description_source, self.config.p_build_pictures / description_source.name)
|
||||
return description_source.read_text(encoding="utf-8")
|
||||
else:
|
||||
return "Bildbeschreibung noch nicht verfügbar"
|
||||
return "Bildbeskrivning saknas ännu"
|
||||
except FileNotFoundError:
|
||||
tqdm.write(f"\033[31mPicture #{id} not found\033[0m")
|
||||
|
||||
@@ -259,7 +248,7 @@ class Build:
|
||||
if (self.config.p_data_photos / f"{id}.txt").exists():
|
||||
return (self.config.p_data_photos / f"{id}.txt").read_text(encoding="utf-8")
|
||||
else:
|
||||
return "Bildbeschreibung noch nicht verfügbar"
|
||||
return "Bildbeskrivning saknas ännu"
|
||||
except FileNotFoundError:
|
||||
tqdm.write(f"\033[31mPhoto #{id} not found\033[0m")
|
||||
|
||||
@@ -441,10 +430,11 @@ class Build:
|
||||
def build_edition(self, edition: str):
|
||||
self.config.p_build.mkdir(exist_ok=True)
|
||||
|
||||
edition = edition.upper()
|
||||
edition = str(edition).upper()
|
||||
toc_file = self.config.p_data_toc / f"{edition}.json"
|
||||
if not toc_file.exists():
|
||||
toc_file = self.config.p_data_toc / f"{edition.lower()}.json"
|
||||
tqdm.write(f"\033[31mtoc/{edition}.json not found, skipping edition {edition}\033[0m")
|
||||
return
|
||||
|
||||
with (
|
||||
toc_file.open(encoding="utf-8") as file,
|
||||
@@ -602,6 +592,8 @@ class Build:
|
||||
with (self.config.p_build / f"{page}.html").open("w", encoding="utf-8") as file:
|
||||
result = self.__build_page(content=content["content"], sidebar=content["sidebar"])
|
||||
file.write(result)
|
||||
return True
|
||||
return False
|
||||
|
||||
def build_website(self):
|
||||
self.config.p_build.mkdir(exist_ok=True)
|
||||
@@ -609,16 +601,17 @@ class Build:
|
||||
snippets = self.__parse_snippets()
|
||||
contents = self.__parse_contents()
|
||||
self.__build_index(snippets)
|
||||
self.__build_course_page(snippets, "kurse-karte", "kurse_vor_ort_karte")
|
||||
self.__build_course_page(snippets, "kurse-liste", "kurse_vor_ort_liste")
|
||||
self.__build_course_page(snippets, "patenkarte", "patenkarte")
|
||||
self.__build_html_page(contents, "pruefung")
|
||||
self.__build_html_page(contents, "infos")
|
||||
self.__build_html_page(contents, "suche")
|
||||
for page in PAGES:
|
||||
# Prefer the static page of the content repository, fall back to the generic template.
|
||||
if not self.__build_html_page(contents, page.name) and page.template is not None:
|
||||
self.__build_course_page(snippets, page.template, page.name)
|
||||
self.__build_exam_simulator()
|
||||
self.__build_homework_tool()
|
||||
|
||||
def build_solutions(self):
|
||||
if not self.has_question_pool:
|
||||
return
|
||||
|
||||
for solution_file in self.config.p_data_solutions.glob("*.md"):
|
||||
with solution_file.open(encoding="utf-8") as file:
|
||||
content = file.read()
|
||||
@@ -657,16 +650,6 @@ class Build:
|
||||
"editions": [],
|
||||
},
|
||||
)
|
||||
if edition != "SWL" and question_entry["editions"] == ["SWL"]:
|
||||
# SWL reuses questions from the regular courses, but can place
|
||||
# them in SWL-specific chapters. The question index exposes a
|
||||
# single canonical location, so prefer the first regular
|
||||
# course occurrence. Pure SWL questions keep their location.
|
||||
question_entry.update(
|
||||
section=section_ident,
|
||||
chapter_title=chapter_title,
|
||||
section_title=section_title,
|
||||
)
|
||||
if edition not in question_entry["editions"]:
|
||||
question_entry["editions"].append(edition)
|
||||
|
||||
@@ -709,6 +692,9 @@ class Build:
|
||||
index_entry["editions"].append(edition)
|
||||
|
||||
def build_question_index(self):
|
||||
if not self.has_question_pool:
|
||||
return
|
||||
|
||||
tqdm.write("Creating question index")
|
||||
for question_data in self.question_index.values():
|
||||
question_data["editions"] = sorted(question_data["editions"])
|
||||
|
||||
@@ -28,9 +28,10 @@ class Config:
|
||||
self.p_data_static = self.p_data_contents / "static"
|
||||
self.p_data_solutions = self.p_data_contents / "solutions"
|
||||
|
||||
self.p_data_fragenkatalog = self.p_data_questions / "fragenkatalog3b.json"
|
||||
self.p_data_fragenkatalog_swl = self.p_data_questions / "fragenkatalog_swl.json"
|
||||
self.p_data_metadata = self.p_data_questions / "metadata3b.json"
|
||||
# The question pool is optional. Without it there is no exam simulator,
|
||||
# homework tool or solution pages. The metadata file is optional as well.
|
||||
self.p_data_question_pool = self.p_data_questions / "question_pool.json"
|
||||
self.p_data_metadata = self.p_data_questions / "metadata.json"
|
||||
|
||||
self.p_build = Path(self.get_config_value("output", "./build") if build_path is None else build_path)
|
||||
self.p_build_photos = self.p_build / "photos"
|
||||
@@ -40,6 +41,10 @@ class Config:
|
||||
self.p_assets = Path("./assets")
|
||||
self.p_templates = Path("./templates")
|
||||
|
||||
@property
|
||||
def has_question_pool(self) -> bool:
|
||||
return self.p_data_question_pool.is_file()
|
||||
|
||||
def get_config_value(self, key: str, default=None):
|
||||
if key in self.config:
|
||||
return self.config[key]
|
||||
|
||||
@@ -2,10 +2,8 @@ from enum import StrEnum
|
||||
|
||||
|
||||
class Edition(StrEnum):
|
||||
swl = "SWL"
|
||||
n = "N"
|
||||
e = "E"
|
||||
a = "A"
|
||||
ne = "NE"
|
||||
ea = "EA"
|
||||
nea = "NEA"
|
||||
"""Available courses. The value is the name of the toc file (toc/<value>.json)."""
|
||||
|
||||
instegs = "INSTEG" # Instegscertifikat
|
||||
harec = "HAREC" # HAREC (full licence)
|
||||
uppgradering = "UPPGRADERING" # Upgrade: Instegscertifikat -> HAREC
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""Single source of truth for the page names (URL parts) of the website.
|
||||
|
||||
The names must match the files in the content repository:
|
||||
``contents/static/<name>.html`` (and optionally ``<name>_sidebar.html``).
|
||||
The jinja templates get the same names via the ``pages`` global.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Page:
|
||||
name: str
|
||||
# Template in templates/html/ used as fallback if the content repository
|
||||
# has no static page with this name.
|
||||
template: str | None = None
|
||||
|
||||
|
||||
# Pages whose body comes from contents/static/<name>.html.
|
||||
PAGES = (
|
||||
Page("prov"),
|
||||
Page("info"),
|
||||
Page("sok"),
|
||||
Page("kurser_karta", template="kurser-karta"),
|
||||
Page("kurser_lista", template="kurser-lista"),
|
||||
Page("mentorer", template="mentorer"),
|
||||
)
|
||||
|
||||
# Pages generated by the generator itself. The last two only exist if the
|
||||
# content repository contains a question pool.
|
||||
INDEX = "index"
|
||||
EXAM_SIMULATOR = "simulering"
|
||||
EXAM_RESULT = "resultat"
|
||||
HOMEWORK = "ovning"
|
||||
|
||||
|
||||
def page_urls() -> dict[str, str]:
|
||||
"""Maps page names to their html file name (for use in templates)."""
|
||||
urls = {page.name: f"{page.name}.html" for page in PAGES}
|
||||
urls.update(
|
||||
{
|
||||
INDEX: f"{INDEX}.html",
|
||||
EXAM_SIMULATOR: f"{EXAM_SIMULATOR}.html",
|
||||
HOMEWORK: f"{HOMEWORK}.html",
|
||||
}
|
||||
)
|
||||
return urls
|
||||
@@ -1,17 +1,18 @@
|
||||
<div style="float: right;" data-quiz-shown>
|
||||
<div class="btn-group" role="group">
|
||||
{% if chapter["video_url"] %}
|
||||
<a class="btn btn-secondary" href="{{ chapter["video_url"] }}" title="Video öffnen" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z"></path></svg></a>
|
||||
<a class="btn btn-secondary" href="{{ chapter["video_url"] }}" title="Öppna video" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z"></path></svg></a>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary" href="{{ edition }}_slide_{{ chapter["ident"] }}.html" title="Öppna presentation"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M840-120v-640H120v320H40v-320q0-33 23.5-56.5T120-840h720q33 0 56.5 23.5T920-760v560q0 33-23.5 56.5T840-120ZM360-400q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T440-560q0-33-23.5-56.5T360-640q-33 0-56.5 23.5T280-560q0 33 23.5 56.5T360-480ZM40-80v-112q0-34 17.5-62.5T104-298q62-31 126-46.5T360-360q66 0 130 15.5T616-298q29 15 46.5 43.5T680-192v112H40Zm80-80h480v-32q0-11-5.5-20T580-226q-54-27-109-40.5T360-280q-56 0-111 13.5T140-226q-9 5-14.5 14t-5.5 20v32Zm240-400Zm0 400Z"/></svg></a>
|
||||
{% if has_question_pool %}
|
||||
<button type="button" class="btn btn-secondary" id="quiz-mode-toggle" title="Visa endast frågor" aria-pressed="false"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 16 16" fill="#000000"><path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/><path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/><path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/></svg></button>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary" href="{{ edition }}_slide_{{ chapter["ident"] }}.html" title="Präsentationsfolien öffnen"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M840-120v-640H120v320H40v-320q0-33 23.5-56.5T120-840h720q33 0 56.5 23.5T920-760v560q0 33-23.5 56.5T840-120ZM360-400q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T440-560q0-33-23.5-56.5T360-640q-33 0-56.5 23.5T280-560q0 33 23.5 56.5T360-480ZM40-80v-112q0-34 17.5-62.5T104-298q62-31 126-46.5T360-360q66 0 130 15.5T616-298q29 15 46.5 43.5T680-192v112H40Zm80-80h480v-32q0-11-5.5-20T580-226q-54-27-109-40.5T360-280q-56 0-111 13.5T140-226q-9 5-14.5 14t-5.5 20v32Zm240-400Zm0 400Z"/></svg></a>
|
||||
<a class="btn btn-secondary" target="_blank" href="/hm" title="Hilfsmittel herunterladen"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 640 640" fill="#000000"><!--!Font Awesome Free v7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M192 112L304 112L304 200C304 239.8 336.2 272 376 272L464 272L464 512C464 520.8 456.8 528 448 528L192 528C183.2 528 176 520.8 176 512L176 128C176 119.2 183.2 112 192 112zM352 131.9L444.1 224L376 224C362.7 224 352 213.3 352 200L352 131.9zM192 64C156.7 64 128 92.7 128 128L128 512C128 547.3 156.7 576 192 576L448 576C483.3 576 512 547.3 512 512L512 250.5C512 233.5 505.3 217.2 493.3 205.2L370.7 82.7C358.7 70.7 342.5 64 325.5 64L192 64zM248 320C234.7 320 224 330.7 224 344C224 357.3 234.7 368 248 368L392 368C405.3 368 416 357.3 416 344C416 330.7 405.3 320 392 320L248 320zM248 416C234.7 416 224 426.7 224 440C224 453.3 234.7 464 248 464L392 464C405.3 464 416 453.3 416 440C416 426.7 405.3 416 392 416L248 416z"/></svg></a>
|
||||
<button type="button" class="btn btn-secondary" id="quiz-mode-toggle" title="Nur Fragen anzeigen" aria-pressed="false"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 16 16" fill="#000000"><path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/><path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/><path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav aria-label="breadcrumb" data-quiz-shown>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html">Hem</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ edition }}_course_index.html">{{ name }}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ chapter["title"] }}</li>
|
||||
</ol>
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
<div id="exam-simulator" class="exam-simulator" v-cloak>
|
||||
<div v-if="loading" class="d-flex align-items-center justify-content-center gap-3 py-5" role="status">
|
||||
<div class="spinner-border text-primary" aria-hidden="true"></div>
|
||||
<span>Prüfungsfragen werden geladen …</span>
|
||||
<span>Provfrågor laddas …</span>
|
||||
</div>
|
||||
|
||||
<div v-else-if="loadError" class="alert alert-danger" role="alert">
|
||||
<h1 class="h4">Die Prüfungssimulation konnte nicht geladen werden</h1>
|
||||
<h1 class="h4">Provsimuleringen kunde inte laddas</h1>
|
||||
<p class="mb-0" v-text="loadError"></p>
|
||||
</div>
|
||||
|
||||
<section v-else-if="view === 'shared' && sharedResult" class="mx-auto mb-5 exam-summary" aria-labelledby="shared-heading">
|
||||
<h1 id="shared-heading">Geteiltes Ergebnis</h1>
|
||||
<h1 id="shared-heading">Delat resultat</h1>
|
||||
<template v-if="sharedResult.kind === 'homework'">
|
||||
<p class="lead">Hausaufgabe auf 50ohm.de</p>
|
||||
<p class="lead">Övning på 50Ω</p>
|
||||
<div class="alert alert-primary">
|
||||
<strong><span v-text="sharedResult.score"></span> von <span v-text="sharedResult.total"></span> Fragen richtig beantwortet</strong>
|
||||
<strong><span v-text="sharedResult.score"></span> av <span v-text="sharedResult.total"></span> frågor rätt besvarade</strong>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="lead" v-text="sharedResult.choice.label"></p>
|
||||
<div class="alert" :class="sharedResult.passed ? 'alert-success' : 'alert-danger'">
|
||||
<strong v-text="sharedResult.passed ? 'Prüfung bestanden' : 'Prüfung nicht bestanden'"></strong>
|
||||
<strong v-text="sharedResult.passed ? 'Provet godkänt' : 'Provet inte godkänt'"></strong>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table align-middle">
|
||||
<thead><tr><th>Teil</th><th>Ergebnis</th><th>Status</th></tr></thead>
|
||||
<thead><tr><th>Del</th><th>Resultat</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(part, index) in sharedResult.choice.parts" :key="part">
|
||||
<td><b v-text="part + ' – ' + partDefinitions[part].label"></b></td>
|
||||
<td><b v-text="sharedResult.scores[index]"></b>/25</td>
|
||||
<td><span class="badge" :class="sharedResult.scores[index] >= 19 ? 'text-bg-success' : 'text-bg-danger'"
|
||||
v-text="sharedResult.scores[index] >= 19 ? 'Bestanden' : 'Nicht bestanden'"></span></td>
|
||||
v-text="sharedResult.scores[index] >= 19 ? 'Godkänd' : 'Inte godkänd'"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
<img v-if="resultImageUrl" class="img-fluid border mb-4" :src="resultImageUrl"
|
||||
alt="50ohm.de-Prüfungssimulation">
|
||||
alt="Provsimulering">
|
||||
<div v-if="resultForSharing" class="border-top pt-3 mt-3">
|
||||
<h2 class="h5">Ergebnis teilen</h2>
|
||||
<h2 class="h5">Dela resultatet</h2>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm d-inline-flex align-items-center" @click="shareNative">
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true">share</span> Teilen …
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true">share</span> Dela …
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="copyResultLink">Link kopieren</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="copyResultLink">Kopiera länk</button>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.mastodon" target="_blank" rel="noopener noreferrer">Mastodon</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.bluesky" target="_blank" rel="noopener noreferrer">Bluesky</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.facebook" target="_blank" rel="noopener noreferrer">Facebook</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.x" target="_blank" rel="noopener noreferrer">X (ehem. Twitter)</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.x" target="_blank" rel="noopener noreferrer">X (tidigare Twitter)</a>
|
||||
</div>
|
||||
<small v-if="shareMessage" class="d-block mt-2" role="status" v-text="shareMessage"></small>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary mt-4" @click="newExam">Eigene Simulation starten</button>
|
||||
<button type="button" class="btn btn-primary mt-4" @click="newExam">Starta en egen simulering</button>
|
||||
</section>
|
||||
|
||||
<section v-else-if="!session" class="mx-auto mb-5 exam-start" aria-labelledby="exam-heading">
|
||||
<h1 id="exam-heading">Prüfungssimulation <sup class="exam-beta fs-6">BETA</sup></h1>
|
||||
<p class="lead">Welche Prüfung möchtest du simulieren?</p>
|
||||
<h1 id="exam-heading">Provsimulering <sup class="exam-beta fs-6">BETA</sup></h1>
|
||||
<p class="lead">Vilket prov vill du simulera?</p>
|
||||
|
||||
<h2 class="h4 mt-5">Erstprüfung</h2>
|
||||
<p class="mb-2">Du hast noch keine Amateurfunkprüfung abgelegt? Dann ist das die richtige Simulation für Dich.</p>
|
||||
<h2 class="h4 mt-5">Första provet</h2>
|
||||
<p class="mb-2">Har du inte gjort något amatörradioprov än? Då är det här rätt simulering för dig.</p>
|
||||
<div class="row row-cols-1 row-cols-md-3 g-2">
|
||||
<div v-for="choice in primaryChoices" :key="choice.id" class="col">
|
||||
<button type="button" class="btn w-100 h-100 py-3 text-white"
|
||||
@@ -71,8 +71,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="h4 mt-4">Aufstockungsprüfung</h2>
|
||||
<p class="mb-2">Du hast bereits eine Zulassung zum Amateurfunkdienst und möchtest in eine höhere Klasse aufstocken? Dann wähle hier die passende Prüfung.</p>
|
||||
<h2 class="h4 mt-4">Uppgraderingsprov</h2>
|
||||
<p class="mb-2">Har du redan ett certifikat och vill uppgradera? Välj då lämpligt prov här.</p>
|
||||
<div class="row row-cols-1 row-cols-md-3 g-2">
|
||||
<div v-for="choice in upgradeChoices" :key="choice.id" class="col">
|
||||
<button type="button" class="btn w-100 h-100 py-3 text-white"
|
||||
@@ -83,8 +83,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="h4 mt-4">Einzelne Prüfungsteile</h2>
|
||||
<p class="mb-2">Übe gezielt einen Prüfungsteil unter Prüfungsbedingungen.</p>
|
||||
<h2 class="h4 mt-4">Enskilda provdelar</h2>
|
||||
<p class="mb-2">Öva på en enskild provdel under provliknande förhållanden.</p>
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-lg-5 g-2">
|
||||
<div v-for="choice in singlePartChoices" :key="choice.id" class="col">
|
||||
<button type="button" class="btn w-100 h-100 py-3 text-white"
|
||||
@@ -96,13 +96,13 @@
|
||||
</div>
|
||||
|
||||
<div class="alert alert-primary mt-4 mb-0">
|
||||
Jeder Prüfungsteil enthält 25 Fragen. Für B, V, N und E stehen jeweils 45 Minuten zur Verfügung,
|
||||
für Technik A 60 Minuten. Ein Teil ist ab 19 Punkten bestanden.
|
||||
Varje provdel innehåller 25 frågor. För delarna B, V, N och E finns 45 minuter vardera,
|
||||
för teknik A 60 minuter. En del är godkänd från 19 poäng.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else-if="view === 'summary'" class="mx-auto mb-5 exam-summary" aria-labelledby="summary-heading">
|
||||
<h1 id="summary-heading" v-text="isHomework ? 'Ergebnis der Hausaufgabe' : 'Gesamtergebnis'"></h1>
|
||||
<h1 id="summary-heading" v-text="isHomework ? 'Resultat av övningen' : 'Totalresultat'"></h1>
|
||||
<p class="lead" v-text="currentChoice.label"></p>
|
||||
<div class="alert d-flex align-items-center gap-2" :class="overallAlertClass">
|
||||
<span class="material-icons" aria-hidden="true" v-text="overallIcon"></span>
|
||||
@@ -110,63 +110,54 @@
|
||||
<strong v-text="overallTitle"></strong>
|
||||
<div v-text="overallText"></div>
|
||||
<p v-if="overallState === 'failed'" class="mt-2 mb-0">
|
||||
Hol dir Unterstützung bei erfahrenen Ausbilderinnen und Ausbildern – zum Beispiel im
|
||||
<a href="https://matrix.to/#/#ausbildung:darc.de" target="_blank" rel="noopener">DARC-Chat</a>, in unseren
|
||||
<a href="https://treff.darc.de/d/#/gastlink/jbogyos6" target="_blank" rel="noopener">Fragestunden auf treff.darc.de</a>
|
||||
oder bei einem Ortsverband in deiner Nähe. Alle Angebote findest du auf der
|
||||
<a href="index.html">Startseite von 50ohm.de</a>.
|
||||
Be om hjälp av erfarna kursledare, till exempel på en kurs eller hos en lokal klubb i din närhet.
|
||||
Alla möjligheter hittar du på <a href="index.html">startsidan</a>.
|
||||
</p>
|
||||
<template v-else-if="overallState === 'passed'">
|
||||
<p class="mt-2 mb-0">
|
||||
Du hast schon viel gelernt. Wenn du dich bereit fühlst, kannst du dich bei der Bundesnetzagentur zur
|
||||
Amateurfunkprüfung anmelden. Alle Informationen dazu findest du unter
|
||||
<a href="pruefung.html">Prüfung</a>.
|
||||
</p>
|
||||
<p class="mt-2 mb-0">
|
||||
Wenn dir 50ohm.de geholfen hat, kannst du unsere Arbeit unterstützen, indem du Mitglied im DARC wirst.
|
||||
Hier geht es zum
|
||||
<a href="https://antrag.darc.de/antrag/schritt-1" target="_blank" rel="noopener">digitalen Mitgliedsantrag</a>.
|
||||
Du har redan lärt dig mycket. När du känner dig redo kan du anmäla dig till provet.
|
||||
All information hittar du under <a href="prov.html">Prov</a>.
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table align-middle">
|
||||
<thead><tr><th>Teil</th><th>Ergebnis</th><th>Status</th><th></th></tr></thead>
|
||||
<thead><tr><th>Del</th><th>Resultat</th><th>Status</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(part, index) in session.parts" :key="part.code">
|
||||
<td><b v-text="part.code + ' – ' + partDefinitions[part.code].label"></b></td>
|
||||
<template v-if="part.status === 'evaluated'">
|
||||
<td><b v-text="part.score"></b>/<span v-text="part.questions.length"></span></td>
|
||||
<td><span class="badge" :class="resultBadgeClass(part)" v-text="resultLabel(part)"></span></td>
|
||||
<td><button type="button" class="btn btn-outline-dark btn-sm" @click="reviewPart(index)">Auswertung</button></td>
|
||||
<td><button type="button" class="btn btn-outline-dark btn-sm" @click="reviewPart(index)">Genomgång</button></td>
|
||||
</template>
|
||||
<template v-else>
|
||||
<td colspan="3" class="text-secondary">Nicht bearbeitet</td>
|
||||
<td colspan="3" class="text-secondary">Inte besvarad</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<img v-if="resultImageUrl" class="img-fluid border mb-4" :src="resultImageUrl"
|
||||
alt="50ohm.de-Prüfungssimulation">
|
||||
alt="Provsimulering">
|
||||
<div v-if="resultForSharing" class="border-top pt-3 mt-3">
|
||||
<h2 class="h5">Ergebnis teilen</h2>
|
||||
<h2 class="h5">Dela resultatet</h2>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm d-inline-flex align-items-center" @click="shareNative">
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true">share</span> Teilen …
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true">share</span> Dela …
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="copyResultLink">Link kopieren</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="copyResultLink">Kopiera länk</button>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.mastodon" target="_blank" rel="noopener noreferrer">Mastodon</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.bluesky" target="_blank" rel="noopener noreferrer">Bluesky</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.facebook" target="_blank" rel="noopener noreferrer">Facebook</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.x" target="_blank" rel="noopener noreferrer">X (ehem. Twitter)</a>
|
||||
<a class="btn btn-outline-secondary btn-sm" :href="socialShareLinks.x" target="_blank" rel="noopener noreferrer">X (tidigare Twitter)</a>
|
||||
</div>
|
||||
<small v-if="shareMessage" class="d-block mt-2" role="status" v-text="shareMessage"></small>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 mt-4">
|
||||
<button v-if="isHomework" type="button" class="btn btn-primary" @click="retryHomework">Hausaufgabe wiederholen</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="newExam">Neue Simulation</button>
|
||||
<button v-if="isHomework" type="button" class="btn btn-primary" @click="retryHomework">Gör övningen igen</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="newExam">Ny simulering</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -174,35 +165,29 @@
|
||||
<header class="exam-toolbar bg-white border-bottom py-2 mb-3">
|
||||
<div>
|
||||
<small class="text-secondary"
|
||||
v-text="isHomework ? currentQuestionCount + ' ausgewählte Fragen' : currentChoice.label + ' · Teil ' + (displayedPartIndex + 1) + ' von ' + session.parts.length"></small>
|
||||
v-text="isHomework ? currentQuestionCount + ' valda frågor' : currentChoice.label + ' · Del ' + (displayedPartIndex + 1) + ' av ' + session.parts.length"></small>
|
||||
<h1 id="part-heading" class="h4 mb-0" v-text="currentPartDefinition.label"></h1>
|
||||
</div>
|
||||
<div class="d-flex align-items-center flex-wrap gap-2">
|
||||
<a class="btn btn-secondary btn-sm d-inline-flex align-items-center" target="_blank" href="/hm"
|
||||
title="Hilfsmittel herunterladen" aria-label="Hilfsmittel herunterladen">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 640 640" fill="currentColor" aria-hidden="true">
|
||||
<path d="M192 112L304 112L304 200C304 239.8 336.2 272 376 272L464 272L464 512C464 520.8 456.8 528 448 528L192 528C183.2 528 176 520.8 176 512L176 128C176 119.2 183.2 112 192 112zM352 131.9L444.1 224L376 224C362.7 224 352 213.3 352 200L352 131.9zM192 64C156.7 64 128 92.7 128 128L128 512C128 547.3 156.7 576 192 576L448 576C483.3 576 512 547.3 512 512L512 250.5C512 233.5 505.3 217.2 493.3 205.2L370.7 82.7C358.7 70.7 342.5 64 325.5 64L192 64zM248 320C234.7 320 224 330.7 224 344C224 357.3 234.7 368 248 368L392 368C405.3 368 416 357.3 416 344C416 330.7 405.3 320 392 320L248 320zM248 416C234.7 416 224 426.7 224 440C224 453.3 234.7 464 248 464L392 464C405.3 464 416 453.3 416 440C416 426.7 405.3 416 392 416L248 416z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<button v-if="currentPart.status === 'running' && !isHomework" type="button"
|
||||
class="btn btn-sm d-inline-flex align-items-center"
|
||||
:class="currentPart.paused ? 'btn-warning' : (remainingSeconds <= 300 ? 'btn-danger' : 'btn-secondary')"
|
||||
@click="toggleTimer"
|
||||
:title="currentPart.paused ? 'Timer fortsetzen' : 'Timer pausieren'"
|
||||
:aria-label="(currentPart.paused ? 'Timer fortsetzen, verbleibende Zeit ' : 'Timer pausieren, verbleibende Zeit ') + formattedTime">
|
||||
:title="currentPart.paused ? 'Fortsätt timern' : 'Pausa timern'"
|
||||
:aria-label="(currentPart.paused ? 'Fortsätt timern, återstående tid ' : 'Pausa timern, återstående tid ') + formattedTime">
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true"
|
||||
v-text="currentPart.paused ? 'play_arrow' : 'pause'"></span>
|
||||
<span role="timer" v-text="formattedTime"></span>
|
||||
</button>
|
||||
<span v-else-if="currentPart.status !== 'running'" class="btn btn-secondary btn-sm d-inline-flex align-items-center">Abgegeben</span>
|
||||
<span v-else-if="currentPart.status !== 'running'" class="btn btn-secondary btn-sm d-inline-flex align-items-center">Inlämnad</span>
|
||||
<button v-if="currentPart.status === 'evaluated' && !isReviewing && hasNextPart"
|
||||
type="button" class="btn btn-primary btn-sm" @click="startNextPart">Nächsten Teil starten</button>
|
||||
type="button" class="btn btn-primary btn-sm" @click="startNextPart">Starta nästa del</button>
|
||||
<a v-else-if="currentPart.status === 'evaluated' && !isReviewing"
|
||||
class="btn btn-primary btn-sm" :href="completedResultUrl"
|
||||
v-text="isHomework ? 'Ergebnis' : 'Gesamtergebnis'"></a>
|
||||
<button v-else-if="isReviewing" type="button" class="btn btn-primary btn-sm" @click="showSummary">Gesamtergebnis</button>
|
||||
v-text="isHomework ? 'Resultat' : 'Totalresultat'"></a>
|
||||
<button v-else-if="isReviewing" type="button" class="btn btn-primary btn-sm" @click="showSummary">Totalresultat</button>
|
||||
<button type="button" class="btn btn-secondary btn-sm d-inline-flex align-items-center" @click="abortExam"
|
||||
v-text="isHomework ? 'Hausaufgabe abbrechen' : 'Simulation abbrechen'"></button>
|
||||
v-text="isHomework ? 'Avbryt övningen' : 'Avbryt simuleringen'"></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -210,7 +195,7 @@
|
||||
:class="resultAlertClass(currentPart)">
|
||||
<span class="material-icons" aria-hidden="true" v-text="resultIcon(currentPart)"></span>
|
||||
<div>
|
||||
<strong><span v-text="currentPart.score"></span> von <span v-text="currentQuestionCount"></span> Punkten – <span v-text="resultLabel(currentPart)"></span></strong>
|
||||
<strong><span v-text="currentPart.score"></span> av <span v-text="currentQuestionCount"></span> poäng – <span v-text="resultLabel(currentPart)"></span></strong>
|
||||
<div v-text="resultDescription(currentPart)"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -226,7 +211,7 @@
|
||||
</div>
|
||||
<div v-if="questionData(questionState).picture" class="question-picture">
|
||||
<img :src="'pictures/' + questionData(questionState).picture + '.svg'"
|
||||
:alt="pictureAlt(questionData(questionState).picture, 'Abbildung zu Frage ' + questionState.id)">
|
||||
:alt="pictureAlt(questionData(questionState).picture, 'Bild till fråga ' + questionState.id)">
|
||||
</div>
|
||||
<div class="answers">
|
||||
<button v-for="(sourceIndex, answerIndex) in questionState.order" :key="answerIndex" type="button"
|
||||
@@ -238,7 +223,7 @@
|
||||
<span v-if="questionData(questionState).answers[sourceIndex].picture" class="question-picture">
|
||||
<img :src="'pictures/' + questionData(questionState).answers[sourceIndex].picture + '.svg'"
|
||||
:alt="pictureAlt(questionData(questionState).answers[sourceIndex].picture,
|
||||
'Abbildung zu Antwort ' + answerLabels[answerIndex] + ' bei Frage ' + questionState.id)">
|
||||
'Bild till svar ' + answerLabels[answerIndex] + ' på fråga ' + questionState.id)">
|
||||
</span>
|
||||
<span v-if="currentPart.status === 'evaluated' && sourceIndex === 0" class="result material-icons">check</span>
|
||||
<span v-else-if="currentPart.status === 'evaluated' && questionState.selected === answerIndex" class="result material-icons">clear</span>
|
||||
@@ -247,59 +232,59 @@
|
||||
</article>
|
||||
<div v-if="currentPart.status === 'evaluated' && questionData(questionState).hasSolution" class="solution">
|
||||
<a class="btn btn-warning btn-sm d-inline-flex align-items-center" :href="questionState.id + '.html'" target="_blank"
|
||||
:aria-label="'Lösungshinweis zu Frage ' + questionState.id">
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true">lightbulb</span> Lösungsweg anzeigen
|
||||
:aria-label="'Lösningstips till fråga ' + questionState.id">
|
||||
<span class="material-icons fs-6 me-1" aria-hidden="true">lightbulb</span> Visa lösningsvägen
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="border-top pt-3 mb-5 d-flex flex-wrap gap-2 align-items-center justify-content-end">
|
||||
<template v-if="currentPart.status === 'running'">
|
||||
<span class="me-auto"><b v-text="answeredCount"></b> von <span v-text="currentQuestionCount"></span> Fragen beantwortet.</span>
|
||||
<button type="button" class="btn btn-primary" @click="requestSubmit" v-text="isHomework ? 'Hausaufgabe abgeben' : 'Prüfungsteil abgeben'"></button>
|
||||
<span class="me-auto"><b v-text="answeredCount"></b> av <span v-text="currentQuestionCount"></span> frågor besvarade.</span>
|
||||
<button type="button" class="btn btn-primary" @click="requestSubmit" v-text="isHomework ? 'Lämna in övningen' : 'Lämna in provdelen'"></button>
|
||||
</template>
|
||||
<template v-else-if="isReviewing">
|
||||
<button type="button" class="btn btn-primary" @click="showSummary">Zurück zum Gesamtergebnis</button>
|
||||
<button type="button" class="btn btn-primary" @click="showSummary">Tillbaka till totalresultatet</button>
|
||||
</template>
|
||||
<template v-else-if="hasNextPart">
|
||||
<button type="button" class="btn btn-primary" @click="startNextPart">Nächsten Prüfungsteil starten</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="finishExamEarly">Simulation hier beenden</button>
|
||||
<button type="button" class="btn btn-primary" @click="startNextPart">Starta nästa provdel</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="finishExamEarly">Avsluta simuleringen här</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a class="btn btn-primary" :href="completedResultUrl"
|
||||
v-text="isHomework ? 'Ergebnis anzeigen' : 'Gesamtergebnis anzeigen'"></a>
|
||||
v-text="isHomework ? 'Visa resultatet' : 'Visa totalresultatet'"></a>
|
||||
</template>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<aside class="exam-answer-sheet" :class="{ 'exam-answer-sheet-homework': isHomework }" aria-label="Antwortbogen">
|
||||
<aside class="exam-answer-sheet" :class="{ 'exam-answer-sheet-homework': isHomework }" aria-label="Svarsblad">
|
||||
<div class="border border-dark bg-white p-2">
|
||||
<h2 class="h5 text-center">Antwortbogen</h2>
|
||||
<h2 class="h5 text-center">Svarsblad</h2>
|
||||
<div class="border-top border-bottom border-dark py-1 mb-2">
|
||||
<strong class="d-block" v-text="currentPartDefinition.label"></strong>
|
||||
<small v-if="isHomework"><span v-text="currentQuestionCount"></span> Fragen · ohne Zeitlimit</small>
|
||||
<small v-else><span v-text="currentPartDefinition.minutes"></span> Minuten · 25 Fragen</small>
|
||||
<small v-if="isHomework"><span v-text="currentQuestionCount"></span> frågor · utan tidsgräns</small>
|
||||
<small v-else><span v-text="currentPartDefinition.minutes"></span> minuter · 25 frågor</small>
|
||||
</div>
|
||||
<table class="answer-table">
|
||||
<thead><tr><th>Nr.</th><th v-for="label in answerLabels" :key="label" v-text="label"></th></tr></thead>
|
||||
<thead><tr><th>Nr</th><th v-for="label in answerLabels" :key="label" v-text="label"></th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(question, questionIndex) in currentPart.questions" :key="question.id">
|
||||
<th scope="row">
|
||||
<button type="button" class="answer-number" @click="scrollToQuestion(questionIndex)"
|
||||
:aria-label="'Zu Frage ' + displayQuestionNumber(question, questionIndex)" v-text="displayQuestionNumber(question, questionIndex)"></button>
|
||||
:aria-label="'Till fråga ' + displayQuestionNumber(question, questionIndex)" v-text="displayQuestionNumber(question, questionIndex)"></button>
|
||||
</th>
|
||||
<td v-for="(_, answerIndex) in answerLabels" :key="answerIndex"
|
||||
:class="answerCellClass(questionIndex, answerIndex)">
|
||||
<button type="button" class="answer-mark"
|
||||
:disabled="currentPart.status !== 'running' || currentPart.paused"
|
||||
@click="selectAnswer(questionIndex, answerIndex)"
|
||||
:aria-label="'Frage ' + displayQuestionNumber(question, questionIndex) + ', Antwort ' + answerLabels[answerIndex]"
|
||||
:aria-label="'Fråga ' + displayQuestionNumber(question, questionIndex) + ', svar ' + answerLabels[answerIndex]"
|
||||
v-html="answerMark(questionIndex, answerIndex)"></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<small class="d-block text-end mt-1"><b v-text="answeredCount"></b> von <span v-text="currentQuestionCount"></span> beantwortet</small>
|
||||
<small class="d-block text-end mt-1"><b v-text="answeredCount"></b> av <span v-text="currentQuestionCount"></span> besvarade</small>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<div id="homework-generator" class="homework-generator mx-auto mb-5" v-cloak>
|
||||
<div v-if="loading" class="d-flex align-items-center justify-content-center gap-3 py-5" role="status">
|
||||
<div class="spinner-border text-primary" aria-hidden="true"></div>
|
||||
<span>Kursdaten werden geladen …</span>
|
||||
<span>Kursdata laddas …</span>
|
||||
</div>
|
||||
|
||||
<div v-else-if="loadError" class="alert alert-danger" role="alert">
|
||||
<h1 class="h4">Das Hausaufgabentool konnte nicht geladen werden</h1>
|
||||
<h1 class="h4">Övningsverktyget kunde inte laddas</h1>
|
||||
<p class="mb-0" v-text="loadError"></p>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<h1>Hausaufgabe erstellen</h1>
|
||||
<p class="lead">Stelle aus den behandelten Kapiteln und Sektionen eine Hausaufgabe zusammen.</p>
|
||||
<h1>Skapa en övning</h1>
|
||||
<p class="lead">Sätt ihop en övning av de kapitel och avsnitt som har gåtts igenom.</p>
|
||||
|
||||
<ol class="homework-steps list-unstyled d-flex flex-wrap gap-2 mb-4" aria-label="Arbeitsschritte">
|
||||
<ol class="homework-steps list-unstyled d-flex flex-wrap gap-2 mb-4" aria-label="Steg">
|
||||
<li v-for="item in stepLabels" :key="item.number"
|
||||
class="badge rounded-pill"
|
||||
:class="step === item.number ? 'text-bg-primary' : (step > item.number ? 'text-bg-secondary' : 'bg-light text-dark border')"
|
||||
@@ -21,8 +21,8 @@
|
||||
</ol>
|
||||
|
||||
<section v-if="step === 1" aria-labelledby="homework-course-heading">
|
||||
<h2 id="homework-course-heading" class="h4">Kurs auswählen</h2>
|
||||
<p>Welchen Kurs bietest du an?</p>
|
||||
<h2 id="homework-course-heading" class="h4">Välj kurs</h2>
|
||||
<p>Vilken kurs håller du?</p>
|
||||
<div class="row row-cols-1 row-cols-md-3 g-2">
|
||||
<div v-for="course in courseChoices" :key="course.edition" class="col">
|
||||
<button type="button" class="btn w-100 h-100 py-3 text-white"
|
||||
@@ -36,8 +36,8 @@
|
||||
</section>
|
||||
|
||||
<section v-else-if="step === 2" aria-labelledby="homework-chapter-heading">
|
||||
<h2 id="homework-chapter-heading" class="h4">Kapitel auswählen</h2>
|
||||
<p><strong v-text="selectedCourse.label"></strong>: Wähle ein oder mehrere behandelte Kapitel aus.</p>
|
||||
<h2 id="homework-chapter-heading" class="h4">Välj kapitel</h2>
|
||||
<p><strong v-text="selectedCourse.label"></strong>: Välj ett eller flera kapitel som har gåtts igenom.</p>
|
||||
<div class="list-group mb-3">
|
||||
<label v-for="chapter in toc.chapters" :key="chapter.ident"
|
||||
class="list-group-item d-flex align-items-start gap-2"
|
||||
@@ -47,21 +47,21 @@
|
||||
<span class="flex-grow-1">
|
||||
<span class="d-block" v-text="chapter.title"></span>
|
||||
<small v-if="chapterQuestionCount(chapter) > 0" class="text-secondary"
|
||||
v-text="chapterQuestionCount(chapter) + ' Prüfungsfragen'"></small>
|
||||
<small v-else>Keine Prüfungsfragen vorhanden</small>
|
||||
v-text="chapterQuestionCount(chapter) + ' provfrågor'"></small>
|
||||
<small v-else>Inga provfrågor finns</small>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between gap-2">
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(1)">Zurück</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(1)">Tillbaka</button>
|
||||
<button type="button" class="btn btn-primary" :disabled="selectedChapterIds.length === 0"
|
||||
@click="openSectionSelection">Weiter zu den Sektionen</button>
|
||||
@click="openSectionSelection">Vidare till avsnitten</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else-if="step === 3" aria-labelledby="homework-section-heading">
|
||||
<h2 id="homework-section-heading" class="h4">Sektionen auswählen</h2>
|
||||
<p>Wähle die Sektionen aus, die bereits behandelt wurden.</p>
|
||||
<h2 id="homework-section-heading" class="h4">Välj avsnitt</h2>
|
||||
<p>Välj de avsnitt som redan har gåtts igenom.</p>
|
||||
<div v-for="chapter in selectedChapters" :key="chapter.ident" class="mb-4">
|
||||
<h3 class="h5" v-text="chapter.title"></h3>
|
||||
<div class="list-group">
|
||||
@@ -73,26 +73,26 @@
|
||||
<span class="flex-grow-1">
|
||||
<span class="d-block" v-text="section.title"></span>
|
||||
<small v-if="sectionQuestionIds(section).length > 0" class="text-secondary"
|
||||
v-text="sectionQuestionIds(section).length + ' Prüfungsfragen'"></small>
|
||||
<small v-else>Keine Prüfungsfragen vorhanden</small>
|
||||
v-text="sectionQuestionIds(section).length + ' provfrågor'"></small>
|
||||
<small v-else>Inga provfrågor finns</small>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between gap-2">
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(2)">Zurück</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(2)">Tillbaka</button>
|
||||
<button type="button" class="btn btn-primary" :disabled="selectedSectionIds.length === 0"
|
||||
@click="openQuestionSelection">Weiter zu den Fragen</button>
|
||||
@click="openQuestionSelection">Vidare till frågorna</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else-if="step === 4" aria-labelledby="homework-question-heading">
|
||||
<h2 id="homework-question-heading" class="h4">Fragen auswählen</h2>
|
||||
<p>Alle Fragen der gewählten Sektionen sind vorausgewählt. Nicht benötigte Fragen kannst du abwählen.</p>
|
||||
<h2 id="homework-question-heading" class="h4">Välj frågor</h2>
|
||||
<p>Alla frågor i de valda avsnitten är förvalda. Frågor du inte behöver kan du välja bort.</p>
|
||||
<div class="d-flex flex-wrap gap-2 mb-3">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="setAllQuestions(true)">Alle auswählen</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="setAllQuestions(false)">Alle abwählen</button>
|
||||
<span class="ms-auto"><strong v-text="selectedQuestionIds.length"></strong> von <span v-text="orderedQuestions.length"></span> ausgewählt</span>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="setAllQuestions(true)">Markera alla</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="setAllQuestions(false)">Avmarkera alla</button>
|
||||
<span class="ms-auto"><strong v-text="selectedQuestionIds.length"></strong> av <span v-text="orderedQuestions.length"></span> valda</span>
|
||||
</div>
|
||||
|
||||
<div class="course">
|
||||
@@ -109,24 +109,24 @@
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between gap-2">
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(3)">Zurück</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(3)">Tillbaka</button>
|
||||
<button type="button" class="btn btn-primary" :disabled="selectedQuestionIds.length === 0"
|
||||
@click="generateLink">Hausaufgabenlink erzeugen</button>
|
||||
@click="generateLink">Skapa övningslänk</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else aria-labelledby="homework-link-heading">
|
||||
<h2 id="homework-link-heading" class="h4">Hausaufgabe ist bereit</h2>
|
||||
<p>Der Link enthält <strong v-text="selectedQuestionIds.length"></strong> Fragen in der Reihenfolge des Kurses.</p>
|
||||
<label for="homework-link" class="form-label">Hausaufgabenlink</label>
|
||||
<h2 id="homework-link-heading" class="h4">Övningen är klar</h2>
|
||||
<p>Länken innehåller <strong v-text="selectedQuestionIds.length"></strong> frågor i kursens ordning.</p>
|
||||
<label for="homework-link" class="form-label">Övningslänk</label>
|
||||
<div class="input-group mb-3">
|
||||
<input id="homework-link" class="form-control" type="text" readonly :value="generatedUrl" @focus="$event.target.select()">
|
||||
<button type="button" class="btn btn-outline-secondary" @click="copyLink">Link kopieren</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="copyLink">Kopiera länk</button>
|
||||
</div>
|
||||
<div v-if="copyMessage" class="alert alert-success py-2" role="status" v-text="copyMessage"></div>
|
||||
<div class="d-flex flex-wrap justify-content-between gap-2">
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(4)">Fragen ändern</button>
|
||||
<a class="btn btn-primary" :href="generatedUrl" target="_blank" rel="noopener">Hausaufgabe öffnen</a>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="goToStep(4)">Ändra frågor</button>
|
||||
<a class="btn btn-primary" :href="generatedUrl" target="_blank" rel="noopener">Öppna övningen</a>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
{{ snippets.index_teaser }}
|
||||
</p>
|
||||
<div class="d-grid gap-3 d-md-block my-5">
|
||||
<a href="#lernen" class="btn btn-primary btn-lg">{{ snippets.index_btn_start }}</a>
|
||||
<a href="infos.html" class="btn btn-outline-secondary btn-lg">{{ snippets.index_btn_was_ist_afu }}</a>
|
||||
<a href="#lara" class="btn btn-primary btn-lg">{{ snippets.index_btn_start }}</a>
|
||||
<a href="{{ pages.info }}" class="btn btn-outline-secondary btn-lg">{{ snippets.index_btn_vad_ar_amatorradio }}</a>
|
||||
</div>
|
||||
<p>
|
||||
<div class="alert alert-primary" role="alert">
|
||||
@@ -18,37 +18,37 @@
|
||||
<div id="carouselExampleControls" class="carousel slide" data-bs-ride="carousel">
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img src="assets/images/hero/hero06.jpg" class="d-block w-100" alt="...">
|
||||
<img src="assets/images/hero/hero06.jpg" class="d-block w-100" alt="">
|
||||
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
|
||||
<p class="p-2 m-0 text-end">Foto: DK5WP df0alz.de</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="assets/images/hero/hero02.jpg" class="d-block w-100" alt="...">
|
||||
<img src="assets/images/hero/hero02.jpg" class="d-block w-100" alt="">
|
||||
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
|
||||
<p class="p-2 m-0 text-end">Foto: DK5WP df0alz.de</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="assets/images/hero/hero03.jpg" class="d-block w-100" alt="...">
|
||||
<img src="assets/images/hero/hero03.jpg" class="d-block w-100" alt="">
|
||||
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
|
||||
<p class="p-2 m-0 text-end">Foto: DK4HAA draussenfunker.de</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="assets/images/hero/hero01.jpg" class="d-block w-100" alt="...">
|
||||
<img src="assets/images/hero/hero01.jpg" class="d-block w-100" alt="">
|
||||
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
|
||||
<p class="p-2 m-0 text-end">Foto: DB8KN bei DL0JMU</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="assets/images/hero/hero04.jpg" class="d-block w-100" alt="...">
|
||||
<img src="assets/images/hero/hero04.jpg" class="d-block w-100" alt="">
|
||||
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
|
||||
<p class="p-2 m-0 text-end">Foto: DK4HAA draussenfunker.de</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="assets/images/hero/hero05.jpg" class="d-block w-100" alt="...">
|
||||
<img src="assets/images/hero/hero05.jpg" class="d-block w-100" alt="">
|
||||
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
|
||||
<p class="p-2 m-0 text-end">Foto: DO3OI</p>
|
||||
</div>
|
||||
@@ -56,17 +56,17 @@
|
||||
</div>
|
||||
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleControls" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Previous</span>
|
||||
<span class="visually-hidden">Föregående</span>
|
||||
</button>
|
||||
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleControls" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Next</span>
|
||||
<span class="visually-hidden">Nästa</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a name="lernen"></a>
|
||||
<a name="lara"></a>
|
||||
|
||||
<div class="row g-5 pt-5 mt-2 mx-0 row-cols-1">
|
||||
<div class="col col-lg-4">
|
||||
@@ -74,121 +74,61 @@
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-60q-72-68-165-104t-195-36v-440q101 0 194 36.5T480-498q73-69 166-105.5T840-640v440q-103 0-195.5 36T480-60Zm0-104q63-47 134-75t146-37v-276q-73 13-143.5 52.5T480-394q-66-66-136.5-105.5T200-552v276q75 9 146 37t134 75Zm0-436q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T560-760q0-33-23.5-56.5T480-840q-33 0-56.5 23.5T400-760q0 33 23.5 56.5T480-680Zm0-80Zm0 366Z"/></svg>
|
||||
</div>
|
||||
<h2>Online lernen</h2>
|
||||
<p>Bringe dir das nötige Wissen für die Amateurfunkprüfung einfach selber bei. Unser Lernmaterial hilft dir auf deinem Weg! Es gibt die drei <a href="infos.html">Klassen N, E und A</a>, die aufeinander aufbauen.</p>
|
||||
<h5>Gesamtkurse</h5>
|
||||
<p>Diese Kurse richten sich an alle, die noch kein Amateurfunkzeugnis haben.</p>
|
||||
<div class="row row-cols-lg-3 g-2">
|
||||
<div class="col"><a href="N_course_index.html" class="btn w-100 text-white" style="background-color: #47ABE8; border-color: #47ABE8;">N<br><small>Neueinsteiger</small></a></div>
|
||||
<div class="col"><a href="NE_course_index.html" class="btn w-100 text-white" style="background-color: #FE756C; border-color: #FE756C;">N + E<br><small>Erweitert</small></a></div>
|
||||
<div class="col"><a href="NEA_course_index.html" class="btn w-100 text-white" style="background-color: #3BB583; border-color: #3BB583;">N + E + A<br><small>Alles</small></a></div>
|
||||
</div>
|
||||
<br>
|
||||
<h5>Aufbaukurse</h5>
|
||||
<p>Für alle, die schon über ein Amateurfunkzeugnis der Klasse N oder E verfügen, gibt es folgende Aufbaukurse:</p>
|
||||
<div class="row row-cols-lg-3 g-2">
|
||||
<div class="col"><a href="E_course_index.html" class="btn w-100 text-white" style="background-color: #FE756C; border-color: #FE756C;">N -> E</a></div>
|
||||
<div class="col"><a href="EA_course_index.html" class="btn w-100 text-white" style="background-color: #3BB583; border-color: #3BB583;">N -> A</a></div>
|
||||
<div class="col"><a href="A_course_index.html" class="btn w-100 text-white" style="background-color: #3BB583; border-color: #3BB583;">E -> A</a></div>
|
||||
</div>
|
||||
<br>
|
||||
<h5>Kurs für die DARC-SWL-Prüfung</h5>
|
||||
<p>Du möchtest erst einmal im Amateurfunk zuhören? Als DARC-Mitglied kannst du nach der DE-Prüfung ein persönliches DE-Kennzeichen erhalten und SWL-QSL-Karten über die DARC-QSL-Vermittlung versenden.</p>
|
||||
<h2>{{ snippets.lernen_selbst_title or "Lär dig online" }}</h2>
|
||||
<p>{{ snippets.lernen_selbst_teaser or "Lär dig det som krävs för proven på egen hand. Vårt kursmaterial hjälper dig på vägen." }}</p>
|
||||
<div class="row row-cols-lg-1 g-2">
|
||||
<div class="col"><a href="SWL_course_index.html" class="btn btn-outline-dark w-100">SWL<br><small>Kurzwellenhören</small></a></div>
|
||||
</div>
|
||||
<br>
|
||||
<h5>Fragestunden</h5>
|
||||
<p>Tauchen beim Selbststudium Fragen auf? Unsere ehrenamtlichen Helfer bieten für DARC-Mitglieder und Gäste eine Fragestunde Mittwochs um 19:00 Uhr und Sonntags um 18:00 Uhr auf dem DARC-Videokonferenzserver an.</p>
|
||||
<div class="row row-cols-lg-2">
|
||||
<div class="col"><a href="https://treff.darc.de/d/#/teilnehmer/964LmqHw" class="btn btn-outline-dark w-100">Mitglieder</a></div>
|
||||
<div class="col"><a href="https://treff.darc.de/d/#/gastlink/jbogyos6" class="btn btn-outline-dark w-100">Gäste</a></div>
|
||||
</div>
|
||||
<br>
|
||||
<h5>DARC Chat</h5>
|
||||
<p>Der DARC e. V. betreibt eine eigene Matrix-Instanz. Dort gibt es einen Raum, in dem du deine Fragen stellen kannst:</p>
|
||||
<div class="row row-cols-lg-1">
|
||||
<div class="col"><a href="https://matrix.to/#/#ausbildung:darc.de" class="btn btn-outline-dark w-100">💬 Ausbildung</a></div>
|
||||
</div>
|
||||
<br>
|
||||
<h5>Mitglied werden</h5>
|
||||
<p>Der <a href="https://darc.de">DARC e. V.</a> unterstützt Dich auf deinem Weg zum Amateurfunkzeugnis und ist die größte Interessensvertretung der Funkamateure in Deutschland.</p>
|
||||
<div class="row row-cols-lg-2">
|
||||
<div class="col"><a href="https://antrag.darc.de/?typ=voll" class="btn btn-outline-dark w-100" target="_blank">Mitglied werden</a></div>
|
||||
<div class="col"><a href="https://antrag.darc.de/?typ=gast" class="btn btn-outline-dark w-100" target="_blank">Gastmitgliedschaft</a></div>
|
||||
<div class="col"><a href="INSTEG_course_index.html" class="btn w-100 text-white" style="background-color: #47ABE8; border-color: #47ABE8;">{{ snippets.lernen_selbst_btn_instegs or "Instegscertifikat" }}</a></div>
|
||||
<div class="col"><a href="HAREC_course_index.html" class="btn w-100 text-white" style="background-color: #FE756C; border-color: #FE756C;">{{ snippets.lernen_selbst_btn_harec or "HAREC" }}</a></div>
|
||||
<div class="col"><a href="UPPGRADERING_course_index.html" class="btn w-100 text-white" style="background-color: #3BB583; border-color: #3BB583;">{{ snippets.lernen_selbst_btn_uppgradering or "Uppgradering: Instegscertifikat → HAREC" }}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-lg-8">
|
||||
<div class="row g-5 pb-5 row-cols-1 row-cols-lg-2">
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48" fill="#5f6368"><path d="m380-300 280-180-280-180v360ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z"/></svg>
|
||||
</div>
|
||||
<h2>Videokurse</h2>
|
||||
<p>In Zusammenarbeit mit DL2YMR ist ein Videokurs für die Klasse N entstanden, der auf seinem YouTube-Kanal abrufbar ist. Weiterhin gibt es noch Vorlesungen für N+E sowie A. </p>
|
||||
<div class="row row-cols-lg-3 g-2">
|
||||
<div class="col"><a href="https://www.youtube.com/playlist?list=PLDpWnjHk5ERbcgpLPUaU0iTsD-wrmfENk" class="btn btn-outline-dark w-100">Videokurs<br><small>Klasse N</small></a></div>
|
||||
<div class="col"><a href="https://www.youtube.com/playlist?list=PL_JZo16Mzs5XGeN5N81MwQ70dp7478VkM" class="btn btn-outline-dark w-100">Vorlesung<br><small>Klasse N+E</small></a></div>
|
||||
<div class="col"><a href="https://www.youtube.com/playlist?list=PL_JZo16Mzs5XebdJhoIDLNp1MObBy7F5d" class="btn btn-outline-dark w-100">Vorlesung<br><small>Klasse A</small></a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature col">
|
||||
<img style="float: right; width: 33%;" src="assets/images/darc-amateurfunklehrgang-klasse-n.jpg">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 448 512" width="48"><path d="M96 0C43 0 0 43 0 96L0 416c0 53 43 96 96 96l288 0 32 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l0-64c17.7 0 32-14.3 32-32l0-320c0-17.7-14.3-32-32-32L384 0 96 0zm0 384l256 0 0 64L96 448c-17.7 0-32-14.3-32-32s14.3-32 32-32zm32-240c0-8.8 7.2-16 16-16l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16zm16 48l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/></svg>
|
||||
</div>
|
||||
<h2>Buch Klasse N</h2>
|
||||
<p>Die Lernhinhalte für die Klasse N gibt es auch als gedrucktes Buch. Es ist passend zum Online-Kurs ausgelegt.</p>
|
||||
<div class="row row-cols-lg-2 g-2 mb-5">
|
||||
<div class="col"><a href="https://darcverlag.de/DARC-Amateurfunklehrgang-Klasse-N" class="btn btn-outline-dark w-100">Beim DARC-Verlag kaufen</a></div>
|
||||
<div class="col"><a href="https://www.amazon.de/dp/388692100X" class="btn btn-outline-dark w-100">Bei Amazon Kaufen</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 640 512" width="48"><path d="M337.8 5.4C327-1.8 313-1.8 302.2 5.4L166.3 96 48 96C21.5 96 0 117.5 0 144L0 464c0 26.5 21.5 48 48 48l208 0 0-96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 96 208 0c26.5 0 48-21.5 48-48l0-320c0-26.5-21.5-48-48-48L473.7 96 337.8 5.4zM96 192l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM96 320l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM232 176a88 88 0 1 1 176 0 88 88 0 1 1 -176 0zm88-48c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-16 0 0-16c0-8.8-7.2-16-16-16z"/></svg>
|
||||
</div>
|
||||
<h2>Kurse</h2>
|
||||
<p>Einige unserer Ortsverbände bieten Präsenz- oder Onlinekurse mit erfahrenen Ausbildern an. Finde heraus, ob es einen für dich passenden Kurs bei dir in der Nähe gibt!</p>
|
||||
<div class="d-flex gap-2 mb-5">
|
||||
<a href="kurse_vor_ort_karte.html" class="btn btn-outline-dark flex-fill">Präsenz</a>
|
||||
<a href="kurse_vor_ort_liste.html" class="btn btn-outline-dark flex-fill">Online</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 448 512" width="48"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z"/></svg>
|
||||
</div>
|
||||
<h2>Ausbildungs­paten</h2>
|
||||
<p>Unsere Ausbildungspaten sind erfahrene Funkamateure, die dich gerne unterstützen. Sie können mit dir auch praktisch üben und nützliche Tipps für die Praxis geben.</p>
|
||||
<div class="d-grid gap-2 mb-5">
|
||||
<a href="patenkarte.html" class="btn btn-outline-dark w-100">Zur Patenkarte</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 384 512" width="48"><path d="M192 0c-41.8 0-77.4 26.7-90.5 64L64 64C28.7 64 0 92.7 0 128L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64l-37.5 0C269.4 26.7 233.8 0 192 0zm0 64a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM105.8 229.3c7.9-22.3 29.1-37.3 52.8-37.3l58.3 0c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L216 328.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24l0-13.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1l-58.3 0c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM160 416a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>
|
||||
</div>
|
||||
<h2>Fragenkatalog</h2>
|
||||
<p>Den Fragenkatalog mit den amtlichen Prüfungsfragen gibt es digital bei der <a href="https://50ohm.de/fk">Bundesnetzagentur</a>. Beim DARC-Verlag kann man auch eine gedruckte Version bestellen.</p>
|
||||
<div class="d-grid gap-2 d-md-block mb-5">
|
||||
<a href="https://darcverlag.de/Fragenkatalog-Klasse-N" class="btn btn-outline-dark w-100">Beim DARC-Verlag kaufen</a>
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z"/></svg>
|
||||
</div>
|
||||
<h2>Om certifikaten</h2>
|
||||
<p>Vilket certifikat passar dig? Här hittar du en översikt över Instegscertifikatet och HAREC samt hur proven går till.</p>
|
||||
<div class="d-flex gap-2 mb-5">
|
||||
<a href="{{ pages.info }}" class="btn btn-outline-dark flex-fill">Info</a>
|
||||
<a href="{{ pages.prov }}" class="btn btn-outline-dark flex-fill">Prov</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 384 512" width="48"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M16 64C16 28.7 44.7 0 80 0L304 0c35.3 0 64 28.7 64 64l0 384c0 35.3-28.7 64-64 64L80 512c-35.3 0-64-28.7-64-64L16 64zM224 448a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM304 64L80 64l0 320 224 0 0-320z"/></svg>
|
||||
</div>
|
||||
<h2>Trainings App</h2>
|
||||
<p>Zum Trainieren der Fragen gibt es die 50Ohm App. Sie ist passend zum Online-Kurs ausgelegt.</p>
|
||||
<div class="d-flex flex-wrap gap-2 mb-5">
|
||||
<a href="https://play.google.com/store/apps/details?id=de.darc.fuenfizigohm" class="btn btn-outline-dark flex-fill">Android</a>
|
||||
<a href="https://apps.apple.com/de/app/50ohm/id6474642114" class="btn btn-outline-dark flex-fill">iOS</a>
|
||||
<a href="https://app.darc.de/obtainium.html" class="btn btn-outline-dark flex-fill">Obtainium</a>
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 640 512" width="48"><path d="M337.8 5.4C327-1.8 313-1.8 302.2 5.4L166.3 96 48 96C21.5 96 0 117.5 0 144L0 464c0 26.5 21.5 48 48 48l208 0 0-96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 96 208 0c26.5 0 48-21.5 48-48l0-320c0-26.5-21.5-48-48-48L473.7 96 337.8 5.4z"/></svg>
|
||||
</div>
|
||||
<h2>{{ snippets.lernen_kurs_title or "Kurser" }}</h2>
|
||||
<p>{{ snippets.lernen_kurs_teaser or "Hitta en kurs i din närhet." }}</p>
|
||||
<div class="d-flex gap-2 mb-5">
|
||||
<a href="{{ pages.kurser_karta }}" class="btn btn-outline-dark flex-fill">Karta</a>
|
||||
<a href="{{ pages.kurser_lista }}" class="btn btn-outline-dark flex-fill">Lista</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 448 512" width="48"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z"/></svg>
|
||||
</div>
|
||||
<h2>{{ snippets.lernen_mentor_title or "Mentorer" }}</h2>
|
||||
<p>{{ snippets.lernen_mentor_teaser or "Erfarna radioamatörer som hjälper dig att komma igång." }}</p>
|
||||
<div class="d-grid gap-2 mb-5">
|
||||
<a href="{{ pages.mentorer }}" class="btn btn-outline-dark w-100">{{ snippets.lernen_mentor_btn or "Till mentorerna" }}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% if has_question_pool %}
|
||||
<div class="feature col">
|
||||
<div class="feature-icon bg-primary bg-gradient">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 384 512" width="48"><path d="M192 0c-41.8 0-77.4 26.7-90.5 64L64 64C28.7 64 0 92.7 0 128L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64l-37.5 0C269.4 26.7 233.8 0 192 0z"/></svg>
|
||||
</div>
|
||||
<h2>Provsimulering</h2>
|
||||
<p>Öva på provfrågor under provliknande förhållanden.</p>
|
||||
<div class="d-grid gap-2 mb-5">
|
||||
<a href="{{ pages.simulering }}" class="btn btn-outline-dark w-100">Starta simuleringen</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a rel="me" href="https://social.darc.de/@AJW"></a>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<div class="row flex-lg-row-reverse align-items-top g-5">
|
||||
|
||||
<div class="col-lg-7">
|
||||
<iframe src="https://ajw.darc.de/lehrgangskarte/" width="100%" height="800px"></iframe>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Kurse vor Ort</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>Kurse vor Ort</h1>
|
||||
<p>Erfahrene Ausbilder halten – meist einmal in der Woche abends – Lektionen. Zwischen den Treffen solltest du selbständig den Lernstoff vertiefen und üben.</p>
|
||||
|
||||
|
||||
<a class="btn btn-outline-secondary btn-sm px-4 gap-3" href="kurse_vor_ort_liste.html">Online-Kurse</a>
|
||||
|
||||
<hr class="col-md-12 mb-3">
|
||||
|
||||
<div><b>Ausbildungskurs</b></div>
|
||||
<div class="d-grid gap-4 d-sm-flex mb-2 align-items-center">
|
||||
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
|
||||
<img src="https://ajw.darc.de/lehrgangskarte/img/Lehrgang-neu.png">
|
||||
neu
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
|
||||
<img src="https://ajw.darc.de/lehrgangskarte/img/Lehrgang-begonnen.png">
|
||||
läuft
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
|
||||
<img src="https://ajw.darc.de/lehrgangskarte/img/Lehrgang-jederzeit.png">
|
||||
auf Anfrage
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div><b>Online-Kurs mit Präsenzanteil</b></div>
|
||||
<div class="d-grid gap-4 d-sm-flex mb-2 align-items-center">
|
||||
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
|
||||
<img src="https://ajw.darc.de/lehrgangskarte/img/Online-neu.png">
|
||||
neu
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
|
||||
<img src="https://ajw.darc.de/lehrgangskarte/img/Online-begonnen.png">
|
||||
läuft
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,19 +0,0 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html#lernen">Lernen</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Kurse vor Ort</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>Kurse vor Ort</h1>
|
||||
<p>Erfahrene Ausbilder halten – meist einmal in der Woche abends – Lektionen. Zwischen den Treffen solltest du selbständig den Lernstoff vertiefen und üben.</p>
|
||||
|
||||
|
||||
<a class="btn btn-outline-secondary btn-sm px-4 gap-3" href="kurse_vor_ort_karte.html">Kartenansicht</a>
|
||||
|
||||
<hr class="col-md-12 mb-3">
|
||||
|
||||
<script src="https://darc.de/fileadmin/config/Resources/Public/JavaScript/tx_t3jquery/jquery-1.8.x-1.9.x-1.2.x.js?1619439474" type="text/javascript"></script>
|
||||
<script id="onlinekurse" type="text/javascript" src="https://ajw.darc.de/lehrgangskarte/onlinelehrgaenge.js"></script>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Hem</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html#lara">Lär dig</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Kurser på plats</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>{{ snippets.lernen_kurs_title or "Kurser på plats" }}</h1>
|
||||
{# TODO: Add a map of courses (e.g. an embedded map) once the operator has a data source. #}
|
||||
<p>{{ snippets.lernen_kurs_teaser or "Här kan du hitta kurser i din närhet." }}</p>
|
||||
|
||||
<a class="btn btn-outline-secondary btn-sm px-4 gap-3" href="{{ pages.kurser_lista }}">Lista</a>
|
||||
@@ -0,0 +1,13 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Hem</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html#lara">Lär dig</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Kurser</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>{{ snippets.lernen_kurs_title or "Kurser" }}</h1>
|
||||
{# TODO: Add a list of courses once the operator has a data source. #}
|
||||
<p>{{ snippets.lernen_kurs_teaser or "Här kan du hitta kurser i din närhet." }}</p>
|
||||
|
||||
<a class="btn btn-outline-secondary btn-sm px-4 gap-3" href="{{ pages.kurser_karta }}">Kartvy</a>
|
||||
@@ -0,0 +1,11 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Hem</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html#lara">Lär dig</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Mentorer</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h1>{{ snippets.lernen_mentor_title or "Mentorer" }}</h1>
|
||||
{# TODO: Add a list or map of mentors once the operator has a data source. #}
|
||||
<p>{{ snippets.lernen_mentor_teaser or "Erfarna radioamatörer som hjälper dig att komma igång." }}</p>
|
||||
@@ -1,4 +1,4 @@
|
||||
<br/>
|
||||
<div data-quiz-shown>
|
||||
Weiter zum nächsten Kapitel: <a href="{{ url }}">{{ title }}</a>
|
||||
Fortsätt till nästa kapitel: <a href="{{ url }}">{{ title }}</a>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<br/>
|
||||
<div data-quiz-shown>
|
||||
Weiter zum nächsten Abschnitt: <a href="{{ url }}">{{ title }}</a>
|
||||
Fortsätt till nästa avsnitt: <a href="{{ url }}">{{ title }}</a>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<html lang="sv">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>50Ω Lernplattform für Amateurfunk</title>
|
||||
<title>50Ω – lär dig amatörradio</title>
|
||||
{% if social_image %}
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="50ohm.de">
|
||||
<meta property="og:title" content="Ergebnis der 50ohm.de-Prüfungssimulation">
|
||||
<meta property="og:description" content="Mein Ergebnis der Prüfungssimulation auf 50ohm.de">
|
||||
<meta property="og:image" content="https://50ohm.de/{{ social_image }}">
|
||||
<meta property="og:image:alt" content="50ohm.de-Prüfungssimulation">
|
||||
<meta property="og:site_name" content="50Ω">
|
||||
<meta property="og:title" content="Resultat från provsimuleringen">
|
||||
<meta property="og:description" content="Mitt resultat från provsimuleringen">
|
||||
<meta property="og:image" content="{{ social_image }}">
|
||||
<meta property="og:image:alt" content="Provsimulering">
|
||||
<meta property="og:image:width" content="1448">
|
||||
<meta property="og:image:height" content="1086">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Ergebnis der 50ohm.de-Prüfungssimulation">
|
||||
<meta name="twitter:description" content="Mein Ergebnis der Prüfungssimulation auf 50ohm.de">
|
||||
<meta name="twitter:image" content="https://50ohm.de/{{ social_image }}">
|
||||
<meta name="twitter:image:alt" content="50ohm.de-Prüfungssimulation">
|
||||
<meta name="twitter:title" content="Resultat från provsimuleringen">
|
||||
<meta name="twitter:description" content="Mitt resultat från provsimuleringen">
|
||||
<meta name="twitter:image" content="{{ social_image }}">
|
||||
<meta name="twitter:image:alt" content="Provsimulering">
|
||||
{% endif %}
|
||||
|
||||
<link rel="icon" href="assets/favicon/icon.png" type="image/png">
|
||||
<link rel="icon" href="assets/favicon/icon.svg" type="image/svg+xml">
|
||||
<link rel="mask-icon" href="assets/favicon/mask-icon.svg" color="#00ADEF">
|
||||
<link href="assets/bootstrap-5.2.0-beta1-dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="assets/antrag/darc-antrag.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/style-fiftyohm.css?ts=20260805">
|
||||
<link rel="stylesheet" href="assets/style-course.css?ts=202608091745">
|
||||
<link rel="stylesheet" href="assets/katex/katex.min.css">
|
||||
@@ -35,7 +34,6 @@
|
||||
<script defer src="assets/katex/auto-render.min.js"></script>
|
||||
<script defer src="assets/latex.js?ts=20260805"></script>
|
||||
<script defer src="assets/script.js"></script>
|
||||
<script defer src="assets/antrag/floating-cta.js"></script>
|
||||
<style>
|
||||
</style>
|
||||
|
||||
@@ -59,15 +57,12 @@
|
||||
<div class="fiftyohm-layout-outer fiftyohm-layout-outer-head">
|
||||
<div class="fiftyohm-layout-inner">
|
||||
<div class="fiftyohm-layout-left">
|
||||
<a class="fiftyohm-brand" href="index.html">
|
||||
<svg class="fiftyohm-darc-logo" version="1.1" viewBox="0 0 246.67 568" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(1.3333 0 0 -1.3333 0 568)"><g transform="scale(.1)" fill-rule="evenodd"><path class="background" d="m925.58 4257.2 921.73-2126-921.73-2126-921.7 2126 921.7 2126" /><path class="foreground" d="m799.9 896.17c0 59.754 42.86 104.21 77.403 104.21h126.99c42.97 0 76.61-43.81 78.46-79.345 1.13-21.539 0.92-84.984 0.92-84.984h-92.787v30.215s1.43 17.007-4.485 25.152c-4.351 5.973-12.585 5.922-12.585 5.922l-49.133 0.098s-9.41 1.156-14.828-3.778c-8.129-7.41-6.895-31.086-6.895-31.086l-0.742-245.91s-1.246-23.664 6.898-31.062c5.414-4.95 14.821-3.793 14.821-3.793l49.144 0.105s8.223-0.055 12.567 5.926c5.937 8.137 4.492 25.148 4.492 25.148v30.215h92.793s0.21-63.465-0.93-84.984c-1.83-35.539-35.48-79.36-78.45-79.36h-126.99c-34.543 0-77.414 44.473-77.414 104.23 0 6.461 0.753 306.61 0.753 313.08zm579.59 938.37-0.68 585.24s135.56-0.65 163.11-0.65c57.13 0 107.14-32.64 107.14-92.84 0-52.22 1.16-140.81-0.2-169.36-3.01-62.64-12.03-86.63-48.82-100.15-0.5-0.91 63.25-223.12 63.25-223.12l-95.01-1-54.63 221.99-38.08 0.19 0.2-221.18-96.28 0.88zm-577.9 1958.4 180.9 0.92c35.476 0 57.856-13.14 78.026-33.78 20.17-20.67 22.22-72.35 22.22-92.03v-316.28c0-19.7 3.22-69.56-22.4-98.04-25.61-28.49-54.64-29.54-75.877-29.54-21.258 0-184.63 0.74-184.63 0.74zm102.26-93.9 52.777 0.24c10.344 0 16.859-3.26 22.75-8.4 5.887-5.12 6.477-17.93 6.477-22.83v-320.66c0-4.93 0.968-17.29-6.508-24.37-7.469-7.05-15.953-7.29-22.16-7.29-6.184 0-53.864 0.19-53.864 0.19zm-240.62-757.48 278.02 239.37 287.78-239.37h-152.81l-77.847 58.63-0.011-200.43s-187-32.49-245.48-81.75c-42.472-35.79-14.359-79.97-14.359-79.97s79.019 66.25 265.2 70.19c154.93 3.29 283.13-48.07 284.62-146.52 1.48-98.45-123.37-138.52-286.59-143.51-158.53-4.85-262.59 62.69-262.59 62.69s-26.492-56.49-21.562-94.03c3.969-30.24 28.957-62.09 28.957-62.09s127.82 60.1 253.23 60.1c180.69 0 297.72-49.65 297.79-135.56 0.07-85.87-120.96-132.83-274.27-138.78-150.89-5.89-282.2 62.69-282.2 62.69s-27.422-23.16-27.422-62.69c0-38.27 44.918-86.98 44.918-86.98s101.78 53.15 252.94 53.66c186.38 0.64 289.25-74.73 288.66-136.34-0.59-61.59-97.01-132.78-286.7-134.1-152.05-1.07-250.84 47.04-250.84 47.04s-8.519-54.46 48.145-83.28c75.105-38.19 197.85-32.14 197.85-32.14l0.27-110.24h204.22l-39.54-80.32h-461.47l-39.211 80.32h212.49l0.746 33.55s-200.26 3.91-227.98 157.03c-14.165 78.18 28.195 130.94 28.195 130.94s-84.285 87.86-76.426 180.29c7.836 92.11 58.844 138.72 58.844 138.72s-51.75 55-51.75 132.64c0 77.63 43.902 161.86 43.902 161.86s-30.512 25.55-29.383 99.96c2.602 174.92 254.86 210.34 254.86 210.34l1.648 126.71-70.551-58.78zm485.76-1443.7-33.46-67.98h-345.77l-33.184 67.98zm-58.08-117.98-32.56-66.12h-231.88l-32.297 66.12zm-57.17-116.12-28.59-58.05h-125.92l-28.352 58.05zm-53.203-108.05-25.816-52.45h-25.481l-25.609 52.45zm-518.6 1263.5 101.5-585.47h-107.27l-17.383 96.76-86.988-0.47-14.359-96.29h-111.09l97.531 584.45 138.06 1.02zm-95.485-378.04h54.079l-28.559 234.91zm1158.4 115.97c14.01 0.44 30.32 6.23 29.01 24.65-0.73 10.32-0.07 95.47-0.07 114.7 0 15.59-8.57 31.16-25.5 31.16-24.09 0-52.41-0.93-52.41-0.93l-0.28-170.38s25.99 0.07 49.25 0.8zm-334.95-219c0-28.15-89.04-50.95-198.9-50.95-109.86 0-198.91 50.95-198.91 50.95s89.046 50.95 198.91 50.95c109.86 0 198.9-22.81 198.9-50.95zm0 307.67c0-28.14-89.04-50.94-198.9-50.94-109.86 0-198.91 50.94-198.91 50.94s89.046 50.95 198.91 50.95c109.86 0 198.9-22.81 198.9-50.95zm0 315.51c0-28.14-89.04-50.97-198.9-50.97-109.86 0-198.91 50.97-198.91 50.97s89.046 50.94 198.91 50.94c109.86 0 198.9-22.8 198.9-50.94" /></g></g></svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="fiftyohm-layout-main">
|
||||
<a class="fiftyohm-brand" href="index.html">
|
||||
<img class="fiftyohm-logo" src="assets/images/50ohm.svg">
|
||||
<br>
|
||||
<span>Lernplattform für Amateurfunk</span>
|
||||
<span>Lär dig amatörradio</span>
|
||||
</a>
|
||||
<div class="fiftyohm-nav-button" id="nav-button" onclick="toggleNavBar();">
|
||||
<svg id="nav-button-closed" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path class="background" d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"/></svg>
|
||||
@@ -81,41 +76,37 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="index.html#lernen">
|
||||
<a href="index.html#lara">
|
||||
<span class="material-icons icon-lernen">local_library</span>
|
||||
Lernen
|
||||
Lär dig
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="suche.html">
|
||||
<a href="{{ pages.sok }}">
|
||||
<span class="material-icons icon-suche">search</span>
|
||||
Suche
|
||||
Sök
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="infos.html">
|
||||
<a href="{{ pages.info }}">
|
||||
<span class="material-icons icon-infos">info</span>
|
||||
Infos
|
||||
Info
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="pruefung.html">
|
||||
<a href="{{ pages.prov }}">
|
||||
<span class="material-icons icon-pruefung">fact_check</span>
|
||||
Prüfung
|
||||
Prov
|
||||
</a>
|
||||
</li>
|
||||
{% if has_question_pool %}
|
||||
<li>
|
||||
<a href="simulation.html">
|
||||
<a href="{{ pages.simulering }}">
|
||||
<span class="material-icons icon-simulation">quiz</span>
|
||||
Simulation
|
||||
Simulering
|
||||
</a>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<a href="login.html">
|
||||
<span class="material-icons">login</span>
|
||||
Login
|
||||
</a>
|
||||
</li>-->
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="fiftyohm-layout-right">
|
||||
@@ -154,30 +145,16 @@
|
||||
|
||||
<footer class="text-lg-start border-top border-dark mt-5 pt-3">
|
||||
<div class="fiftyohm-footer-content d-flex flex-wrap align-items-end justify-content-between gap-5 mb-5">
|
||||
<div class="fiftyohm-footer-logo">
|
||||
<img height="90" src="assets/images/darc.svg">
|
||||
</div>
|
||||
<div class="fiftyohm-footer-info d-flex flex-column align-items-center">
|
||||
<div class="fiftyohm-footer-team d-flex gap-1 align-items-center mb-1">
|
||||
Mit
|
||||
<svg class="text-primary" xmlns="http://www.w3.org/2000/svg" width="1rem" height="1rem" fill="#FE756C" viewBox="0 0 512 512"><path d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></svg></span>
|
||||
vom <a class=link-secondary href="/infos.html#contributors">50ohm-Team</a> entwickelt
|
||||
<div class="fiftyohm-footer-info d-flex flex-column">
|
||||
<div class="mb-1">
|
||||
Baserad på <a class="link-secondary" href="https://50ohm.de">50ohm.de</a> (DARC e. V.),
|
||||
<a class="link-secondary" href="https://creativecommons.org/licenses/by/4.0/deed.sv">CC BY 4.0</a>
|
||||
– översatt och anpassad till svenska förhållanden.
|
||||
Inte godkänd av DARC eller SSA.
|
||||
</div>
|
||||
<div class="mb-1">Ein Angebot des Deutschen Amateur-Radio-Club e. V.</div>
|
||||
<div class="fiftyohm-footer-links d-flex gap-2">
|
||||
<a class="link-secondary" href="https://www.darc.de/der-club/referate/ajw/">Referat AJW</a>
|
||||
·
|
||||
<a class="link-secondary" href="https://darc.de/impressum">Impressum</a>
|
||||
·
|
||||
<a class="link-secondary" href="https://darc.de/datenschutzerklaerung">Datenschutz</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fiftyohm-footer-sponsor text-start">
|
||||
<div>Unterstützt von:</div>
|
||||
<div style="margin-top: -15px;">
|
||||
<a href="https://www.rohde-schwarz.com/ausbildung">
|
||||
<img style="width: 300px;" src="assets/images/rus-logo-gross.svg">
|
||||
</a>
|
||||
{# TODO: The operator must add their own imprint / contact details and privacy information here. #}
|
||||
<span class="text-secondary">[Utgivare, kontakt och integritetspolicy – ska fyllas i av driftansvarig]</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -190,27 +167,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="darc-antrag">
|
||||
<div class="darc-floating darc-floating--right" data-darc-floating="1" data-uid="341903" data-dismissible="1">
|
||||
<div class="btn-group" role="group" aria-label="DARC Mitgliedsantrag">
|
||||
<a class="btn btn-primary darc-floating__link" href="https://antrag.darc.de/" target="_blank" rel="noopener noreferrer">
|
||||
<span class="darc-floating__icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" focusable="false">
|
||||
<path d="M12 20v-7"></path>
|
||||
<circle cx="12" cy="11" r="2"></circle>
|
||||
<path d="M7.8 6.2a6 6 0 0 0 0 8.5"></path>
|
||||
<path d="M16.2 6.2a6 6 0 0 1 0 8.5"></path>
|
||||
<path d="M5 3.7a9.5 9.5 0 0 0 0 13.4"></path>
|
||||
<path d="M19 3.7a9.5 9.5 0 0 1 0 13.4"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="darc-floating__label">DARC Mitglied werden</span>
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary darc-floating__close" aria-label="Hinweis ausblenden">×</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/bootstrap-5.2.0-beta1-dist/js/bootstrap.bundle.min.js"></script>
|
||||
{% for script in page_scripts|default([]) %}
|
||||
<script src="{{ script }}"></script>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html#lernen">Lernen</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Ausbildungspaten</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row flex-lg-row-reverse align-items-top g-5 py-1">
|
||||
<div class="col-lg-7">
|
||||
<iframe src="https://ajw.darc.de/patenkarte/" width="100%" height="800px"></iframe>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<h1>Ausbildungspaten</h1>
|
||||
<p>Die DARC-Ausbildungspaten sind erfahrene Funkamateure und helfen dir gerne beim Einstieg in den Amateurfunk. Sie beantworten Fragen, Helfen beim Lernen und können mit dir praktischen Ausbildungsfunk machen.</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -25,11 +25,11 @@
|
||||
</div>
|
||||
<div class="solution" data-quiz-shown>
|
||||
{% if has_solution %}
|
||||
<a class="btn btn-warning btn-sm d-inline-flex align-items-center" href="{{ number }}.html" aria-label="Lösungshinweis zu Frage {{ number }}" title="Lösungshinweis">
|
||||
<a class="btn btn-warning btn-sm d-inline-flex align-items-center" href="{{ number }}.html" aria-label="Lösningstips till fråga {{ number }}" title="Lösningstips">
|
||||
<svg class="solution-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" fill="currentColor" aria-hidden="true" focusable="false">
|
||||
<path d="M420.9 448C428.2 425.7 442.8 405.5 459.3 388.1C492 353.7 512 307.2 512 256C512 150 426 64 320 64C214 64 128 150 128 256C128 307.2 148 353.7 180.7 388.1C197.2 405.5 211.9 425.7 219.1 448L420.8 448zM416 496L224 496L224 512C224 556.2 259.8 592 304 592L336 592C380.2 592 416 556.2 416 512L416 496zM312 176C272.2 176 240 208.2 240 248C240 261.3 229.3 272 216 272C202.7 272 192 261.3 192 248C192 181.7 245.7 128 312 128C325.3 128 336 138.7 336 152C336 165.3 325.3 176 312 176z"/>
|
||||
</svg>
|
||||
<span>Lösungsweg anzeigen</span>
|
||||
<span>Visa lösningsvägen</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<div style="float: right;" data-quiz-shown>
|
||||
<div class="btn-group" role="group">
|
||||
{% if section["video_url"] %}
|
||||
<a class="btn btn-secondary" href="{{ section["video_url"] }}" title="Video öffnen" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z"></path></svg></a>
|
||||
<a class="btn btn-secondary" href="{{ section["video_url"] }}" title="Öppna video" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z"></path></svg></a>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary" href="{{ edition }}_slide_{{ chapter["ident"] }}.html#{{ section_id }}" title="Öppna presentation"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M840-120v-640H120v320H40v-320q0-33 23.5-56.5T120-840h720q33 0 56.5 23.5T920-760v560q0 33-23.5 56.5T840-120ZM360-400q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T440-560q0-33-23.5-56.5T360-640q-33 0-56.5 23.5T280-560q0 33 23.5 56.5T360-480ZM40-80v-112q0-34 17.5-62.5T104-298q62-31 126-46.5T360-360q66 0 130 15.5T616-298q29 15 46.5 43.5T680-192v112H40Zm80-80h480v-32q0-11-5.5-20T580-226q-54-27-109-40.5T360-280q-56 0-111 13.5T140-226q-9 5-14.5 14t-5.5 20v32Zm240-400Zm0 400Z"/></svg></a>
|
||||
{% if has_question_pool %}
|
||||
<button type="button" class="btn btn-secondary" id="quiz-mode-toggle" title="Visa endast frågor" aria-pressed="false"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 16 16" fill="#000000"><path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/><path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/><path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/></svg></button>
|
||||
{% endif %}
|
||||
<a class="btn btn-secondary" href="{{ edition }}_slide_{{ chapter["ident"] }}.html#{{ section_id }}" title="Präsentationsfolien öffnen"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M840-120v-640H120v320H40v-320q0-33 23.5-56.5T120-840h720q33 0 56.5 23.5T920-760v560q0 33-23.5 56.5T840-120ZM360-400q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T440-560q0-33-23.5-56.5T360-640q-33 0-56.5 23.5T280-560q0 33 23.5 56.5T360-480ZM40-80v-112q0-34 17.5-62.5T104-298q62-31 126-46.5T360-360q66 0 130 15.5T616-298q29 15 46.5 43.5T680-192v112H40Zm80-80h480v-32q0-11-5.5-20T580-226q-54-27-109-40.5T360-280q-56 0-111 13.5T140-226q-9 5-14.5 14t-5.5 20v32Zm240-400Zm0 400Z"/></svg></a>
|
||||
<a class="btn btn-secondary" target="_blank" href="/hm" title="Hilfsmittel herunterladen"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 640 640" fill="#000000"><!--!Font Awesome Free v7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M192 112L304 112L304 200C304 239.8 336.2 272 376 272L464 272L464 512C464 520.8 456.8 528 448 528L192 528C183.2 528 176 520.8 176 512L176 128C176 119.2 183.2 112 192 112zM352 131.9L444.1 224L376 224C362.7 224 352 213.3 352 200L352 131.9zM192 64C156.7 64 128 92.7 128 128L128 512C128 547.3 156.7 576 192 576L448 576C483.3 576 512 547.3 512 512L512 250.5C512 233.5 505.3 217.2 493.3 205.2L370.7 82.7C358.7 70.7 342.5 64 325.5 64L192 64zM248 320C234.7 320 224 330.7 224 344C224 357.3 234.7 368 248 368L392 368C405.3 368 416 357.3 416 344C416 330.7 405.3 320 392 320L248 320zM248 416C234.7 416 224 426.7 224 440C224 453.3 234.7 464 248 464L392 464C405.3 464 416 453.3 416 440C416 426.7 405.3 416 392 416L248 416z"/></svg></a>
|
||||
<button type="button" class="btn btn-secondary" id="quiz-mode-toggle" title="Nur Fragen anzeigen" aria-pressed="false"><svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 16 16" fill="#000000"><path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/><path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/><path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12-.708.708z"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav aria-label="breadcrumb" data-quiz-shown>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html">Hem</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ edition }}_course_index.html">{{ name }}</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ edition }}_chapter_{{ chapter["ident"] }}.html">{{ chapter["title"] }}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ section["title"] }}</li>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" fill="currentColor" aria-hidden="true" focusable="false" style="width: 1.1em; height: 1.1em; vertical-align: -0.1em;">
|
||||
<path d="M420.9 448C428.2 425.7 442.8 405.5 459.3 388.1C492 353.7 512 307.2 512 256C512 150 426 64 320 64C214 64 128 150 128 256C128 307.2 148 353.7 180.7 388.1C197.2 405.5 211.9 425.7 219.1 448L420.8 448zM416 496L224 496L224 512C224 556.2 259.8 592 304 592L336 592C380.2 592 416 556.2 416 512L416 496zM312 176C272.2 176 240 208.2 240 248C240 261.3 229.3 272 216 272C202.7 272 192 261.3 192 248C192 181.7 245.7 128 312 128C325.3 128 336 138.7 336 152C336 165.3 325.3 176 312 176z"/>
|
||||
</svg>
|
||||
Lösungsweg: {{number}}
|
||||
Lösningsväg: {{number}}
|
||||
</h2>
|
||||
|
||||
<div class="card-body text-bg-light">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<div class="question layout-{{ layout }} for-solution" id="{{ number }}">
|
||||
<div class="question-text m-0">Frage: {{ question }}</div>
|
||||
<div class="question-text m-0">Fråga: {{ question }}</div>
|
||||
{% if picture_question %}
|
||||
<div class="question-picture"><img src="pictures/{{ picture_question }}.svg" alt="{{ alt_text_question }}"></div>
|
||||
{% endif %}
|
||||
<div class="answers">
|
||||
{% for i in range(1) %}
|
||||
<div>
|
||||
<b>{{ 'Lösung:' if i == 0 else 'Falsch:' }}</b>
|
||||
<b>{{ 'Lösning:' if i == 0 else 'Fel:' }}</b>
|
||||
{% if answers[i] %}
|
||||
{{ answers[i] }}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,113 +1,103 @@
|
||||
<section>
|
||||
<h3>Navigationshilfe</h3>
|
||||
<p>Diese Navigationshilfe zeigt die ersten Schritte zur Verwendung der Präsention. Sie kann mit ⟶ (Pfeiltaste
|
||||
rechts) übersprungen werden.</p>
|
||||
<h3>Navigeringshjälp</h3>
|
||||
<p>Den här navigeringshjälpen visar de första stegen för att använda presentationen. Du kan hoppa över den med ⟶ (högerpil).</p>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Navigation</h4>
|
||||
<h4>Navigering</h4>
|
||||
<div id="left">
|
||||
<p>Zwischen den Folien und Abschnitten lässt sich mittels der Pfeiltasten hin- und herspringen, dazu lassen sich
|
||||
auch
|
||||
die Pfeiltasten am Computer nutzen.</p>
|
||||
<img src="assets/images/slides/navigation.png" alt="Navigationspfeile für die Präsentation" />
|
||||
<p>Du kan bläddra mellan bilder och avsnitt med piltangenterna på datorn.</p>
|
||||
<img src="assets/images/slides/navigation.png" alt="Navigeringspilar för presentationen" />
|
||||
</div>
|
||||
<div id="right">
|
||||
<ul class="list">
|
||||
<li>Pfeil runter und hoch: Nächste / Vorherige Folie</li>
|
||||
<li>Pfeil rechts und links: Nächster / Vorheriger Abschnitt</li>
|
||||
<li>Leertaste oder „n“: Der Reihe nach alle Elemente in Folien aufdecken oder zur nächsten Folie blättern
|
||||
<li>Pil ned och upp: nästa / föregående bild</li>
|
||||
<li>Pil höger och vänster: nästa / föregående avsnitt</li>
|
||||
<li>Blanksteg eller ”n”: visa elementen på bilden ett i taget eller gå till nästa bild
|
||||
</li>
|
||||
<li>Shift-Leertaste oder „p“: Der Reihe nach Elemente rückwärts zudecken oder zur vorherigen Folie blättern
|
||||
<li>Skift-blanksteg eller ”p”: dölj elementen baklänges eller gå till föregående bild
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Weitere Funktionen</h4>
|
||||
<p>Mit ein paar Tastenkürzeln können weitere Funktionen aufgerufen werden. Die wichtigsten sind:</p>
|
||||
<h4>Fler funktioner</h4>
|
||||
<p>Med några kortkommandon kommer du åt fler funktioner. De viktigaste är:</p>
|
||||
<dl>
|
||||
<dt>F1</dt>
|
||||
<dd>Help / Hilfe</dd>
|
||||
<dd>Help / hjälp</dd>
|
||||
<dt>o</dt>
|
||||
<dd>Overview / Übersicht aller Folien</dd>
|
||||
<dd>Overview / översikt över alla bilder</dd>
|
||||
<dt>s</dt>
|
||||
<dd>Speaker View / Referentenansicht</dd>
|
||||
<dd>Speaker View / talarvy</dd>
|
||||
<dt>f</dt>
|
||||
<dd>Full Screen / Vollbildmodus</dd>
|
||||
<dd>Full Screen / helskärmsläge</dd>
|
||||
<dt>b</dt>
|
||||
<dd>Break, Black, Pause / Ausblenden der Präsentation</dd>
|
||||
<dt>Alt-Click</dt>
|
||||
<dd>In die Folie hin- oder herauszoomen</dd>
|
||||
<dd>Break, Black, Pause / dölj presentationen</dd>
|
||||
<dt>Alt-klick</dt>
|
||||
<dd>Zooma in på eller ut från bilden</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Übersicht</h4>
|
||||
<h4>Översikt</h4>
|
||||
<div id="left">
|
||||
<p>Die Präsentation ist zweidimensional aufgebaut. Dadurch sind in Spalten die einzelnen Abschnitte eines
|
||||
Kapitels und in den Reihen die Folien zu den Abschnitten.</p>
|
||||
<p>Tippt man ein „o“ ein, bekommt man eine Übersicht über alle Folien des Foliensatzes. Das hilft,
|
||||
sich zunächst einen Überblick zu verschaffen oder sich zu orientieren, wenn man das Gefüht hat, sich
|
||||
„verlaufen“ zu haben. Die Navigation erfolgt über die Pfeiltasten.</p>
|
||||
<p>Presentationen är tvådimensionell: kolumnerna är kapitlets avsnitt och raderna är bilderna i respektive avsnitt.</p>
|
||||
<p>Skriver du ett ”o” får du en översikt över alla bilder i presentationen. Det hjälper dig att få en
|
||||
överblick eller hitta tillbaka om du känner att du ”gått vilse”. Navigera med piltangenterna.</p>
|
||||
</div>
|
||||
<div id="right">
|
||||
<img src="assets/images/slides/overview.png" alt="Übersicht aller Folien" />
|
||||
<p>Durch Anklicken einer Folie wird diese präsentiert.</p>
|
||||
<img src="assets/images/slides/overview.png" alt="Översikt över alla bilder" />
|
||||
<p>Klicka på en bild för att visa den.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Referentenansicht</h4>
|
||||
<h4>Talarvy</h4>
|
||||
<div id="left">
|
||||
<img src="assets/images/slides/notes.png" alt="Referentenansicht" />
|
||||
<p>Tippt man ein „s“ ein, bekommt man ein neues Fenster, die Referentenansicht.</p>
|
||||
<p>Indem man „Layout“ auswählt, kann man zwischen verschieden Anordnungen der Elemente auswählen.</p>
|
||||
<img src="assets/images/slides/notes.png" alt="Talarvy" />
|
||||
<p>Skriver du ett ”s” öppnas ett nytt fönster, talarvyn.</p>
|
||||
<p>Under ”Layout” kan du välja mellan olika placeringar av elementen.</p>
|
||||
</div>
|
||||
<div id="right">
|
||||
<p>Die Referentenansicht bietet folgende Elemente:</p>
|
||||
<p>Talarvyn innehåller följande:</p>
|
||||
<ul class="list">
|
||||
<li>Links sieht man die aktuelle Folie</li>
|
||||
<li>Rechts oben sieht man die nächste Folie</li>
|
||||
<li>Rechts in der Mitte Hilfsmittel zur Zeiteinteilung</li>
|
||||
<li>Rechts unten, die „Notizen für den Vortragenden“</li>
|
||||
<li>Unten die Pfeile zur Navigation</li>
|
||||
<li>Till vänster syns den aktuella bilden</li>
|
||||
<li>Uppe till höger syns nästa bild</li>
|
||||
<li>I mitten till höger finns hjälpmedel för tidsplaneringen</li>
|
||||
<li>Nere till höger finns ”anteckningar för talaren”</li>
|
||||
<li>Längst ned finns navigeringspilarna</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h3>Praxistipps zur Referentenansicht</h3>
|
||||
<h3>Praktiska tips för talarvyn</h3>
|
||||
<ul class="list">
|
||||
<li>Wenn man mit einem Projektor arbeitet, stellt man im Betriebssystem die Nutzung von 2 Monitoren ein: Die
|
||||
Referentenansicht wird dann zum Beispiel auf dem Laptop angezeigt, während die Teilnehmer die
|
||||
Präsentation angezeigt bekommen.</li>
|
||||
<li>Bei einer Online-Präsentation, wie beispielsweise auf <a href="https://treff.darc.de/">TREFF.darc.de</a>,
|
||||
präsentiert man den Browser-Tab und navigiert im „Speaker View“ Fenster.</li>
|
||||
<li>Die Referentenansicht bezieht sich immer auf ein Kapitel. Am Ende des Kapitels muss sie geschlossen
|
||||
werden, um im neuen Kapitel eine neue Referentenansicht zu öffnen.</li>
|
||||
<li>Um mit dem Mauszeiger etwas zu markieren oder den Zoom zu verwenden, muss mit der Maus auf den
|
||||
Bildschirm mit der Präsentation gewechselt werden.</li>
|
||||
<li>Om du använder en projektor ställer du in operativsystemet på två skärmar: talarvyn visas då till exempel
|
||||
på laptopen medan deltagarna ser presentationen.</li>
|
||||
<li>Vid en onlinepresentation delar du webbläsarfliken och navigerar i fönstret ”Speaker View”.</li>
|
||||
<li>Talarvyn gäller alltid ett kapitel. I slutet av kapitlet måste den stängas för att kunna öppna en ny
|
||||
talarvy i nästa kapitel.</li>
|
||||
<li>För att markera något med muspekaren eller använda zoom måste du byta till det fönster där
|
||||
presentationen visas.</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Vollbild</h4>
|
||||
<p>Tippt man ein „f“ ein, wird die aktuelle Folie im Vollbild angezeigt. Mit „Esc“ kann man das Vollbild wieder
|
||||
verlassen.</p>
|
||||
<p>Das ist insbesondere für den Bildschirm mit der Präsentation für das Publikum praktisch.</li>
|
||||
<h4>Helskärm</h4>
|
||||
<p>Skriver du ett ”f” visas den aktuella bilden i helskärm. Med ”Esc” lämnar du helskärmsläget.</p>
|
||||
<p>Det är särskilt praktiskt för skärmen som visar presentationen för publiken.</p>
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Ausblenden</h4>
|
||||
<p>Tippt man ein „b“ ein, wird die Präsentation ausgeblendet.</p>
|
||||
<p>Sie kann wie folgt wieder eingeblendet werden:</p>
|
||||
<h4>Dölj</h4>
|
||||
<p>Skriver du ett ”b” döljs presentationen.</p>
|
||||
<p>Du visar den igen på något av följande sätt:</p>
|
||||
<ul class="list">
|
||||
<li>Durch Klicken in das Fenster.</li>
|
||||
<li>Durch nochmaliges Drücken von „b“.</li>
|
||||
<li>Durch Klicken der Schaltfläche „Resume presentation“.</li>
|
||||
<li>Klicka i fönstret.</li>
|
||||
<li>Tryck på ”b” igen.</li>
|
||||
<li>Klicka på knappen ”Resume presentation”.</li>
|
||||
</ul>
|
||||
<img src="assets/images/slides/resume.png" alt="Schaltfläche für Resume Presentation" />
|
||||
<img src="assets/images/slides/resume.png" alt="Knappen Resume Presentation" />
|
||||
</section>
|
||||
<section style="font-size: smaller;">
|
||||
<h4>Zoom</h4>
|
||||
<p>Bei gedrückter Alt-Taste und einem Mausklick in der Präsentation wird in diesen Teil hineingezoomt. Das ist
|
||||
praktisch, um Details von Schaltungen hervorzuheben. Durch einen nochmaligen Mausklick zusammen mit Alt wird
|
||||
wieder herausgezoomt.</p>
|
||||
<p>Das Zoomen funktioniert nur im ausgewählten Fenster. Die Referentenansicht ist hier nicht mit der
|
||||
Präsenationsansicht gesynct.</p>
|
||||
<p>Håller du ned Alt-tangenten och klickar i presentationen zoomas den delen in. Det är praktiskt för att lyfta fram
|
||||
detaljer i kopplingar. Ett nytt klick tillsammans med Alt zoomar ut igen.</p>
|
||||
<p>Zoomen fungerar bara i det valda fönstret. Talarvyn är inte synkroniserad med presentationsvyn när det gäller zoom.</p>
|
||||
</section>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<section data-background="#DAEEFA">
|
||||
<h2>Fragen?</h2>
|
||||
<h2>Frågor?</h2>
|
||||
<hr />
|
||||
<h3>Links zu diesem Foliensatz</h3>
|
||||
<h3>Länkar till den här presentationen</h3>
|
||||
<ul>
|
||||
{% if next_chapter is defined -%}
|
||||
<li><a href="{{ edition }}_slide_{{ next_chapter["ident"] }}.html">Weiter zum nächsten Kapitel: {{
|
||||
<li><a href="{{ edition }}_slide_{{ next_chapter["ident"] }}.html">Gå vidare till nästa kapitel: {{
|
||||
next_chapter["title"] }}</a></li>
|
||||
{% endif -%}
|
||||
<li><a href="{{ edition }}_chapter_{{ chapter["ident"] }}.html">Zum Kapitel auf 50Ohm.de</a></li>
|
||||
<li><a href="{{ edition }}_slide_index.html">Zur Kapitelübersicht aller Foliensätze</a></li>
|
||||
<li><a href="?print-pdf">Diesen Foliensatz zum Ausdrucken öffnen</a></li>
|
||||
<li><a href="?print-pdf&showNotes=true">Diesen Foliensatz mit Notizen zum Ausdrucken öffnen</a></li>
|
||||
<li><a href="{{ edition }}_chapter_{{ chapter["ident"] }}.html">Till kapitlet på webbplatsen</a></li>
|
||||
<li><a href="{{ edition }}_slide_index.html">Till kapitelöversikten för alla presentationer</a></li>
|
||||
<li><a href="?print-pdf">Öppna presentationen för utskrift</a></li>
|
||||
<li><a href="?print-pdf&showNotes=true">Öppna presentationen med anteckningar för utskrift</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<html lang="sv">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DARC Ausbildungsplattform</title>
|
||||
<title>50Ω – presentation</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h1>Folien: {{ book["title"] }}</h1>
|
||||
<h1>Presentationer: {{ book["title"] }}</h1>
|
||||
<p>{{ book["abstract"] }}</p>
|
||||
<div class="chapter-toc d-grid gap-2">
|
||||
{% for chapter in book["chapters"] %}
|
||||
|
||||
@@ -10,7 +10,7 @@ def test_comment_html():
|
||||
assertions = {
|
||||
"%Comment\nBar": paragraph("Bar"),
|
||||
"%Comment\n": "",
|
||||
"Foo 100 % Bar": paragraph("Foo 100% Bar"),
|
||||
"Foo 100 % Bar": paragraph("Foo 100 % Bar"),
|
||||
"Foo\n%Comment\nBar": paragraph("Foo") + paragraph("Bar"),
|
||||
}
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ from test.util import paragraph, render_html
|
||||
|
||||
@pytest.mark.html
|
||||
def test_halfwidth_space_html():
|
||||
input = "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein."
|
||||
target = "Dies ist z. B. ein Test. D. h. hier sollten d. h. Spaces ersetzt worden sein."
|
||||
input = "Det här är t.ex. ett test. T.ex. här ska mellanrummen ha ersatts, t. ex. så."
|
||||
target = "Det här är t. ex. ett test. T. ex. här ska mellanrummen ha ersatts, t. ex. så."
|
||||
|
||||
assert render_html(input) == paragraph(target)
|
||||
|
||||
|
||||
@pytest.mark.latex
|
||||
def test_halfwidth_space_latex():
|
||||
input = "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein."
|
||||
target = "\nDies ist z.\\,B. ein Test. D.\\,h. hier sollten d.\\,h. Spaces ersetzt worden sein.\n"
|
||||
input = "Det här är t.ex. ett test. T.ex. här ska mellanrummen ha ersatts."
|
||||
target = "\nDet här är t.\\,ex. ett test. T.\\,ex. här ska mellanrummen ha ersatts.\n"
|
||||
|
||||
assert mistletoe.markdown(input, FiftyOhmLaTeXRenderer) == target
|
||||
|
||||
@@ -29,8 +29,8 @@ Reference to second: [ref:pic2]
|
||||
result = renderer.render(doc)
|
||||
|
||||
# Hierarchical numbers in the figure captions.
|
||||
assert "Abbildung E-2.3.1:" in result
|
||||
assert "Abbildung E-2.3.2:" in result
|
||||
assert "Figur E-2.3.1:" in result
|
||||
assert "Figur E-2.3.2:" in result
|
||||
|
||||
# References are resolved to the same numbers.
|
||||
assert ">E-2.3.1</a>" in result
|
||||
@@ -56,8 +56,8 @@ Reference: [ref:photo1]
|
||||
|
||||
result = renderer.render(doc)
|
||||
|
||||
assert "Abbildung N-1.2.1:" in result
|
||||
assert "Abbildung N-1.2.2:" in result
|
||||
assert "Figur N-1.2.1:" in result
|
||||
assert "Figur N-1.2.2:" in result
|
||||
assert ">N-1.2.1</a>" in result
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ Reference: [ref:table1]
|
||||
|
||||
result = renderer.render(doc)
|
||||
|
||||
assert "Tabelle A-3.1.1:" in result
|
||||
assert "Tabelle A-3.1.2:" in result
|
||||
assert "Tabell A-3.1.1:" in result
|
||||
assert "Tabell A-3.1.2:" in result
|
||||
assert ">A-3.1.1</a>" in result
|
||||
|
||||
|
||||
@@ -117,10 +117,10 @@ References: [ref:pic1], [ref:photo1], [ref:tab1], [ref:pic2]
|
||||
|
||||
result = renderer.render(doc)
|
||||
|
||||
assert "Abbildung E-5.2.1:" in result # pic1
|
||||
assert "Abbildung E-5.2.2:" in result # photo1
|
||||
assert "Tabelle E-5.2.3:" in result # tab1
|
||||
assert "Abbildung E-5.2.4:" in result # pic2
|
||||
assert "Figur E-5.2.1:" in result # pic1
|
||||
assert "Figur E-5.2.2:" in result # photo1
|
||||
assert "Tabell E-5.2.3:" in result # tab1
|
||||
assert "Figur E-5.2.4:" in result # pic2
|
||||
|
||||
|
||||
@pytest.mark.slide
|
||||
@@ -139,7 +139,7 @@ Reference: [ref:pic1]
|
||||
|
||||
result = renderer.render(Document(markdown_text))
|
||||
|
||||
assert "Abbildung ES-2.1.1:" in result
|
||||
assert "Figur ES-2.1.1:" in result
|
||||
assert ">ES-2.1.1</a>" in result
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ Reference: [ref:pic1]
|
||||
result = renderer.render(Document(markdown_text))
|
||||
|
||||
# Falls back to the bare counter.
|
||||
assert "Abbildung 1:" in result
|
||||
assert "Figur 1:" in result
|
||||
assert ">1</a>" in result
|
||||
|
||||
|
||||
@@ -192,5 +192,5 @@ def test_table_without_name_not_numbered():
|
||||
|
||||
result = renderer.render(doc)
|
||||
|
||||
assert "Abbildung E-1.1.1:" in result
|
||||
assert "Tabelle" not in result
|
||||
assert "Figur E-1.1.1:" in result
|
||||
assert "Tabell" not in result
|
||||
|
||||
@@ -10,13 +10,13 @@ from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
|
||||
conf = config.Config()
|
||||
|
||||
|
||||
def parse_katalog():
|
||||
with open(conf.p_data_fragenkatalog) as fragenkatalog_file:
|
||||
fragenkatalog = json.load(fragenkatalog_file)
|
||||
def parse_question_pool():
|
||||
with open(conf.p_data_question_pool) as question_pool_file:
|
||||
question_pool = json.load(question_pool_file)
|
||||
|
||||
questions = {}
|
||||
|
||||
for exampart in fragenkatalog["sections"]:
|
||||
for exampart in question_pool["sections"]:
|
||||
for chapter in exampart["sections"]:
|
||||
if "questions" in chapter:
|
||||
for question in chapter["questions"]:
|
||||
@@ -34,8 +34,8 @@ question_template = env.get_template("question.html")
|
||||
|
||||
|
||||
def question_stub(number):
|
||||
questions = parse_katalog()
|
||||
"""Combines the original question dataset from BNetzA with our internal metadata"""
|
||||
questions = parse_question_pool()
|
||||
"""Combines the question pool with our internal metadata"""
|
||||
with open(conf.p_data_metadata) as metadata_file:
|
||||
metadata = json.load(metadata_file)
|
||||
question = questions[number]
|
||||
|
||||
@@ -11,13 +11,13 @@ from renderer.fifty_ohm_html_slide_renderer import FiftyOhmHtmlSlideRenderer
|
||||
conf = config.Config()
|
||||
|
||||
|
||||
def parse_katalog():
|
||||
with open(conf.p_data_fragenkatalog) as fragenkatalog_file:
|
||||
fragenkatalog = json.load(fragenkatalog_file)
|
||||
def parse_question_pool():
|
||||
with open(conf.p_data_question_pool) as question_pool_file:
|
||||
question_pool = json.load(question_pool_file)
|
||||
|
||||
questions = {}
|
||||
|
||||
for exampart in fragenkatalog["sections"]:
|
||||
for exampart in question_pool["sections"]:
|
||||
for chapter in exampart["sections"]:
|
||||
if "questions" in chapter:
|
||||
for question in chapter["questions"]:
|
||||
@@ -47,8 +47,8 @@ def filter_shuffle_answers(seq):
|
||||
|
||||
|
||||
def question_stub(number):
|
||||
questions = parse_katalog()
|
||||
"""Combines the original question dataset from BNetzA with our internal metadata"""
|
||||
questions = parse_question_pool()
|
||||
"""Combines the question pool with our internal metadata"""
|
||||
with open(conf.p_data_metadata) as metadata_file:
|
||||
metadata = json.load(metadata_file)
|
||||
question = questions[number]
|
||||
|
||||
@@ -17,3 +17,17 @@ def test_morse_html():
|
||||
|
||||
for assertion in assertions:
|
||||
assert render_html(assertion) == paragraph(assertions[assertion])
|
||||
|
||||
|
||||
@pytest.mark.html
|
||||
def test_swedish_letters_morse_html():
|
||||
# Å .--.- Ä .-.- Ö ---.
|
||||
assertions = {
|
||||
"[morse: å]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2, 2, 1, 2]]),
|
||||
"[morse: ä]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2, 1, 2]]),
|
||||
"[morse: ö]": FiftyOhmHtmlRenderer.render_morse_helper([[2, 2, 2, 1]]),
|
||||
"[morse: Å]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2, 2, 1, 2]]),
|
||||
}
|
||||
|
||||
for assertion in assertions:
|
||||
assert render_html(assertion) == paragraph(assertions[assertion])
|
||||
|
||||
@@ -7,8 +7,8 @@ from test.util import paragraph, render_html
|
||||
|
||||
@pytest.mark.html
|
||||
def test_paragraph_html():
|
||||
input = "Der Test befindet sich unter §2 vielleicht aber auch § 3."
|
||||
target = "Der Test befindet sich unter § 2 vielleicht aber auch § 3."
|
||||
input = "Se 2§ och kanske även 3 §."
|
||||
target = "Se 2 § och kanske även 3 §."
|
||||
|
||||
assert render_html(input) == paragraph(target)
|
||||
|
||||
@@ -16,7 +16,7 @@ def test_paragraph_html():
|
||||
@pytest.mark.html
|
||||
def test_three_points_html():
|
||||
assertions = {
|
||||
"Heute hatte ich ... zum Mittagessen.": "Heute hatte ich ... zum Mittagessen.",
|
||||
"Idag åt jag ... till lunch.": "Idag åt jag ... till lunch.",
|
||||
"Niemals hätte ich gedacht, dass...ich ...nicht kann.": "Niemals hätte ich gedacht, dass...ich ...nicht kann.", # noqa: E501
|
||||
"Oh nein ...ein Pinguin.": "Oh nein ...ein Pinguin.",
|
||||
"Haha .. . Hahaha": "Haha .. . Hahaha",
|
||||
@@ -27,25 +27,17 @@ def test_three_points_html():
|
||||
|
||||
|
||||
@pytest.mark.html
|
||||
def test_absatz_html():
|
||||
input = "Der Test befindet sich unter Abs.2 vielleicht aber auch Abs. 3."
|
||||
target = "Der Test befindet sich unter Abs. 2 vielleicht aber auch Abs. 3."
|
||||
|
||||
assert render_html(input) == paragraph(target)
|
||||
|
||||
|
||||
@pytest.mark.html
|
||||
def test_class_html():
|
||||
input = "Ich lerne für Klasse A, Klasse E und Klasse N."
|
||||
target = "Ich lerne für Klasse A, Klasse E und Klasse N."
|
||||
def test_chapter_and_ptsfs_html():
|
||||
input = "Se 3 kap. 2 § och 4 st. samt PTSFS 2025:1 och Report 89."
|
||||
target = "Se 3 kap. 2 § och 4 st. samt PTSFS 2025:1 och Report 89."
|
||||
|
||||
assert render_html(input) == paragraph(target)
|
||||
|
||||
|
||||
@pytest.mark.latex
|
||||
def test_paragraph_latex():
|
||||
input = "Der Test befindet sich unter §2 vielleicht aber auch § 3."
|
||||
target = "\nDer Test befindet sich unter §~2 vielleicht aber auch §~3.\n"
|
||||
input = "Se 2§ och kanske även 3 §."
|
||||
target = "\nSe 2~§ och kanske även 3~§.\n"
|
||||
|
||||
assert mistletoe.markdown(input, FiftyOhmLaTeXRenderer) == target
|
||||
|
||||
@@ -53,7 +45,7 @@ def test_paragraph_latex():
|
||||
@pytest.mark.latex
|
||||
def test_three_points_latex():
|
||||
assertions = {
|
||||
"Heute hatte ich ... zum Mittagessen.": "\nHeute hatte ich~...~zum Mittagessen.\n",
|
||||
"Idag åt jag ... till lunch.": "\nIdag åt jag~...~till lunch.\n",
|
||||
"Niemals hätte ich gedacht, dass...ich ...nicht kann.": "\nNiemals hätte ich gedacht, dass...ich~...nicht kann.\n", # noqa: E501
|
||||
"Oh nein ...ein Pinguin.": "\nOh nein~...ein Pinguin.\n",
|
||||
"Haha .. . Hahaha": "\nHaha .. . Hahaha\n",
|
||||
@@ -64,16 +56,8 @@ def test_three_points_latex():
|
||||
|
||||
|
||||
@pytest.mark.latex
|
||||
def test_absatz_latex():
|
||||
input = "Der Test befindet sich unter Abs.2 vielleicht aber auch Abs. 3."
|
||||
target = "\nDer Test befindet sich unter Abs.~2 vielleicht aber auch Abs.~3.\n"
|
||||
|
||||
assert mistletoe.markdown(input, FiftyOhmLaTeXRenderer) == target
|
||||
|
||||
|
||||
@pytest.mark.latex
|
||||
def test_class_latex():
|
||||
input = "Ich lerne für Klasse A, Klasse E und Klasse N."
|
||||
target = "\nIch lerne für Klasse~A, Klasse~E und Klasse~N.\n"
|
||||
def test_chapter_and_ptsfs_latex():
|
||||
input = "Se 3 kap. 2 § och 4 st. samt PTSFS 2025:1 och Report 89."
|
||||
target = "\nSe 3~kap. 2~§ och 4~st. samt PTSFS~2025:1 och Report~89.\n"
|
||||
|
||||
assert mistletoe.markdown(input, FiftyOhmLaTeXRenderer) == target
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import json
|
||||
|
||||
from src.build import Build
|
||||
from src.config import Config
|
||||
from src.edition import Edition
|
||||
|
||||
|
||||
def write_pool(path, number):
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"sections": [
|
||||
{
|
||||
"title": f"Pool {number}",
|
||||
"questions": [
|
||||
{
|
||||
"number": number,
|
||||
"question": f"Fråga {number}",
|
||||
"answer_a": "A",
|
||||
"answer_b": "B",
|
||||
"answer_c": "C",
|
||||
"answer_d": "D",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def write_toc(tmp_path, edition, section_content):
|
||||
(tmp_path / "toc").mkdir(exist_ok=True)
|
||||
(tmp_path / "contents" / "sections").mkdir(parents=True, exist_ok=True)
|
||||
(tmp_path / "contents" / "sections" / "intro.md").write_text(section_content, encoding="utf-8")
|
||||
(tmp_path / "toc" / f"{edition}.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"title": "Instegskurs",
|
||||
"edition": str(edition),
|
||||
"chapters": [
|
||||
{
|
||||
"title": "Inledning",
|
||||
"ident": "inledning",
|
||||
"sections": [{"title": "Välkommen", "ident": "intro"}],
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def test_editions():
|
||||
assert [str(edition) for edition in Edition] == ["INSTEG", "HAREC", "UPPGRADERING"]
|
||||
|
||||
|
||||
def test_build_without_question_pool(tmp_path):
|
||||
write_toc(tmp_path, Edition.instegs, "Hej [question:SE101]")
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
assert not build.has_question_pool
|
||||
build.build_website()
|
||||
build.build_edition(Edition.instegs)
|
||||
build.build_solutions()
|
||||
build.build_question_index()
|
||||
|
||||
out = tmp_path / "build"
|
||||
assert (out / "index.html").exists()
|
||||
assert (out / "INSTEG_course_index.html").exists()
|
||||
assert (out / "INSTEG_intro.html").exists()
|
||||
assert not (out / "simulering.html").exists()
|
||||
assert not (out / "ovning.html").exists()
|
||||
assert not (tmp_path / "build" / "assets" / "question_index.json").exists()
|
||||
assert 'lang="sv"' in (out / "index.html").read_text(encoding="utf-8")
|
||||
assert "simulering.html" not in (out / "index.html").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_build_with_question_pool_and_default_metadata(tmp_path):
|
||||
questions = tmp_path / "contents" / "questions"
|
||||
questions.mkdir(parents=True)
|
||||
write_pool(questions / "question_pool.json", "SE101")
|
||||
write_toc(tmp_path, Edition.instegs, "[question:SE101]")
|
||||
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
assert build.has_question_pool
|
||||
assert set(build.questions) == {"SE101"}
|
||||
build.build_website()
|
||||
build.build_edition(Edition.instegs)
|
||||
build.build_question_index()
|
||||
|
||||
out = tmp_path / "build"
|
||||
assert (out / "simulering.html").exists()
|
||||
assert (out / "ovning.html").exists()
|
||||
assert "Fråga SE101" in (out / "INSTEG_intro.html").read_text(encoding="utf-8")
|
||||
assert json.loads((out / "assets" / "question_index.json").read_text(encoding="utf-8"))["SE101"]["editions"] == [
|
||||
"INSTEG"
|
||||
]
|
||||
@@ -8,11 +8,11 @@ from test.util import paragraph, render_html
|
||||
@pytest.mark.html
|
||||
def test_quote_html():
|
||||
assertions = {
|
||||
'"quote"': "„quote“",
|
||||
'" quote "': "„ quote “",
|
||||
'"quote" "': '„quote“ "',
|
||||
'"quo te1" filltext "qu ot e2"': "„quo te1“ filltext „qu ot e2“",
|
||||
'"quo *te1*" filltext "qu ot e2"': "„quo <em>te1</em>“ filltext „qu ot e2“",
|
||||
'"quote"': "”quote”",
|
||||
'" quote "': "” quote ”",
|
||||
'"quote" "': '”quote” "',
|
||||
'"quo te1" filltext "qu ot e2"': "”quo te1” filltext ”qu ot e2”",
|
||||
'"quo *te1*" filltext "qu ot e2"': "”quo <em>te1</em>” filltext ”qu ot e2”",
|
||||
'""': '""',
|
||||
}
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
import json
|
||||
|
||||
from src.build import Build
|
||||
from src.config import Config
|
||||
|
||||
|
||||
def write_catalog(path, number):
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"sections": [
|
||||
{
|
||||
"title": f"Katalog {number}",
|
||||
"questions": [
|
||||
{
|
||||
"number": number,
|
||||
"class": "SWL" if number.startswith("SWL") else "1",
|
||||
"question": f"Frage {number}",
|
||||
"answer_a": "A",
|
||||
"answer_b": "B",
|
||||
"answer_c": "C",
|
||||
"answer_d": "D",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def prepare_content(tmp_path, include_swl):
|
||||
questions_path = tmp_path / "contents" / "questions"
|
||||
questions_path.mkdir(parents=True)
|
||||
write_catalog(questions_path / "fragenkatalog3b.json", "NA101")
|
||||
(questions_path / "metadata3b.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"NA101": {
|
||||
"directus_id": "1",
|
||||
"picture_question": "",
|
||||
"picture_a": "",
|
||||
"picture_b": "",
|
||||
"picture_c": "",
|
||||
"picture_d": "",
|
||||
"layout": "",
|
||||
}
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
if include_swl:
|
||||
write_catalog(questions_path / "fragenkatalog_swl.json", "SWL001")
|
||||
|
||||
|
||||
def test_optional_swl_catalog_is_loaded_with_default_metadata(tmp_path):
|
||||
prepare_content(tmp_path, include_swl=True)
|
||||
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
assert set(build.questions) == {"NA101", "SWL001"}
|
||||
assert build.question_metadata["SWL001"]["layout"] == ""
|
||||
assert len(build.fragenkatalog["sections"]) == 2
|
||||
|
||||
|
||||
def test_missing_optional_swl_catalog_is_allowed(tmp_path):
|
||||
prepare_content(tmp_path, include_swl=False)
|
||||
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
assert set(build.questions) == {"NA101"}
|
||||
assert len(build.fragenkatalog["sections"]) == 1
|
||||
|
||||
|
||||
def test_lowercase_swl_toc_is_supported(tmp_path):
|
||||
prepare_content(tmp_path, include_swl=True)
|
||||
toc_path = tmp_path / "toc"
|
||||
section_path = tmp_path / "contents" / "sections"
|
||||
toc_path.mkdir()
|
||||
section_path.mkdir()
|
||||
(section_path / "swl_intro.md").write_text("Einführung", encoding="utf-8")
|
||||
(toc_path / "swl.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"title": "SWL-Kurs",
|
||||
"edition": "SWL",
|
||||
"chapters": [
|
||||
{
|
||||
"title": "Einstieg",
|
||||
"ident": "swl_einstieg",
|
||||
"sections": [{"title": "Einführung", "ident": "swl_intro"}],
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
build.build_edition("SWL")
|
||||
assert (tmp_path / "build" / "SWL_course_index.html").exists()
|
||||
assert (tmp_path / "build" / "SWL_swl_intro.html").exists()
|
||||
|
||||
|
||||
def test_regular_course_location_takes_precedence_for_shared_swl_question(tmp_path):
|
||||
prepare_content(tmp_path, include_swl=True)
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
build._Build__collect_question_occurrences(
|
||||
"SWL",
|
||||
"SWL-Kapitel",
|
||||
"swl_buchstabieralphabet",
|
||||
"SWL-Buchstabieralphabet",
|
||||
"[question:NA101]",
|
||||
)
|
||||
build._Build__collect_question_occurrences(
|
||||
"N",
|
||||
"Erste Schritte",
|
||||
"buchstabiertafel",
|
||||
"Internationale Buchstabiertafel",
|
||||
"[question:NA101]",
|
||||
)
|
||||
|
||||
assert build.question_index["NA101"] == {
|
||||
"has_solution": False,
|
||||
"section": "buchstabiertafel",
|
||||
"chapter_title": "Erste Schritte",
|
||||
"section_title": "Internationale Buchstabiertafel",
|
||||
"editions": ["SWL", "N"],
|
||||
}
|
||||
|
||||
|
||||
def test_pure_swl_question_keeps_its_swl_location(tmp_path):
|
||||
prepare_content(tmp_path, include_swl=True)
|
||||
build = Build(Config(content_path=tmp_path, build_path=tmp_path / "build"))
|
||||
|
||||
build._Build__collect_question_occurrences(
|
||||
"SWL",
|
||||
"SWL-Kapitel",
|
||||
"swl_eigene_fragen",
|
||||
"SWL-Fragen",
|
||||
"[question:SWL001]",
|
||||
)
|
||||
|
||||
assert build.question_index["SWL001"]["section"] == "swl_eigene_fragen"
|
||||
assert build.question_index["SWL001"]["editions"] == ["SWL"]
|
||||
@@ -15,7 +15,7 @@ def test_table_html():
|
||||
"| l: a |\n| b |\n| c |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n<tr>\n<td style="text-align: left;">c</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
|
||||
"| a |\n| b |\n| c |": '<table class="table table-hover">\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
|
||||
"| l: a |\n| *b* |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;"><em>b</em></td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
|
||||
"| l: a |\n| b |\n[table:n_ab:A und B]": '<table class="table table-hover" id="ref_n_ab" name="n_ab">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n</tbody>\n<caption>Tabelle 1: A und B</caption>\n</table>\n', # noqa: E501
|
||||
"| l: a |\n| b |\n[table:n_ab:A och B]": '<table class="table table-hover" id="ref_n_ab" name="n_ab">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">b</td>\n</tr>\n</tbody>\n<caption>Tabell 1: A och B</caption>\n</table>\n', # noqa: E501
|
||||
"| l: *a* |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;"><em>a</em></th>\n</tr>\n</thead>\n</table>\n', # noqa: E501
|
||||
"| l: a |\n| [morse:a] |": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;"><span class="morse"><span class="morse_char">\n<span class="morse_symbol">\n▄</span>\n<span class="morse_symbol">\n▄▄▄</span>\n</span>\n</span></td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
|
||||
"| l: abc | r: abc | X: abc |\n| 123 | 456 | 789 | \n | 987 | 654 | 321 | ": '<table class="table table-hover">\n<thead>\n<tr>\n<th style="text-align: left;">abc</th>\n<th style="text-align: right;">abc</th>\n<th>abc</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style="text-align: left;">123</td>\n<td style="text-align: right;">456</td>\n<td>789</td>\n</tr>\n<tr>\n<td style="text-align: left;">987</td>\n<td style="text-align: right;">654</td>\n<td>321</td>\n</tr>\n</tbody>\n</table>\n', # noqa: E501
|
||||
|
||||
@@ -14,7 +14,7 @@ def test_basic_units_html():
|
||||
"1 Ah": "1 Ah",
|
||||
"10 A/mm²": "10 A/mm²",
|
||||
"DL9MJ": "DL9MJ", # Ensure other strings, like callsings, aren‘t mistaken for units. ;)
|
||||
"Ein Satz mit 200 V.": "Ein Satz mit 200 V.", # Support units before sentence ends.
|
||||
"En mening med 200 V.": "En mening med 200 V.", # Support units before sentence ends.
|
||||
}
|
||||
|
||||
for input, output in assertions.items():
|
||||
@@ -35,10 +35,10 @@ def test_translated_units_html():
|
||||
|
||||
@pytest.mark.html
|
||||
def test_special_units_html():
|
||||
"""Test special units: Don't put space before ° and %."""
|
||||
"""Test special units: Don't put space before °; % gets a thin space (Swedish convention)."""
|
||||
assertions = {
|
||||
"100%": "100%",
|
||||
"100 %": "100%",
|
||||
"100%": "100 %",
|
||||
"100 %": "100 %",
|
||||
"42,24°": "42,24°",
|
||||
}
|
||||
|
||||
|
||||