Agentur-Events: aus einem Bildschirmfoto wird eine Kampagnenkachel
Filipe: "bei den agentur events soll ich kein link sondern immer so ein
screen reinschicke und dan soll daraus alles genommen werden und daraus
die kampagne kachel gemacht werden."
WARUM EIN BILD UND NICHT DER LINK. Gemessen am 07./08.10.2026 an seinem
echten Agenturlink, mit Gegenprobe:
vm.tiktok.com/ZSbACwAnK/ -> tiktok.com/tcn/activity?activity_id=...
233 KB reine Huelle, kein Datenpaket
dieselbe Nummer auf dem Weg der oeffentlichen Kampagnenseite
42 KB, ebenfalls ohne Datenpaket
eine ECHTE Kampagne auf demselben Weg
967 KB MIT Datenpaket
Die Agentur-Kampagnen leben im Creator Network, und das rendert nichts
auf dem Server. Was Filipe sieht, sieht nur sein Browser -- also wird
genau das gelesen: das Bild davon.
DREI WEGE ZUM SELBEN KASTEN: einfuegen (Strg+V nach Win+Umschalt+S),
hereinziehen, auswaehlen (Handy). Derselbe Kasten, derselbe
Knopfzustand, dieselbe Meldezeile wie beim Link.
TESSERACT, NICHT EIN DIENST IM NETZ. Apache 2.0, auf dem eigenen
Server, 0 EUR, und das Bild verlaesst ihn nicht -- ein Backstage-Foto
zeigt Teilnehmerzahlen und Kampagnennamen. Version 5.5.0 mit deutschen
Sprachdaten war bereits vorhanden. `--psm 4` gemessen gegen `6` (24
statt 14 Zeilen); keine Bildnachbearbeitung, weil vier gemessene
Fassungen (unveraendert, invertiert, doppelt, beides) dieselben Ziele
wortgleich lesen.
DIESELBE FORM WIE DER LINK-LESER. `leseBild()` gibt Feld fuer Feld
dasselbe zurueck wie `leseKampagne()` -- dadurch greifen Gliederung,
Geschenkplaketten, Aufklappen, Teilen, Steckbrief und Spaltenwahl
unveraendert. Geprueft wird das ausdruecklich (17 gegen 17 Felder).
DER ZEITRAUM WIRD ZWEIMAL GELESEN UND MUSS ZWEIMAL DASSELBE SAGEN.
Auf der Seite steht er amerikanisch (10/01/2026) und deutsch
(01.10.2026). Genommen wird die deutsche, die amerikanische ist die
Gegenprobe. Widersprechen sie sich, entsteht KEINE Kachel: Eine Kachel
ohne Zeitraum ist unvollstaendig und sagt das selbst -- eine mit dem
falschen ist eine Falschauskunft, und bei Texterkennung ist aus einer 3
schnell eine 8.
Der Anlege-Block ist aus der Link-Route herausgezogen
(`kachelSchreiben`), damit beide Wege DIESELBE Stelle benutzen.
Abgeschrieben waere er die Dopplung, die hier am 11.09.2026 schon
einmal drei Spalten gekostet hat.
GEMESSEN UND BERICHTIGT (alles aus echten Laeufen, nicht geraten):
- Die Phasenueberschrift trug ein Zielscheiben-Zeichen, das als `@`
gelesen wurde -- die erste "Aufgabe" hiess "Ziele erreichen Endetin
23 Tage 22 : 50 : 44".
- Halbe Schilder liessen ihre zweite Haelfte im Wert stehen:
"Sichtbar für: für Privat".
- "Creator*innen" schnitt mitten im Nachbarwert ab und machte aus
"1 Creator Network, 55 Creator*innen" ein "1 Creator Network, 55".
- "In Bearbeitung" kam als "in aearbeitung" durch.
- Die Creator-Zahl steht als "1 (i)" da, und der Kreis wird als Null
gelesen. Sie wird deshalb GAR NICHT angezeigt: keine Angabe ist
richtig, eine falsche ist falsch.
- Das Wasserzeichen (seine Mailadresse, vielfach und schraeg) taucht
im Erkennungstext kein einziges Mal auf -- festgehalten mit
Gegenprobe, falls eine kuenftige Fassung es doch liest.
- `.knopf--still` hiess zuerst wie ein allgemeiner Knopf-Zusatz;
pruef-css-klassen hatte recht, ihn auf drei Seiten zu vermissen.
Jetzt `.kampagneholen__waehlen`, im Namensraum seines Kastens.
- Die Pruefung selbst meldete zweimal Falsches: Sie fand "execFile"
und "Tesseract" in den KOMMENTAREN des Lesers und hielt
`regex.exec(...)` fuer einen fremden Prozess.
GEPRUEFT: 43 neu (pruef-kampagne-bild, davon 1 nicht nachsehbar --
Tesseract fehlt auf dem Entwicklungsrechner; auf dem Server liefert es
den gespeicherten Erkennungstext zeichengleich), 169 (Route,
unveraendert nach dem Herausziehen), struktur, css-klassen, zeichen,
deutsche-texte.
PARALLELE ARBEIT: An derselben Arbeitskopie wird gleichzeitig an der
Crew-Seite gebaut (Reaction, Foyer). Dieser Commit fasst ausschliesslich
die zehn Dateien oben an -- einzeln vorgemerkt, kein `git add -A`. Der
globale Cache-Stempel wurde absichtlich NICHT gelaufen, nur die zwei
Verweise in bereich.html; gestempelt wird am Ende einmal fuer beide.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -4222,3 +4222,76 @@ body[data-ton] .kopf-zeile::before {
|
||||
.kampagneholen__seite { border: 1px solid CanvasText; }
|
||||
.kampagneholen__seite:has(input:checked) { border: 2px solid Highlight; }
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
EIN BILDSCHIRMFOTO STATT EINES LINKS (08.10.2026)
|
||||
|
||||
Filipe: „bei den agentur events soll ich kein link sondern immer so
|
||||
ein screen reinschicke und dan soll daraus alles genommen werden.“
|
||||
|
||||
Drei Wege zum selben Ziel — einfügen, hereinziehen, auswählen. Der
|
||||
Kasten muss deshalb beim Hereinziehen sichtbar antworten: Ein Bild
|
||||
loszulassen und nicht zu wissen, ob es angekommen ist, ist der
|
||||
Moment, in dem man es ein zweites Mal versucht.
|
||||
===================================================================== */
|
||||
.kampagneholen__bild {
|
||||
display: flex; flex-wrap: wrap; align-items: center;
|
||||
gap: 8px 12px;
|
||||
margin: 12px 0 0;
|
||||
}
|
||||
.kampagneholen__bild .feld-hinweis { margin: 0; }
|
||||
|
||||
/* Der stille Knopf: ein `label` zum versteckten Dateifeld. Er sieht
|
||||
aus wie ein Knopf, weil er einer ist — aber er tritt zurück, denn
|
||||
„Kampagne holen“ bleibt die Haupthandlung.
|
||||
|
||||
HIESS ZUERST `.knopf--still` (berichtigt 08.10.2026). Das klang
|
||||
nach einem allgemeinen Knopf-Zusatz für das ganze Haus — und
|
||||
pruef-css-klassen hatte recht, als sie ihn auf drei Seiten
|
||||
vermisste: Ein Zusatz im `knopf`-Namensraum verspricht, überall
|
||||
verwendbar zu sein. Er gilt aber genau für diese eine Stelle, also
|
||||
trägt er auch ihren Namen. */
|
||||
.kampagneholen__waehlen {
|
||||
background: transparent;
|
||||
border: 1px dashed color-mix(in srgb, var(--rand) 85%, transparent);
|
||||
color: var(--text-leise);
|
||||
cursor: pointer;
|
||||
}
|
||||
.kampagneholen__waehlen:hover, .kampagneholen__waehlen:focus-visible {
|
||||
color: var(--text);
|
||||
border-style: solid;
|
||||
border-color: color-mix(in srgb, var(--akzent, #3fbdf5) 45%, transparent);
|
||||
}
|
||||
/* Das Dateifeld ist `hidden`; sein Fokus wandert sichtbar auf das
|
||||
Etikett, sonst wäre der Knopf mit der Tastatur unsichtbar. */
|
||||
.kampagneholen__bild input:focus-visible + label,
|
||||
.kampagneholen__bild input:focus-visible ~ label {
|
||||
outline: 2px solid var(--akzent, #3fbdf5);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* WÄHREND ETWAS DARÜBER SCHWEBT. Kein Blinken, kein Springen — ein
|
||||
ruhiger Rahmen in der Hausfarbe reicht, und er lässt die Höhe
|
||||
unverändert (`inset`-Schatten statt Rand, sonst ruckt der ganze
|
||||
Kasten um zwei Pixel). */
|
||||
.kampagneholen[data-zieht="ja"] {
|
||||
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--akzent, #3fbdf5) 60%, transparent);
|
||||
}
|
||||
.kampagneholen[data-zieht="ja"] .kampagneholen__bild .feld-hinweis {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
/* 44 px Tippziel — dieselbe Vorgabe wie überall im Haus. Auf dem
|
||||
Handy ist „auswählen“ der einzige der drei Wege, den es gibt. */
|
||||
.kampagneholen__waehlen { min-height: 44px; }
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.kampagneholen__waehlen { border: 1px solid CanvasText; }
|
||||
.kampagneholen[data-zieht="ja"] { outline: 2px solid Highlight; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.kampagneholen__waehlen { transition: none; }
|
||||
}
|
||||
|
||||
@@ -2865,6 +2865,10 @@
|
||||
const feld = $('kampagne-text');
|
||||
const knopf = $('kampagne-holen');
|
||||
const sagt = $('kampagne-sagt');
|
||||
/* DER GANZE KASTEN, nicht nur das Textfeld: Daran haengen
|
||||
Einfuegen und Hereinziehen weiter unten. Wer ein Bild einfuegt,
|
||||
soll nicht erst in das Textfeld klicken muessen. */
|
||||
const kasten = $('kampagneholen') || form;
|
||||
const ruheText = sagt ? sagt.textContent : '';
|
||||
|
||||
/* DER KNOPF GIBT SICH VON SELBST WIEDER FREI.
|
||||
@@ -2882,10 +2886,15 @@
|
||||
zweites Mal. */
|
||||
const FREI_NACH_MS = 15000;
|
||||
let wecker = null;
|
||||
const sperren = () => {
|
||||
/* `satz` SEIT DEM 08.10.2026: Beim Bild steht dort „Bild wird
|
||||
gelesen …“, beim Link „Wird geholt …“. Dieselbe Sperre,
|
||||
dieselbe Zeile -- nur das Wort passt zu dem, was wirklich
|
||||
laeuft. „Wird geholt“ waere beim Bild schlicht falsch: Es
|
||||
wird nichts geholt, es wird gelesen. */
|
||||
const sperren = (satz) => {
|
||||
knopf.disabled = true;
|
||||
form.dataset.laeuft = 'ja';
|
||||
if (sagt) sagt.textContent = 'Wird geholt …';
|
||||
if (sagt) sagt.textContent = satz || 'Wird geholt …';
|
||||
clearTimeout(wecker);
|
||||
wecker = setTimeout(() => {
|
||||
knopf.disabled = false;
|
||||
@@ -2901,6 +2910,97 @@
|
||||
if (sagt) sagt.textContent = text || ruheText;
|
||||
};
|
||||
|
||||
/* ==== EIN BILDSCHIRMFOTO STATT EINES LINKS (08.10.2026) ====
|
||||
|
||||
Filipe: „bei den agentur events soll ich kein link sondern
|
||||
immer so ein screen reinschicke.“
|
||||
|
||||
DERSELBE KASTEN, DERSELBE KNOPFZUSTAND, DIESELBE
|
||||
MELDEZEILE. Ein zweiter Kasten daneben hiesse: zweimal
|
||||
dasselbe lernen, und beim naechsten Umbau laufen beide
|
||||
auseinander. Nur der Weg zum Server ist ein anderer, weil
|
||||
ein Bild keine Zeichenkette ist.
|
||||
|
||||
ROHE BYTES, BESCHRIFTUNG IM KOPF -- so nimmt dieses Haus
|
||||
jede Datei entgegen (siehe workspace-dateien.js). Kein
|
||||
multipart/form-data von Hand. */
|
||||
const bildSenden = async (datei) => {
|
||||
if (!datei) return;
|
||||
if (!/^image\//.test(datei.type || '')) {
|
||||
freigeben('Das war kein Bild. Es geht ein Bildschirmfoto als PNG oder JPEG.');
|
||||
return;
|
||||
}
|
||||
sperren('Bild wird gelesen …');
|
||||
try {
|
||||
const gewaehlt = form.querySelector('input[name="kampagne-seite"]:checked');
|
||||
const a = await hole('/workspace/api/kampagne/bild', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': datei.type || 'application/octet-stream',
|
||||
'x-seite': gewaehlt ? gewaehlt.value : '',
|
||||
},
|
||||
body: datei,
|
||||
});
|
||||
const r = await a.json().catch(() => ({}));
|
||||
if (!a.ok) {
|
||||
freigeben(sagWas(r.fehler,
|
||||
`Der Server hat abgelehnt (${a.status}), ohne den Grund mitzuschicken.`));
|
||||
return;
|
||||
}
|
||||
if (r.schon) {
|
||||
freigeben('Diese Kampagne war schon da — die Kachel steht unten.');
|
||||
} else {
|
||||
const spanne = r.von && r.bis ? ` (${r.von} bis ${r.bis})` : '';
|
||||
const zahl = (r.aufgaben || []).length;
|
||||
freigeben(`„${r.titel}“${spanne} steht unten — `
|
||||
+ `${zahl} Ziel(e) gelesen. Bitte Titel und Zeitraum nachsehen.`);
|
||||
}
|
||||
await laden();
|
||||
} catch (f) {
|
||||
void f; /* umgeleitet -- holen.js schickt bei 401 zur Anmeldung */
|
||||
}
|
||||
};
|
||||
|
||||
/* EINFÜGEN. Das ist der Weg, den Filipe meint: Win+Umschalt+S,
|
||||
dann Strg+V. Der Zuhörer haengt am ganzen Kasten, nicht nur
|
||||
am Textfeld -- sonst muss man erst hineinklicken. */
|
||||
kasten.addEventListener('paste', (ev) => {
|
||||
const dinge = [...(ev.clipboardData?.items || [])];
|
||||
const bild = dinge.find((x) => x.kind === 'file' && /^image\//.test(x.type));
|
||||
if (!bild) return; /* Text eingefuegt: alles wie bisher */
|
||||
ev.preventDefault();
|
||||
bildSenden(bild.getAsFile());
|
||||
});
|
||||
|
||||
/* HEREINZIEHEN. `dragover` muss abgefangen werden, sonst oeffnet
|
||||
der Browser das Bild einfach in der Seite -- und die Arbeit
|
||||
waere weg. */
|
||||
kasten.addEventListener('dragover', (ev) => {
|
||||
if (![...(ev.dataTransfer?.types || [])].includes('Files')) return;
|
||||
ev.preventDefault();
|
||||
kasten.dataset.zieht = 'ja';
|
||||
});
|
||||
kasten.addEventListener('dragleave', () => { delete ziel.dataset.zieht; });
|
||||
kasten.addEventListener('drop', (ev) => {
|
||||
const d = ev.dataTransfer?.files?.[0];
|
||||
if (!d) return;
|
||||
ev.preventDefault();
|
||||
delete kasten.dataset.zieht;
|
||||
bildSenden(d);
|
||||
});
|
||||
|
||||
/* AUSWÄHLEN -- der Weg auf dem Handy, wo es kein Strg+V gibt.
|
||||
Das Feld wird danach geleert: Sonst laesst sich dasselbe Bild
|
||||
kein zweites Mal waehlen (`change` kommt nur bei Aenderung). */
|
||||
const bildfeld = $('kampagne-bilddatei');
|
||||
if (bildfeld) {
|
||||
bildfeld.addEventListener('change', () => {
|
||||
const d = bildfeld.files?.[0];
|
||||
bildfeld.value = '';
|
||||
bildSenden(d);
|
||||
});
|
||||
}
|
||||
|
||||
form.addEventListener('submit', async (ev) => {
|
||||
ev.preventDefault();
|
||||
const text = (feld?.value || '').trim();
|
||||
|
||||
+22
-3
@@ -17,7 +17,7 @@
|
||||
<link rel="stylesheet" href="assets/css/gate.css?v=202610080131" />
|
||||
<link rel="stylesheet" href="assets/css/start.css?v=202610080131" />
|
||||
<link rel="stylesheet" href="assets/css/aufgaben.css?v=202610080131" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202610080131" />
|
||||
<link rel="stylesheet" href="assets/css/bereich.css?v=202610081000" />
|
||||
<!-- Wegen des Blocks „Willst du dazugehoeren?" auf dem Brett
|
||||
„Mitmachen". Eine eigene Kopie der Regel hier waere die zweite
|
||||
Stelle, an der dieselbe Sache anders aussieht. -->
|
||||
@@ -399,8 +399,27 @@
|
||||
<span>Agentur</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<!-- ODER EIN BILDSCHIRMFOTO (08.10.2026)
|
||||
|
||||
Filipe: „bei den agentur events soll ich kein link sondern
|
||||
immer so ein screen reinschicke und dan soll daraus alles
|
||||
genommen werden.“ Die Agentur-Kampagnen stehen im Creator
|
||||
Network, und das ist von außen nicht lesbar (gemessen am
|
||||
07.10.2026) — sichtbar sind sie nur in seinem Browser.
|
||||
|
||||
DREI WEGE ZUM SELBEN ZIEL, weil jeder woanders der
|
||||
bequemste ist: einfügen (Strg+V nach Win+Umschalt+S),
|
||||
fallen lassen (Maus), auswählen (Handy). Der Knopf ist
|
||||
ein `label` zum versteckten Dateifeld — so sieht er aus
|
||||
wie die anderen Knöpfe und bedient sich wie ein
|
||||
Dateifeld. -->
|
||||
<div class="kampagneholen__bild">
|
||||
<input type="file" id="kampagne-bilddatei" accept="image/*" hidden>
|
||||
<label class="knopf knopf--klein kampagneholen__waehlen" for="kampagne-bilddatei">Bildschirmfoto wählen</label>
|
||||
<span class="feld-hinweis">… oder hier einfügen (Strg+V) oder hereinziehen.</span>
|
||||
</div>
|
||||
<div class="kampagneholen__zeile">
|
||||
<p class="feld-hinweis" id="kampagne-sagt" role="status" aria-live="polite">Titel, Zeitraum, Banner, Aufgaben und Preise kommen von selbst.</p>
|
||||
<p class="feld-hinweis" id="kampagne-sagt" role="status" aria-live="polite">Aus dem Link kommen Titel, Zeitraum, Banner, Aufgaben und Preise von selbst — aus einem Bildschirmfoto Titel, Zeitraum und Ziele.</p>
|
||||
<button type="submit" class="knopf knopf--klein" id="kampagne-holen">Kampagne holen</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -427,6 +446,6 @@
|
||||
<script src="assets/js/schulung.js?v=202610080131" defer></script>
|
||||
<script src="assets/js/holen.js?v=202610080131" defer></script>
|
||||
<script src="assets/js/bildschau.js?v=202610080131"></script>
|
||||
<script src="assets/js/bereich.js?v=202610080131" defer></script>
|
||||
<script src="assets/js/bereich.js?v=202610081000" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user