Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python" (Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch Version_03 (eingefroren) verwaltet und Version_04/ ignoriert. Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist. Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise, 325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren, 25 Notebooks, PDF mit 715 Seiten. Zusaetzlich in diesem Commit: * pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api, figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt unveraendert daneben bestehen. ortools steht in der Grundausstattung, highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der schlanken Installation gar nicht erst auftreten. * Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo steht in requirements.txt, wird aber von keinem Programm importiert, sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in [empfehlungen]). * NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen. * PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den tatsaechlichen aus erzeuge_titelseite.py korrigiert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
b7af2f1d9a
468 changed files with 262141 additions and 0 deletions
225
OR_HTML_04/assets/highlight.css
Normal file
225
OR_HTML_04/assets/highlight.css
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
{
|
||||
"text-color": "#cfcfc2",
|
||||
"background-color": "#232629",
|
||||
"line-number-color": "#7a7c7d",
|
||||
"line-number-background-color": "#232629",
|
||||
"text-styles": {
|
||||
"Alert": {
|
||||
"text-color": "#95da4c",
|
||||
"background-color": "#4d1f24",
|
||||
"bold": true,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Annotation": {
|
||||
"text-color": "#3f8058",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Attribute": {
|
||||
"text-color": "#2980b9",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"BaseN": {
|
||||
"text-color": "#f67400",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"BuiltIn": {
|
||||
"text-color": "#7f8c8d",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Char": {
|
||||
"text-color": "#3daee9",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Comment": {
|
||||
"text-color": "#7a7c7d",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"CommentVar": {
|
||||
"text-color": "#7f8c8d",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Constant": {
|
||||
"text-color": "#27aeae",
|
||||
"background-color": null,
|
||||
"bold": true,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"ControlFlow": {
|
||||
"text-color": "#fdbc4b",
|
||||
"background-color": null,
|
||||
"bold": true,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"DataType": {
|
||||
"text-color": "#2980b9",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"DecVal": {
|
||||
"text-color": "#f67400",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Documentation": {
|
||||
"text-color": "#a43340",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Error": {
|
||||
"text-color": "#da4453",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": true
|
||||
},
|
||||
"Extension": {
|
||||
"text-color": "#0099ff",
|
||||
"background-color": null,
|
||||
"bold": true,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Float": {
|
||||
"text-color": "#f67400",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Function": {
|
||||
"text-color": "#8e44ad",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Import": {
|
||||
"text-color": "#27ae60",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Information": {
|
||||
"text-color": "#c45b00",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Keyword": {
|
||||
"text-color": "#cfcfc2",
|
||||
"background-color": null,
|
||||
"bold": true,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Normal": {
|
||||
"text-color": "#cfcfc2",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Operator": {
|
||||
"text-color": "#cfcfc2",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Other": {
|
||||
"text-color": "#27ae60",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Preprocessor": {
|
||||
"text-color": "#27ae60",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"RegionMarker": {
|
||||
"text-color": "#2980b9",
|
||||
"background-color": "#153042",
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"SpecialChar": {
|
||||
"text-color": "#3daee9",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"SpecialString": {
|
||||
"text-color": "#da4453",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"String": {
|
||||
"text-color": "#f44f4f",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Variable": {
|
||||
"text-color": "#27aeae",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"VerbatimString": {
|
||||
"text-color": "#da4453",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
},
|
||||
"Warning": {
|
||||
"text-color": "#da4453",
|
||||
"background-color": null,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"underline": false
|
||||
}
|
||||
}
|
||||
}
|
||||
41
OR_HTML_04/assets/icons.svg
Normal file
41
OR_HTML_04/assets/icons.svg
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
|
||||
<symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||||
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
|
||||
</symbol>
|
||||
<symbol id="icon-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||||
<circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.2" y2="16.2"/>
|
||||
</symbol>
|
||||
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||||
<circle cx="12" cy="12" r="4.5"/>
|
||||
<line x1="12" y1="1.5" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22.5"/>
|
||||
<line x1="1.5" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22.5" y2="12"/>
|
||||
<line x1="4.5" y1="4.5" x2="6.2" y2="6.2"/><line x1="17.8" y1="17.8" x2="19.5" y2="19.5"/>
|
||||
<line x1="19.5" y1="4.5" x2="17.8" y2="6.2"/><line x1="6.2" y1="17.8" x2="4.5" y2="19.5"/>
|
||||
</symbol>
|
||||
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z"/>
|
||||
</symbol>
|
||||
<symbol id="icon-chevron-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="15 4 7 12 15 20"/>
|
||||
</symbol>
|
||||
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="9 4 17 12 9 20"/>
|
||||
</symbol>
|
||||
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="4 13 9.5 18.5 20 6"/>
|
||||
</symbol>
|
||||
<symbol id="icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5"/>
|
||||
<polyline points="14.5 3.5 20.5 3.5 20.5 9.5"/><line x1="11" y1="13" x2="20" y2="4"/>
|
||||
</symbol>
|
||||
<symbol id="icon-book" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z"/>
|
||||
<path d="M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z"/>
|
||||
</symbol>
|
||||
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
||||
</symbol>
|
||||
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 19.5h16"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3 KiB |
3882
OR_HTML_04/assets/plotly.min.js
vendored
Normal file
3882
OR_HTML_04/assets/plotly.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
OR_HTML_04/assets/programme.js
Normal file
1
OR_HTML_04/assets/programme.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
window.OR_PROGRAMME = ["Backtest_Fallen.py", "Bausteine_Vorlage.py", "Bellman_Minimalbeispiel.py", "Benchmark_Skalierung.py", "Betriebsueberwachung.py", "Big_M_Falle.py", "Bot_Allokation.py", "Brute_Force_Vergleich.py", "CP_SAT_Statusfaelle.py", "CP_SAT_Vertretungssystem.py", "CVaR_Portfolio.py", "Data_Snooping.py", "Diversifikation_Demo.py", "Dualitaet_Nachweis.py", "Ein_System_Vier_Ansaetze.py", "Entropie_Maximierte_Allokation.py", "Erklaerbarkeit.py", "Excel_Bruecke.py", "Finanzdaten_Ledoit_Wolf.py", "Fluch_des_Durchschnitts.py", "Infeasibility_Diagnose.py", "Installationstest.py", "JobShop_Intervalle.py", "KKT_Nachweis.py", "Konfliktsuche.py", "Konvexitaet_Demo.py", "Kovarianz_Falle.py", "Kraftwerkseinsatz.py", "Large_Neighborhood_Search.py", "Lokale_Optima_Multistart.py", "MILP_Portfolio_Fixgebuehren.py", "Markowitz_CVXPY.py", "Matrixform.py", "Mehrperiodige_Order_Execution.py", "Mehrziel_Pareto.py", "Metaheuristik_vs_Exakt.py", "Min_Cost_Flow.py", "Modellierungsschichten.py", "Monte_Carlo.py", "Mutationstest.py", "Optimierungsdienst.py", "Predict_then_Optimize.py", "Propagation_Demo.py", "QP_Grundlagen.py", "QuantitativeTradingEngine.py", "Renditen_Vergleich.py", "Renditeschaetzung_Falle.py", "Robuste_Optimierung.py", "Rucksack.py", "Runden_Gegenbeispiel.py", "Schaetzrauschen_Demo.py", "Sensitivitaetsanalyse.py", "Simplex_Tableau_LP.py", "Simulated_Annealing.py", "Skalierung_Kondition.py", "Solver_Wahl.py", "Solverstatus_und_Gap.py", "Solverwechsel_CPSAT_HiGHS.py", "Spaltengenerierung.py", "Stochastische_Optimierung.py", "Strafgewichte.py", "Strukturbruecke.py", "Toleranzen_und_Entartung.py", "VRP_Flotten_Routing.py", "VRP_Kapazitaetsfalle.py", "VaR_CVaR_Demo.py", "Vektorisierte_Modellgenerierung.py", "Visualisierung_Loesungsraum.py", "Vom_Wunsch_zum_Modell.py", "Warmstart_Effekt.py", "Zuordnung_Ungarisch.py", "or_kern.py", "test_or_kern.py"];
|
||||
1
OR_HTML_04/assets/search-index.js
Normal file
1
OR_HTML_04/assets/search-index.js
Normal file
File diff suppressed because one or more lines are too long
346
OR_HTML_04/assets/site.css
Normal file
346
OR_HTML_04/assets/site.css
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/* site.css — Design-System der Mehrseiten-Website "Operations Research mit
|
||||
Python". Struktur (CSS-Variablen, .dark-Umschaltung, kuehle Graustufen)
|
||||
nach dem Vorbild https://jamulix.de/sorting/, Farben aus der bestehenden
|
||||
Buchpalette (Titelseite/PDF: Indigo/Cyan/Violett/Gruen/Amber). */
|
||||
|
||||
:root {
|
||||
--bg: #f5f6fa;
|
||||
--surface: #ffffff;
|
||||
--surface2: #eef0f5;
|
||||
--border: #d9dce6;
|
||||
--text: #1a1a2e;
|
||||
--muted: #5c6380;
|
||||
--accent: #4338ca;
|
||||
--accent-text: #ffffff;
|
||||
--cyan: #0891b2;
|
||||
--violett: #7c3aed;
|
||||
--emerald: #059669;
|
||||
--amber: #b45309;
|
||||
--rose: #e11d48;
|
||||
--tint-indigo: #eef2ff;
|
||||
--tint-violett: #f5f3ff;
|
||||
--tint-cyan: #ecfeff;
|
||||
--tint-emerald: #ecfdf5;
|
||||
--tint-amber: #fffbeb;
|
||||
--code-bg: #1e293b;
|
||||
--code-text: #e6edf3;
|
||||
--shadow: 0 2px 10px rgba(26, 26, 46, .07);
|
||||
--shadow-lg: 0 8px 30px rgba(26, 26, 46, .12);
|
||||
--radius: 12px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--bg: #0e0f1a;
|
||||
--surface: #161826;
|
||||
--surface2: #1e2133;
|
||||
--border: #2b2f45;
|
||||
--text: #e7e9f5;
|
||||
--muted: #9aa1c4;
|
||||
--accent: #818cf8;
|
||||
--accent-text: #0e0f1a;
|
||||
--cyan: #22d3ee;
|
||||
--violett: #c4b5fd;
|
||||
--emerald: #34d399;
|
||||
--amber: #fbbf24;
|
||||
--rose: #fb7185;
|
||||
--tint-indigo: #1b1f3a;
|
||||
--tint-violett: #241f3d;
|
||||
--tint-cyan: #132833;
|
||||
--tint-emerald: #10291f;
|
||||
--tint-amber: #2c2410;
|
||||
--code-bg: #0b0d14;
|
||||
--code-text: #dbe4f0;
|
||||
--shadow: 0 2px 10px rgba(0, 0, 0, .35);
|
||||
--shadow-lg: 0 8px 30px rgba(0, 0, 0, .5);
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
--bg: #0e0f1a;
|
||||
--surface: #161826;
|
||||
--surface2: #1e2133;
|
||||
--border: #2b2f45;
|
||||
--text: #e7e9f5;
|
||||
--muted: #9aa1c4;
|
||||
--accent: #818cf8;
|
||||
--accent-text: #0e0f1a;
|
||||
--cyan: #22d3ee;
|
||||
--violett: #c4b5fd;
|
||||
--emerald: #34d399;
|
||||
--amber: #fbbf24;
|
||||
--rose: #fb7185;
|
||||
--tint-indigo: #1b1f3a;
|
||||
--tint-violett: #241f3d;
|
||||
--tint-cyan: #132833;
|
||||
--tint-emerald: #10291f;
|
||||
--tint-amber: #2c2410;
|
||||
--code-bg: #0b0d14;
|
||||
--code-text: #dbe4f0;
|
||||
--shadow: 0 2px 10px rgba(0, 0, 0, .35);
|
||||
--shadow-lg: 0 8px 30px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; }
|
||||
body {
|
||||
margin: 0; background: var(--bg); color: var(--text);
|
||||
font-family: "Segoe UI", -apple-system, BlinkMacSystemFont, "DejaVu Sans", Arial, sans-serif;
|
||||
line-height: 1.7; font-size: 16px; -webkit-text-size-adjust: 100%;
|
||||
}
|
||||
.icon { width: 1.15em; height: 1.15em; flex: none; vertical-align: -.2em; }
|
||||
|
||||
/* --- Kopfzeile --- */
|
||||
.site-header {
|
||||
position: sticky; top: 0; z-index: 30; display: flex; align-items: center;
|
||||
gap: .75rem; padding: .6rem 1rem; background: var(--surface);
|
||||
border-bottom: 1px solid var(--border); box-shadow: var(--shadow);
|
||||
}
|
||||
.icon-btn {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
width: 2.2rem; height: 2.2rem; border-radius: 8px; border: 1px solid transparent;
|
||||
background: transparent; color: var(--text); cursor: pointer;
|
||||
}
|
||||
.icon-btn:hover { background: var(--surface2); border-color: var(--border); }
|
||||
.brand {
|
||||
display: flex; align-items: center; gap: .5rem; color: var(--accent);
|
||||
font-weight: 700; text-decoration: none; white-space: nowrap;
|
||||
}
|
||||
.brand span { display: none; }
|
||||
@media (min-width: 900px) { .brand span { display: inline; } }
|
||||
.site-search { position: relative; flex: 1; max-width: 420px; margin: 0 auto; }
|
||||
.site-search input {
|
||||
width: 100%; padding: .5rem .8rem .5rem 2.2rem; border-radius: 20px;
|
||||
border: 1px solid var(--border); background: var(--surface2); color: var(--text);
|
||||
font-size: .92rem;
|
||||
}
|
||||
.site-search input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
|
||||
.such-icon { position: absolute; left: .7rem; top: 50%; transform: translateY(-50%); color: var(--muted); }
|
||||
.suche-ergebnisse {
|
||||
position: absolute; top: calc(100% + .4rem); left: 0; right: 0; max-height: 60vh;
|
||||
overflow-y: auto; background: var(--surface); border: 1px solid var(--border);
|
||||
border-radius: var(--radius); box-shadow: var(--shadow-lg); z-index: 40;
|
||||
}
|
||||
.suche-ergebnisse a {
|
||||
display: block; padding: .55rem .9rem; color: var(--text); text-decoration: none;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.suche-ergebnisse a:last-child { border-bottom: none; }
|
||||
.suche-ergebnisse a:hover, .suche-ergebnisse a.aktiv { background: var(--tint-indigo); }
|
||||
.suche-ergebnisse small { display: block; color: var(--muted); font-weight: 400; }
|
||||
.suche-leer { padding: .8rem .9rem; color: var(--muted); }
|
||||
#theme-toggle .icon-moon { display: none; }
|
||||
:root[data-theme="dark"] #theme-toggle .icon-sun { display: none; }
|
||||
:root[data-theme="dark"] #theme-toggle .icon-moon { display: inline; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) #theme-toggle .icon-sun { display: none; }
|
||||
:root:not([data-theme="light"]) #theme-toggle .icon-moon { display: inline; }
|
||||
}
|
||||
|
||||
/* --- Layout: Sidebar + Inhalt --- */
|
||||
.site-body { display: flex; align-items: flex-start; max-width: 1400px; margin: 0 auto; }
|
||||
.sidebar {
|
||||
position: sticky; top: 3.6rem; width: 290px; flex: none;
|
||||
height: calc(100vh - 3.6rem); overflow-y: auto; border-right: 1px solid var(--border);
|
||||
background: var(--surface); padding: 1rem 0;
|
||||
}
|
||||
.sidebar-gruppe { border-bottom: 1px solid var(--border); }
|
||||
.sidebar-gruppe summary {
|
||||
cursor: pointer; padding: .6rem 1rem; font-weight: 700; color: var(--accent);
|
||||
list-style: none; display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.sidebar-gruppe summary::-webkit-details-marker { display: none; }
|
||||
.sidebar-gruppe summary::after { content: "▾"; color: var(--muted); font-size: .8em; }
|
||||
.sidebar-gruppe[open] summary::after { content: "▴"; }
|
||||
.sidebar ul { list-style: none; margin: 0; padding: 0 .5rem .5rem; }
|
||||
.sidebar li a {
|
||||
display: flex; align-items: center; gap: .5rem; padding: .4rem .6rem;
|
||||
border-radius: 8px; color: var(--text); text-decoration: none; font-size: .92rem;
|
||||
}
|
||||
.sidebar li a:hover { background: var(--tint-indigo); }
|
||||
.sidebar li.aktiv a { background: var(--accent); color: var(--accent-text); font-weight: 600; }
|
||||
.fortschritt-haken { width: 1em; height: 1em; color: var(--emerald); visibility: hidden; }
|
||||
.fortschritt-haken .icon { width: 100%; height: 100%; }
|
||||
li[data-erledigt="1"] .fortschritt-haken { visibility: visible; }
|
||||
.sidebar-extra { border-top: 2px solid var(--border); margin-top: .5rem; padding-top: .8rem !important; }
|
||||
.sidebar-overlay { display: none; }
|
||||
|
||||
.content { flex: 1; min-width: 0; padding: 1.5rem 2rem 5rem; max-width: 900px; margin: 0 auto; }
|
||||
|
||||
/* --- Breadcrumb, Prev/Next --- */
|
||||
.breadcrumb { font-size: .85rem; color: var(--muted); margin-bottom: .8rem; }
|
||||
.breadcrumb a { color: var(--muted); }
|
||||
.prev-next { display: flex; justify-content: space-between; gap: 1rem; margin: 1.2rem 0; }
|
||||
.prev-next-knopf {
|
||||
display: flex; align-items: center; gap: .6rem; flex: 1; max-width: 48%;
|
||||
padding: .7rem 1rem; border: 1px solid var(--border); border-radius: var(--radius);
|
||||
background: var(--surface); color: var(--text); text-decoration: none; font-size: .9rem;
|
||||
box-shadow: var(--shadow); transition: border-color .15s, transform .15s;
|
||||
}
|
||||
.prev-next-knopf:hover { border-color: var(--accent); transform: translateY(-1px); }
|
||||
.prev-next-next { margin-left: auto; text-align: right; flex-direction: row-reverse; }
|
||||
.prev-next-knopf small { display: block; color: var(--muted); font-weight: 400; }
|
||||
.prev-next-leer { flex: 1; max-width: 48%; }
|
||||
|
||||
.fortschritt-knopf {
|
||||
display: inline-flex; align-items: center; gap: .5rem; margin: 1rem 0;
|
||||
padding: .55rem 1rem; border-radius: 20px; border: 1px solid var(--border);
|
||||
background: var(--surface2); color: var(--text); cursor: pointer; font: inherit; font-size: .88rem;
|
||||
}
|
||||
.fortschritt-knopf .icon { color: var(--muted); }
|
||||
.fortschritt-knopf.erledigt { background: var(--tint-emerald); border-color: var(--emerald); color: var(--emerald); }
|
||||
.fortschritt-knopf.erledigt .icon { color: var(--emerald); }
|
||||
|
||||
.site-footer { text-align: center; padding: 1.5rem; color: var(--muted); font-size: .85rem; border-top: 1px solid var(--border); }
|
||||
.site-footer a { color: var(--muted); }
|
||||
|
||||
/* --- Typografie im Artikel (angelehnt an bilder/or_html_style.html) --- */
|
||||
article h1, article h2, article h3, article h4, article h5 {
|
||||
line-height: 1.25; font-weight: 700; margin-top: 2.1em; margin-bottom: .6em; scroll-margin-top: 4.5rem;
|
||||
}
|
||||
article h1 { color: var(--accent); font-size: 1.9rem; border-bottom: 3px solid var(--accent); padding-bottom: .25em; }
|
||||
article h2 { color: var(--accent); font-size: 1.45rem; border-bottom: 2px solid var(--border); padding-bottom: .2em; }
|
||||
article h3 { color: var(--cyan); font-size: 1.18rem; }
|
||||
article h4 { color: var(--violett); font-size: 1.05rem; }
|
||||
article h2[id$="-lernziele"]::before { content: "🎯 "; }
|
||||
article h2[id$="-uebungsaufgaben"]::before { content: "📝 "; }
|
||||
article h2[id$="-selbsttest"]::before { content: "✅ "; }
|
||||
article h2[id$="-zusammenfassung"]::before { content: "📌 "; }
|
||||
article a { color: var(--accent); text-decoration: none; }
|
||||
article a:hover { text-decoration: underline; }
|
||||
article a[target="_blank"]::after { content: " \2197"; font-size: .82em; color: var(--cyan); text-decoration: none; }
|
||||
article p { margin: .75em 0; }
|
||||
article hr { border: 0; border-top: 1px solid var(--border); margin: 2.2em 0; }
|
||||
article figure { margin: 2em 0; text-align: center; }
|
||||
article img { max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 10px; }
|
||||
article figure img { box-shadow: var(--shadow-lg); }
|
||||
article figcaption { color: var(--muted); font-size: .9rem; font-style: italic; margin-top: .6em; }
|
||||
article table { border-collapse: collapse; width: 100%; margin: 1.4em 0; font-size: .94rem; box-shadow: var(--shadow); border-radius: 8px; overflow: hidden; }
|
||||
article th { background: var(--accent); color: var(--accent-text); font-weight: 700; text-align: left; }
|
||||
article th, article td { padding: .55em .75em; border: 1px solid var(--border); vertical-align: top; }
|
||||
article tbody tr:nth-child(even) { background: var(--tint-indigo); }
|
||||
article code { font-family: "DejaVu Sans Mono", Consolas, Menlo, monospace; font-size: .9em; background: var(--tint-violett); color: var(--violett); padding: .12em .4em; border-radius: 5px; }
|
||||
article pre { background: var(--code-bg); color: var(--code-text); padding: 1.1em 1.2em; border-radius: 10px; overflow-x: auto; line-height: 1.5; font-size: .85rem; box-shadow: var(--shadow-lg); }
|
||||
article pre code { background: none; color: inherit; padding: 0; font-size: inherit; }
|
||||
article div.sourceCode { position: relative; }
|
||||
article div.sourceCode pre.sourceCode { padding-top: 2.6em; }
|
||||
article blockquote { border-left: 4px solid var(--violett); background: var(--tint-violett); margin: 1.4em 0; padding: .6em 1.2em; border-radius: 0 8px 8px 0; }
|
||||
article ul, article ol { padding-left: 1.4em; }
|
||||
article li { margin: .3em 0; }
|
||||
.katex-display { overflow-x: auto; overflow-y: hidden; padding: .4em 0; }
|
||||
|
||||
/* --- Code-Buttons (Kopieren / Herunterladen) --- */
|
||||
.code-btn-leiste { position: absolute; top: .55em; right: .55em; z-index: 2; display: flex; gap: .4em; }
|
||||
.code-btn, .download-link {
|
||||
display: inline-flex; align-items: center; gap: .35em; background: rgba(255,255,255,.08);
|
||||
color: #cbd5e1; border: 1px solid rgba(255,255,255,.18); border-radius: 6px;
|
||||
padding: .3em .65em; font: inherit; font-size: .78rem; cursor: pointer;
|
||||
text-decoration: none !important; transition: background .15s, color .15s;
|
||||
}
|
||||
.code-btn:hover, .download-link:hover { background: rgba(255,255,255,.18); color: #fff; }
|
||||
.code-btn.copied { background: var(--emerald); color: #fff; border-color: var(--emerald); }
|
||||
.download-link { position: static; margin-left: .6em; }
|
||||
|
||||
/* --- Karten (Kapitel auf einen Blick, Lernpfade, Kapitelraster) --- */
|
||||
.card { border-radius: var(--radius); padding: 1.1em 1.4em; margin: 1.6em 0; box-shadow: var(--shadow); }
|
||||
.card p, .card blockquote { margin: .5em 0 !important; border: none !important; background: none !important; padding: 0 !important; }
|
||||
.card-blick { background: var(--tint-indigo); border: 1px solid var(--accent); }
|
||||
.card-blick blockquote { border-left: 3px solid var(--accent); padding-left: .8em !important; }
|
||||
|
||||
/* --- Didaktische Karten der Version 04 ---------------------------------
|
||||
Jede Kartenart traegt eine eigene Leitfarbe aus der Buchpalette, damit
|
||||
Kursteilnehmer beim Blaettern sofort erkennen, was sie vor sich haben:
|
||||
gruen = sofort ausprobieren, cyan = Formel im Klartext, violett = Excel,
|
||||
amber = Selbstkontrolle, rose = hier steckt ein Fehler drin. Die
|
||||
Leitfarbe liegt links als 5px-Balken, damit sie auch im Ausdruck und in
|
||||
der Druckvorschau erkennbar bleibt. */
|
||||
.card-schnellstart,
|
||||
.card-formel,
|
||||
.card-excel,
|
||||
.card-quiz,
|
||||
.card-denkfehler { border: 1px solid var(--border); border-left-width: 5px; }
|
||||
|
||||
.card-schnellstart { background: var(--tint-emerald); border-left-color: var(--emerald); }
|
||||
.card-formel { background: var(--tint-cyan); border-left-color: var(--cyan); }
|
||||
.card-excel { background: var(--tint-violett); border-left-color: var(--violett); }
|
||||
.card-quiz { background: var(--tint-amber); border-left-color: var(--amber); }
|
||||
.card-denkfehler { background: var(--tint-amber); border-left-color: var(--rose); }
|
||||
|
||||
/* Die Karten enthalten haeufig Tabellen (Formel-Uebersetzer) und
|
||||
Codebloecke (Schnellstart, Denkfehler). Beide sollen sich klar vom
|
||||
getoenten Kartengrund abheben statt darin zu verschwimmen. */
|
||||
.card-schnellstart pre,
|
||||
.card-denkfehler pre { margin: .8em 0 !important; }
|
||||
.card-formel table { margin: .6em 0; background: var(--surface); }
|
||||
.card-formel td:first-child { white-space: nowrap; }
|
||||
|
||||
/* --- Interaktive Plotly-Figuren ---------------------------------------
|
||||
Stehen im Text unmittelbar hinter der statischen Fassung (die im PDF
|
||||
gedruckt wird). Auf schmalen Displays darf die Figur horizontal
|
||||
scrollen, statt die Seite selbst breit zu machen. */
|
||||
.plotly-figur { margin: 1.4em 0; background: var(--surface); border: 1px solid var(--border);
|
||||
border-radius: var(--radius); padding: .6em; overflow-x: auto; }
|
||||
.plotly-figur .plotly-graph-div { min-width: 320px; }
|
||||
|
||||
/* Der Formel-Uebersetzer ist zweispaltig gedacht: links die Mathematik,
|
||||
rechts der Klartext. Auf schmalen Displays wuerde die Formelspalte die
|
||||
Tabelle sonst aus dem Viewport druecken. */
|
||||
@media (max-width: 640px) {
|
||||
.card-formel td:first-child { white-space: normal; }
|
||||
}
|
||||
|
||||
.kartenraster { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1rem; margin: 1rem 0 2rem; }
|
||||
.karte { display: block; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.1rem; box-shadow: var(--shadow); text-decoration: none; color: var(--text); }
|
||||
.karte:hover { border-color: var(--accent); transform: translateY(-2px); transition: transform .15s, border-color .15s; }
|
||||
.karte h3 { margin: .3em 0; color: var(--text); font-size: 1.05rem; }
|
||||
.karte p { color: var(--muted); font-size: .88rem; margin: .4em 0; }
|
||||
.karte-nummer { font-size: .78rem; font-weight: 700; color: var(--accent); text-transform: uppercase; letter-spacing: .03em; }
|
||||
.karte-zeit { font-size: .8rem; color: var(--muted); }
|
||||
.karte-pfad { background: var(--tint-violett); border-color: var(--violett); }
|
||||
.karte-einstieg { background: var(--tint-cyan); border-color: var(--cyan); }
|
||||
.kapitelgruppe { margin: 2.5rem 0; }
|
||||
.kapitelgruppe h2 { color: var(--accent); border-bottom: 2px solid var(--border); padding-bottom: .3em; }
|
||||
.lernpfade h2 { color: var(--violett); }
|
||||
|
||||
/* --- Landing-Page Hero --- */
|
||||
.hero { margin: 1rem 0 2.5rem; }
|
||||
.hero-kicker { color: var(--cyan); letter-spacing: .12em; font-weight: 700; font-size: .85rem; }
|
||||
.hero-text h1 { font-size: 2.1rem; color: var(--accent); margin: .2em 0; }
|
||||
.hero-untertitel { color: var(--muted); font-size: 1.05rem; }
|
||||
.hero-badges { display: flex; gap: .6rem; margin-top: 1rem; flex-wrap: wrap; }
|
||||
.hero-kompendium { color: var(--muted); margin-top: 1.4rem; max-width: 640px; }
|
||||
.hero-autor { color: var(--muted); font-size: .92rem; line-height: 1.5; }
|
||||
.badge { padding: .35em .9em; border-radius: 20px; color: #fff; font-weight: 600; font-size: .85rem; }
|
||||
.badge-indigo { background: var(--accent); }
|
||||
.badge-cyan { background: var(--cyan); }
|
||||
.badge-violett { background: var(--violett); }
|
||||
.badge-emerald { background: var(--emerald); }
|
||||
|
||||
/* --- Programme-Seite --- */
|
||||
.programmgruppe { margin: 2rem 0; }
|
||||
.programmliste { list-style: none; padding: 0; }
|
||||
.programmliste li { display: flex; align-items: center; justify-content: space-between; padding: .5em .8em; border: 1px solid var(--border); border-radius: 8px; margin: .4em 0; background: var(--surface); }
|
||||
|
||||
/* --- Stichwortverzeichnis --- */
|
||||
.register-sprungleiste { display: flex; flex-wrap: wrap; gap: .3rem; margin: 1.2rem 0 1.8rem; position: sticky; top: 3.6rem; background: var(--bg); padding: .5rem 0; z-index: 5; }
|
||||
.register-sprungleiste a { display: inline-flex; align-items: center; justify-content: center; width: 1.8rem; height: 1.8rem; border-radius: 6px; background: var(--surface2); color: var(--accent); text-decoration: none; font-weight: 700; font-size: .85rem; }
|
||||
.register-sprungleiste a:hover { background: var(--tint-indigo); }
|
||||
.register-buchstabe { color: var(--accent); border-bottom: 2px solid var(--border); padding-bottom: .15em; margin-top: 2em; font-size: 1.3rem; }
|
||||
.register-eintrag { padding: .55em 0; border-bottom: 1px solid var(--border); }
|
||||
.register-begriff { font-weight: 700; }
|
||||
.register-eintrag a { font-size: .92rem; }
|
||||
.register-unter { list-style: none; margin: .4em 0 0; padding-left: 1.4em; }
|
||||
.register-unter li { margin: .3em 0; color: var(--muted); font-size: .92rem; }
|
||||
.register-unter a { font-size: inherit; }
|
||||
|
||||
/* --- Mobile --- */
|
||||
@media (max-width: 899px) {
|
||||
.sidebar {
|
||||
position: fixed; top: 0; left: 0; height: 100vh; z-index: 50; transform: translateX(-105%);
|
||||
transition: transform .2s ease; box-shadow: var(--shadow-lg); padding-top: 3.6rem;
|
||||
}
|
||||
.sidebar.offen { transform: translateX(0); }
|
||||
.sidebar-overlay.offen { display: block; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 40; }
|
||||
.content { padding: 1.2rem 1rem 4rem; }
|
||||
.site-search { max-width: none; }
|
||||
}
|
||||
211
OR_HTML_04/assets/site.js
Normal file
211
OR_HTML_04/assets/site.js
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
// site.js — Interaktivität der Mehrseiten-Website "Operations Research mit
|
||||
// Python": Dark-Mode-Toggle, mobile Sidebar, Volltextsuche, Lernfortschritt,
|
||||
// Code-Kopieren/Herunterladen. Reines Vanilla-JS, keine Abhaengigkeiten.
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var LS_THEME = "or-theme";
|
||||
var LS_FORTSCHRITT = "or-fortschritt";
|
||||
|
||||
function ladeFortschritt() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(LS_FORTSCHRITT) || "{}");
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function speichereFortschritt(daten) {
|
||||
try {
|
||||
localStorage.setItem(LS_FORTSCHRITT, JSON.stringify(daten));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// --- Dark-Mode-Toggle -------------------------------------------------
|
||||
function initTheme() {
|
||||
var btn = document.getElementById("theme-toggle");
|
||||
if (!btn) return;
|
||||
btn.addEventListener("click", function () {
|
||||
var aktuell = document.documentElement.getAttribute("data-theme");
|
||||
var dunkelSystem = window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
var istDunkel = aktuell ? aktuell === "dark" : dunkelSystem;
|
||||
var neu = istDunkel ? "light" : "dark";
|
||||
document.documentElement.setAttribute("data-theme", neu);
|
||||
try { localStorage.setItem(LS_THEME, neu); } catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
// --- Mobile Sidebar -----------------------------------------------------
|
||||
function initSidebar() {
|
||||
var sidebar = document.getElementById("sidebar");
|
||||
var overlay = document.getElementById("sidebar-overlay");
|
||||
var knopf = document.getElementById("sidebar-toggle");
|
||||
if (!sidebar || !overlay || !knopf) return;
|
||||
|
||||
function schliessen() {
|
||||
sidebar.classList.remove("offen");
|
||||
overlay.classList.remove("offen");
|
||||
overlay.hidden = true;
|
||||
}
|
||||
knopf.addEventListener("click", function () {
|
||||
var offen = sidebar.classList.toggle("offen");
|
||||
overlay.hidden = !offen;
|
||||
overlay.classList.toggle("offen", offen);
|
||||
});
|
||||
overlay.addEventListener("click", schliessen);
|
||||
sidebar.querySelectorAll("a").forEach(function (a) {
|
||||
a.addEventListener("click", schliessen);
|
||||
});
|
||||
|
||||
// Aktuelle Kapitelgruppe aufklappen, falls noch nicht offen.
|
||||
var aktiv = sidebar.querySelector("li.aktiv");
|
||||
if (aktiv) {
|
||||
var details = aktiv.closest("details");
|
||||
if (details) details.open = true;
|
||||
// Nur den Sidebar-eigenen Scrollbereich verschieben, NICHT
|
||||
// aktiv.scrollIntoView() verwenden: das wuerde auch das ganze Fenster
|
||||
// scrollen und einen #anker-Sprung aus der URL (z.B. von einem
|
||||
// Querverweis) wieder zunichtemachen.
|
||||
sidebar.scrollTop = Math.max(0, aktiv.offsetTop - sidebar.clientHeight / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Lernfortschritt ------------------------------------------------
|
||||
function initFortschritt() {
|
||||
var daten = ladeFortschritt();
|
||||
document.querySelectorAll('.sidebar li[data-kapitel]').forEach(function (li) {
|
||||
if (daten[li.dataset.kapitel]) li.dataset.erledigt = "1";
|
||||
});
|
||||
var knopf = document.querySelector(".fortschritt-knopf");
|
||||
if (!knopf) return;
|
||||
var kapitel = knopf.dataset.kapitel;
|
||||
function aktualisiereKnopf() {
|
||||
var erledigt = !!daten[kapitel];
|
||||
knopf.classList.toggle("erledigt", erledigt);
|
||||
knopf.querySelector("span").textContent =
|
||||
erledigt ? "Als gelesen markiert" : "Als gelesen markieren";
|
||||
var eintrag = document.querySelector(
|
||||
'.sidebar li[data-kapitel="' + kapitel + '"]');
|
||||
if (eintrag) eintrag.dataset.erledigt = erledigt ? "1" : "0";
|
||||
}
|
||||
aktualisiereKnopf();
|
||||
knopf.addEventListener("click", function () {
|
||||
daten[kapitel] = !daten[kapitel];
|
||||
speichereFortschritt(daten);
|
||||
aktualisiereKnopf();
|
||||
});
|
||||
}
|
||||
|
||||
// --- Suche ------------------------------------------------------------
|
||||
function initSuche() {
|
||||
var eingabe = document.getElementById("suche-eingabe");
|
||||
var ergebnisBox = document.getElementById("suche-ergebnisse");
|
||||
if (!eingabe || !ergebnisBox) return;
|
||||
// window.OR_SEARCH_INDEX kommt aus assets/search-index.js (als normales
|
||||
// <script> geladen, nicht per fetch()) - fetch() auf lokale Dateien
|
||||
// scheitert unter file:// (Seite ohne Webserver geoeffnet) an CORS.
|
||||
var index = window.OR_SEARCH_INDEX || [];
|
||||
|
||||
function anzeigen(treffer) {
|
||||
if (!treffer.length) {
|
||||
ergebnisBox.innerHTML = '<p class="suche-leer">Keine Treffer.</p>';
|
||||
ergebnisBox.hidden = false;
|
||||
return;
|
||||
}
|
||||
ergebnisBox.innerHTML = treffer.slice(0, 20).map(function (t) {
|
||||
var href = t.seite + (t.anker ? "#" + t.anker : "");
|
||||
var snippet = t.text ? "<small>" + t.text + "</small>" : "";
|
||||
return '<a href="' + href + '">' + t.titel + snippet + "</a>";
|
||||
}).join("");
|
||||
ergebnisBox.hidden = false;
|
||||
}
|
||||
|
||||
eingabe.addEventListener("input", function () {
|
||||
var q = eingabe.value.trim().toLowerCase();
|
||||
if (q.length < 2) { ergebnisBox.hidden = true; return; }
|
||||
var treffer = index.filter(function (e) {
|
||||
return (e.titel && e.titel.toLowerCase().indexOf(q) !== -1) ||
|
||||
(e.text && e.text.toLowerCase().indexOf(q) !== -1);
|
||||
});
|
||||
anzeigen(treffer);
|
||||
});
|
||||
document.addEventListener("click", function (ev) {
|
||||
if (!ergebnisBox.contains(ev.target) && ev.target !== eingabe) {
|
||||
ergebnisBox.hidden = true;
|
||||
}
|
||||
});
|
||||
eingabe.addEventListener("keydown", function (ev) {
|
||||
if (ev.key === "Escape") { ergebnisBox.hidden = true; eingabe.blur(); }
|
||||
});
|
||||
}
|
||||
|
||||
// --- Code: Kopieren-Button (+ Herunterladen, falls Programmdatei bekannt) --
|
||||
function initCodeButtons() {
|
||||
// window.OR_PROGRAMME kommt aus assets/programme.js (normales <script>,
|
||||
// kein fetch() - siehe initSuche()).
|
||||
var programmListe = window.OR_PROGRAMME || [];
|
||||
|
||||
document.querySelectorAll("div.sourceCode").forEach(function (box) {
|
||||
var code = box.querySelector("code");
|
||||
if (!code) return;
|
||||
var leiste = document.createElement("div");
|
||||
leiste.className = "code-btn-leiste";
|
||||
|
||||
var kopieren = document.createElement("button");
|
||||
kopieren.type = "button";
|
||||
kopieren.className = "code-btn";
|
||||
kopieren.setAttribute("aria-label", "Code kopieren");
|
||||
kopieren.innerHTML =
|
||||
'<svg class="icon"><use href="#icon-copy"></use></svg><span>Kopieren</span>';
|
||||
kopieren.addEventListener("click", function () {
|
||||
navigator.clipboard.writeText(code.innerText).then(function () {
|
||||
var label = kopieren.querySelector("span");
|
||||
var original = label.textContent;
|
||||
kopieren.classList.add("copied");
|
||||
label.textContent = "Kopiert!";
|
||||
setTimeout(function () {
|
||||
kopieren.classList.remove("copied");
|
||||
label.textContent = original;
|
||||
}, 1500);
|
||||
});
|
||||
});
|
||||
leiste.appendChild(kopieren);
|
||||
box.appendChild(leiste);
|
||||
|
||||
// Erste Codezeile "# Name.py" (nach Shebang) -> Download-Button, wenn
|
||||
// eine passende Datei unter programme/ existiert (Programme.py werden
|
||||
// beim Bau nach OR_HTML/programme/ kopiert, siehe build_version_03.py).
|
||||
var text = code.innerText;
|
||||
var treffer = text.match(/^#\s*([A-Za-z0-9_]+\.py)\s*$/m);
|
||||
if (treffer && programmListe.indexOf(treffer[1]) !== -1) {
|
||||
var link = document.createElement("a");
|
||||
link.className = "code-btn";
|
||||
link.href = "programme/" + treffer[1];
|
||||
link.setAttribute("download", "");
|
||||
link.innerHTML =
|
||||
'<svg class="icon"><use href="#icon-download"></use></svg><span>Herunterladen</span>';
|
||||
leiste.appendChild(link);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
initTheme();
|
||||
initSidebar();
|
||||
initFortschritt();
|
||||
initSuche();
|
||||
initCodeButtons();
|
||||
});
|
||||
|
||||
// Bilder ohne width/height-Attribut (siehe Kapitelseiten) reflowen den
|
||||
// Text erst, wenn sie fertig geladen sind - das passiert erst NACH
|
||||
// DOMContentLoaded. Ein #anker-Sprung aus der URL (Querverweis, Such-
|
||||
// treffer, Stichwortverzeichnis) kann dadurch zu weit oben landen. Nach
|
||||
// vollstaendigem Laden (inkl. Bilder) hier zur Sicherheit erneut hinspringen.
|
||||
window.addEventListener("load", function () {
|
||||
if (!location.hash) return;
|
||||
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
||||
if (ziel) ziel.scrollIntoView({ behavior: "instant", block: "start" });
|
||||
});
|
||||
})();
|
||||
Loading…
Reference in a new issue