fix(#178 Phase 12): Teilen-Funktion umfassend gefixt

- **X (Twitter) raus** — Button + Logik entfernt.
- **Copy & Paste**: vollständiger Body ohne Länge-Cut, mehrzeilig
  strukturiert (Score, Titel, Drucksache, Beschreibung, Permalink,
  Hashtags). Statt 240-Zeichen-Twitter-Variante.
- **Threads**: encodeURIComponent kümmert sich um UTF-8 — keine
  Sonderzeichen-Probleme.
- **Mastodon**: gleicher Body wie Threads, Limit auf 420 Zeichen
  (mit Permalink-Reserve), Instance-Prompt bleibt.
- **LinkedIn**: Composer öffnet nur den Permalink (LinkedIn-API-
  Limitation), aber der vollständige Body landet parallel in der
  Zwischenablage. Toast informiert User.
- **E-Mail**: strukturierter Body mit Umbrüchen — Score-Zeile, Titel,
  Drucksache, Beschreibung, Permalink, Footer. Statt der knappen
  Threads-Variante.
- **Magnific**: korrekte URL mit `last_filter=selection&last_value=1
  &selection=1` — license-Filter vorausgewählt.

Refs: #178

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dotty Dotter 2026-05-06 23:34:09 +02:00
parent d853101275
commit a06bcb4d89

View File

@ -449,10 +449,6 @@
style="padding:5px 10px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);"> style="padding:5px 10px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);">
Threads Threads
</button> </button>
<button onclick="v2DetailShare('twitter')"
style="padding:5px 10px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);">
𝕏
</button>
<button onclick="v2DetailShareMastodon()" <button onclick="v2DetailShareMastodon()"
style="padding:5px 10px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);"> style="padding:5px 10px;border:1px solid var(--hairline);border-radius:4px;background:none;cursor:pointer;font-family:var(--font-mono);font-size:11px;color:var(--ecg-dark);">
Mastodon Mastodon
@ -726,37 +722,73 @@ window.v2ShowMatrixFieldInfo = function(field) {
}; };
/* ── Share ────────────────────────────────────────────────────── */ /* ── Share ────────────────────────────────────────────────────── */
// Limits pro Plattform (konservativ, mit Permalink-Reserve).
// Mastodon: meiste Instances erlauben 500 — minus Permalink (~80) = 420.
var SHARE_LIMITS = {threads: 460, mastodon: 420};
function buildShareText(platform) { function buildShareText(platform) {
var LIMITS = {twitter: 240, threads: 460, mastodon: 460}; var limit = SHARE_LIMITS[platform]; // null = kein Limit (Copy/E-Mail)
var limit = LIMITS[platform] || 460;
var text; var text;
if (platform === 'twitter' && SHARE_TWI) text = SHARE_TWI; if (platform === 'threads' && SHARE_THR) text = SHARE_THR;
else if (platform === 'threads' && SHARE_THR) text = SHARE_THR;
else if (platform === 'mastodon' && SHARE_MAS) text = SHARE_MAS; else if (platform === 'mastodon' && SHARE_MAS) text = SHARE_MAS;
else if (platform === 'threads' && SHARE_MAS) text = SHARE_MAS; // Fallback Threads ← Mastodon
else { else {
var emoji = SCORE >= 8 ? '🟢' : SCORE >= 5 ? '🟡' : SCORE >= 3 ? '🟠' : '🔴'; var emoji = SCORE >= 8 ? '🟢' : SCORE >= 5 ? '🟡' : SCORE >= 3 ? '🟠' : '🔴';
text = emoji + ' GWÖ-Score ' + SCORE + '/10: „' + TITLE.substring(0, 70) + '" (' + DRS + ')\n\n#Gemeinwohl #GWÖ'; text = emoji + ' GWÖ-Score ' + SCORE + '/10: „' + TITLE.substring(0, 70) + '" (' + DRS + ')\n\n#Gemeinwohl #GWÖ';
} }
if (text.length > limit) text = text.substring(0, limit - 1) + '…'; if (limit && text.length > limit) text = text.substring(0, limit - 1) + '…';
return text; return text;
} }
// Vollständiger Share-Body fuer LinkedIn/E-Mail/Copy — keine Längen-Cuts.
function buildLongShareText() {
var emoji = SCORE >= 8 ? '🟢' : SCORE >= 5 ? '🟡' : SCORE >= 3 ? '🟠' : '🔴';
var lines = [
emoji + ' GWÖ-Score ' + SCORE + '/10 für „' + TITLE + '" (' + DRS + ')',
'',
'Bewertet nach der Gemeinwohl-Matrix 2.0 — Würde, Solidarität,',
'Nachhaltigkeit, Gerechtigkeit, Demokratie. Vollständige Auswertung',
'mit Fraktions-Programmtreue, Verbesserungsvorschlägen und Belegen:',
'',
PERMALINK,
'',
'#Gemeinwohl #GWÖ #Antragspruefer'
];
return lines.join('\n');
}
window.v2DetailShare = function(platform) { window.v2DetailShare = function(platform) {
if (platform === 'linkedin') {
// LinkedIn legacy share-offsite akzeptiert nur url. Aber wir
// prefillen den Text via Clipboard + öffnen Composer parallel,
// damit der User mit Strg-V einfügen kann.
var body = buildLongShareText();
var urlOnly = 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(PERMALINK);
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(body).then(function() {
window.open(urlOnly, '_blank', 'noopener');
v2ShareToast('LinkedIn-Composer geöffnet — Text liegt in der Zwischenablage (Strg/⌘-V einfügen)');
}, function() {
window.open(urlOnly, '_blank', 'noopener');
});
} else {
window.open(urlOnly, '_blank', 'noopener');
}
return;
}
var text = buildShareText(platform) + '\n' + PERMALINK; var text = buildShareText(platform) + '\n' + PERMALINK;
var urls = { var urls = {
twitter: 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(text),
threads: 'https://www.threads.net/intent/post?text=' + encodeURIComponent(text), threads: 'https://www.threads.net/intent/post?text=' + encodeURIComponent(text),
linkedin: 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(PERMALINK)
}; };
if (urls[platform]) window.open(urls[platform], '_blank', 'noopener'); if (urls[platform]) window.open(urls[platform], '_blank', 'noopener');
}; };
window.v2DetailShareCopy = function() { window.v2DetailShareCopy = function(evt) {
var text = buildShareText('twitter') + '\n' + PERMALINK; // Kompletter Body, keine Längen-Cuts. PERMALINK enthalten.
var text = buildLongShareText();
if (navigator.clipboard && navigator.clipboard.writeText) { if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function() { navigator.clipboard.writeText(text).then(function() {
// kleiner visueller Hinweis: Button-Text temporär var btn = (evt && evt.currentTarget) || (window.event && window.event.currentTarget);
var btn = event && event.currentTarget;
if (btn) { if (btn) {
var orig = btn.textContent; var orig = btn.textContent;
btn.textContent = '✓ kopiert'; btn.textContent = '✓ kopiert';
@ -770,17 +802,39 @@ window.v2ShowMatrixFieldInfo = function(field) {
window.v2DetailShareEmail = function() { window.v2DetailShareEmail = function() {
var subject = 'GWÖ-Bewertung: ' + (TITLE.substring(0, 60)); var subject = 'GWÖ-Bewertung: ' + (TITLE.substring(0, 60));
var body = (SHARE_THR || buildShareText('threads')) + '\n\n' + PERMALINK; var emoji = SCORE >= 8 ? '🟢' : SCORE >= 5 ? '🟡' : SCORE >= 3 ? '🟠' : '🔴';
var body = [
emoji + ' GWÖ-Score ' + SCORE + '/10',
'',
'Antrag: ' + TITLE,
'Drucksache: ' + DRS,
'',
(SHARE_MAS || SHARE_THR || ('Eine Auswertung aus Sicht der Gemeinwohl-Ökonomie zum Antrag „' + TITLE.substring(0, 80) + '".')),
'',
'Vollständige Bewertung mit Matrix 2.0, Programm-Treue pro Fraktion,',
'Verbesserungsvorschlägen und Belegen:',
'',
PERMALINK,
'',
'— GWÖ-Antragsprüfer · gwoe.toppyr.de'
].join('\n');
window.location.href = 'mailto:?subject=' + encodeURIComponent(subject) + '&body=' + encodeURIComponent(body); window.location.href = 'mailto:?subject=' + encodeURIComponent(subject) + '&body=' + encodeURIComponent(body);
}; };
window.v2DetailShareImage = function() { window.v2DetailShareImage = function() {
var topics = (window.ANTRAG_TOPICS || []).slice(0, 2).join(' '); var topics = (window.ANTRAG_TOPICS || []).slice(0, 2).join(' ');
var query = (topics || TITLE.substring(0, 40)) + ' Politik'; var query = (topics || TITLE.substring(0, 40)) + ' Politik';
window.open('https://www.freepik.com/search?format=search&query=' + encodeURIComponent(query), '_blank', 'noopener'); // Magnific: license-Selection vorausgewählt (selection=1, last_filter=selection).
var url = 'https://www.magnific.com/search?format=search'
+ '&last_filter=selection&last_value=1'
+ '&query=' + encodeURIComponent(query)
+ '&selection=1';
window.open(url, '_blank', 'noopener');
}; };
window.v2DetailShareMastodon = function() { window.v2DetailShareMastodon = function() {
// Encoding-Fix: encodeURIComponent kümmert sich um UTF-8 — wir
// dürfen den Text NICHT vorher manuell escapen.
var text = buildShareText('mastodon') + '\n' + PERMALINK; var text = buildShareText('mastodon') + '\n' + PERMALINK;
var instance = localStorage.getItem('mastodon_instance'); var instance = localStorage.getItem('mastodon_instance');
if (!instance) { if (!instance) {
@ -792,6 +846,18 @@ window.v2ShowMatrixFieldInfo = function(field) {
window.open('https://' + instance + '/share?text=' + encodeURIComponent(text), '_blank', 'noopener'); window.open('https://' + instance + '/share?text=' + encodeURIComponent(text), '_blank', 'noopener');
}; };
// Kleine Toast-Helper-Funktion — verschwindet nach 2 s
function v2ShareToast(msg) {
var t = document.createElement('div');
t.textContent = msg;
t.style.cssText = 'position:fixed;bottom:24px;left:50%;transform:translateX(-50%);'
+ 'background:var(--ecg-teal);color:#fff;padding:10px 18px;border-radius:4px;'
+ 'font-family:var(--font-mono);font-size:12px;z-index:9999;'
+ 'box-shadow:0 4px 12px rgba(0,0,0,0.15);';
document.body.appendChild(t);
setTimeout(function(){ t.remove(); }, 2500);
}
/* ── Re-Analyze ───────────────────────────────────────────────── */ /* ── Re-Analyze ───────────────────────────────────────────────── */
function pollReAnalyze(jobId, btn) { function pollReAnalyze(jobId, btn) {
fetch('/status/' + jobId) fetch('/status/' + jobId)