Keine Browser-Dialoge mehr — eigene dolModal-Helper [deploy]
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
All checks were successful
Deploy bericht / deploy (push) Successful in 1s
Eddys Browser blockiert alert/confirm/prompt, deshalb sind die Dialoge unsichtbar. Komplett umgestellt: - js/editor.js: dolAlert/dolConfirm/dolPrompt als Promise-basierte Modals mit passendem Dark-Theme-Styling. Globaler click-Handler für data-dolconfirm an Links/Buttons. - Alle alert()/confirm()/prompt() in editor.js ersetzt (Template speichern, Finalize, Upload, Löschen, Signatur-Verify usw.). - bericht_card.php + admin/setup.php: onclick="return confirm(...)" durch data-dolconfirm="..." ersetzt. - btn-finalize: butActionConfirm → butAction (Dolibarr erzeugt sonst automatisch einen leeren jQuery-UI-Confirm-Dialog #confirm-dialog-box-btn-finalize, unser eigener Handler macht das jetzt). - css/bericht.css: Styling für .bericht-dolmodal*.
This commit is contained in:
parent
d40587845f
commit
bf368122aa
4 changed files with 155 additions and 18 deletions
|
|
@ -146,7 +146,7 @@ if (empty($templates)) {
|
|||
print '<td>'.dol_print_size(filesize($path)).'</td>';
|
||||
print '<td class="right">';
|
||||
print '<a href="?action=delete_template&name='.urlencode($tpl).'&token='.newToken().'" '
|
||||
.'onclick="return confirm(\'Vorlage löschen?\')" class="button-small">'.$langs->trans("Delete").'</a>';
|
||||
.'data-dolconfirm="Vorlage löschen?" class="button-small">'.$langs->trans("Delete").'</a>';
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ if (!$bericht) {
|
|||
}
|
||||
if ($mode !== 'from_order' && $user->hasRight('bericht', 'delete')) {
|
||||
print '<a href="'.$_SERVER['PHP_SELF'].'?action=delete&berichtid='.$b->id.'&token='.newToken().'" '
|
||||
.'onclick="return confirm(\''.dol_escape_js($langs->trans("BerichtConfirmDelete")).'\')" '
|
||||
.'data-dolconfirm="'.dol_escape_htmltag($langs->trans("BerichtConfirmDelete")).'" '
|
||||
.'class="button-small button-delete">'.$langs->trans("Delete").'</a>';
|
||||
}
|
||||
print '</td>';
|
||||
|
|
@ -548,12 +548,12 @@ if (!$bericht) {
|
|||
print '<button type="button" id="btn-preview" class="butAction" title="PDF-Vorschau ansehen ohne zu finalisieren">👁️ Vorschau</button>';
|
||||
print '<button type="button" id="btn-save-as-template" class="butAction" title="Aktuellen Bericht als wiederverwendbare Vorlage speichern">📋 Als Vorlage</button>';
|
||||
print '<a href="'.$_SERVER['PHP_SELF'].'?action=new_version&berichtid='.$bericht->id.'&token='.newToken().'" '
|
||||
.'onclick="return confirm(\'Neue Version (v'.((int)$bericht->version + 1).') erstellen? Der aktuelle Bericht bleibt unverändert.\')" '
|
||||
.'data-dolconfirm="Neue Version (v'.((int)$bericht->version + 1).') erstellen? Der aktuelle Bericht bleibt unverändert." '
|
||||
.'class="butAction" title="Neue Version des Berichts anlegen, aktueller bleibt erhalten">🔀 Neue Version</a>';
|
||||
print '<button type="button" id="btn-finalize" class="butActionConfirm" title="PDF erzeugen und unter Verknüpfte Dokumente ablegen">📑 '.$langs->trans("BerichtFinalize").'</button>';
|
||||
print '<button type="button" id="btn-finalize" class="butAction" title="PDF erzeugen und unter Verknüpfte Dokumente ablegen">📑 '.$langs->trans("BerichtFinalize").'</button>';
|
||||
if ($user->hasRight('bericht', 'delete')) {
|
||||
print '<a href="'.$_SERVER['PHP_SELF'].'?action=delete&berichtid='.$bericht->id.'&token='.newToken().'" '
|
||||
.'onclick="return confirm(\''.dol_escape_js($langs->trans("BerichtConfirmDelete")).'\')" '
|
||||
.'data-dolconfirm="'.dol_escape_htmltag($langs->trans("BerichtConfirmDelete")).'" '
|
||||
.'class="butActionDelete">🗑️ '.$langs->trans("Delete").'</a>';
|
||||
}
|
||||
print '</div>';
|
||||
|
|
|
|||
|
|
@ -494,3 +494,48 @@
|
|||
.qr-url-display { word-break: break-all; }
|
||||
.qr-url-display a { color: var(--colortextlink, #7aa2f7); }
|
||||
.qr-status { padding: 8px; background: var(--colorbackbody, #1a1a1f); border-radius: 4px; margin-top: 12px; }
|
||||
|
||||
/* ---------- dolModal (alert/confirm/prompt Ersatz) ---------- */
|
||||
.bericht-dolmodal-overlay {
|
||||
position: fixed; inset: 0;
|
||||
background: rgba(0,0,0,0.55);
|
||||
z-index: 100000;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.bericht-dolmodal {
|
||||
background: var(--colorbackbody, #22222a);
|
||||
color: var(--colortext, #eee);
|
||||
border: 1px solid var(--colorboxbordertitle1, #444);
|
||||
border-radius: 6px;
|
||||
min-width: 320px; max-width: 520px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.6);
|
||||
font-size: 14px;
|
||||
}
|
||||
.bericht-dolmodal-title {
|
||||
padding: 10px 14px;
|
||||
font-weight: bold;
|
||||
background: var(--colorbacktitle1, #2d2d38);
|
||||
border-bottom: 1px solid var(--colorboxbordertitle1, #444);
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
.bericht-dolmodal-body {
|
||||
padding: 16px 14px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.bericht-dolmodal-input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
padding: 6px 8px;
|
||||
background: var(--colorbackbody, #1a1a1f);
|
||||
color: var(--colortext, #eee);
|
||||
border: 1px solid var(--colorboxbordertitle1, #555);
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.bericht-dolmodal-foot {
|
||||
padding: 10px 14px;
|
||||
display: flex; gap: 8px; justify-content: flex-end;
|
||||
border-top: 1px solid var(--colorboxbordertitle1, #444);
|
||||
}
|
||||
|
|
|
|||
118
js/editor.js
118
js/editor.js
|
|
@ -865,7 +865,7 @@
|
|||
const tplBtn = document.getElementById('btn-save-as-template');
|
||||
if (tplBtn) {
|
||||
tplBtn.addEventListener('click', async () => {
|
||||
const label = prompt('Label für die Vorlage:\n(z. B. "PV-Anlage Standard" oder "Wallbox 11kW")');
|
||||
const label = await dolPrompt('Label für die Vorlage (z. B. "PV-Anlage Standard" oder "Wallbox 11kW")');
|
||||
if (!label) return;
|
||||
await savePageAnnotations(false);
|
||||
const fd = new FormData();
|
||||
|
|
@ -875,12 +875,12 @@
|
|||
const r = await fetch(cfg.urls.save_as_template, { method: 'POST', body: fd });
|
||||
const data = await r.json();
|
||||
if (data.success) toast('✓ Vorlage "' + label + '" gespeichert');
|
||||
else alert('Fehler: ' + (data.error || ''));
|
||||
else dolAlert('Fehler: ' + (data.error || ''));
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('btn-finalize').addEventListener('click', async () => {
|
||||
if (!confirm('Bericht jetzt finalisieren und PDF erzeugen?')) return;
|
||||
if (!(await dolConfirm('Bericht jetzt finalisieren und PDF erzeugen?'))) return;
|
||||
toast('Speichere aktuelle Seite…');
|
||||
await savePageAnnotations(false);
|
||||
toast('PDF wird erzeugt…');
|
||||
|
|
@ -918,7 +918,7 @@
|
|||
btn.addEventListener('click', async () => {
|
||||
const checks = document.querySelectorAll('.att-check:checked');
|
||||
if (!checks.length) {
|
||||
alert('Bitte zuerst Bilder ankreuzen');
|
||||
dolAlert('Bitte zuerst Bilder ankreuzen');
|
||||
return;
|
||||
}
|
||||
const layout = layoutSel ? layoutSel.value : 'single';
|
||||
|
|
@ -942,7 +942,7 @@
|
|||
const slotCount = { grid_2: 2, grid_2v: 2, grid_4: 4, grid_6: 6, before_after: 2 }[layout] || 4;
|
||||
const imageChecks = Array.from(checks).filter(c => c.dataset.mime.startsWith('image'));
|
||||
if (!imageChecks.length) {
|
||||
alert('Bitte mindestens ein Bild ankreuzen (PDFs nicht in Grids unterstützt)');
|
||||
dolAlert('Bitte mindestens ein Bild ankreuzen (PDFs nicht in Grids unterstützt)');
|
||||
return;
|
||||
}
|
||||
// In Gruppen à slotCount aufteilen
|
||||
|
|
@ -956,7 +956,7 @@
|
|||
const r = await fetch(cfg.urls.create_grid_page, { method: 'POST', body: fd });
|
||||
const data = await r.json().catch(() => ({}));
|
||||
if (!data.success) {
|
||||
alert('Fehler bei Gruppe '+(Math.floor(i/slotCount)+1)+': '+(data.error || 'unbekannt'));
|
||||
dolAlert('Fehler bei Gruppe '+(Math.floor(i/slotCount)+1)+': '+(data.error || 'unbekannt'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -972,7 +972,7 @@
|
|||
const rel = btn.dataset.relpath;
|
||||
const ref = btn.dataset.sourceRef || '';
|
||||
const name = btn.parentElement.querySelector('.att-name')?.textContent || rel;
|
||||
if (!confirm('Datei "' + name + '" aus ' + (ref ? ref : 'dem Anhang') + ' wirklich löschen?\n\nDiese Aktion kann nicht rückgängig gemacht werden.')) return;
|
||||
if (!(await dolConfirm('Datei "' + name + '" aus ' + (ref ? ref : 'dem Anhang') + ' wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.'))) return;
|
||||
const fd = new FormData();
|
||||
fd.append('token', cfg.token);
|
||||
fd.append('relpath', rel);
|
||||
|
|
@ -982,7 +982,7 @@
|
|||
btn.parentElement.remove();
|
||||
toast('Datei gelöscht');
|
||||
} else {
|
||||
alert('Löschen fehlgeschlagen: ' + (data.error || 'unbekannt'));
|
||||
dolAlert('Löschen fehlgeschlagen: ' + (data.error || 'unbekannt'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -1000,7 +1000,7 @@
|
|||
const r = await fetch(cfg.urls.upload_extra, { method: 'POST', body: fd });
|
||||
const data = await r.json();
|
||||
if (data.success) location.reload();
|
||||
else alert('Upload fehlgeschlagen: ' + (data.error || ''));
|
||||
else dolAlert('Upload fehlgeschlagen: ' + (data.error || ''));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1023,7 +1023,7 @@
|
|||
const r = await fetch(cfg.urls.create_upload_token, { method: 'POST', body: fd });
|
||||
const data = await r.json();
|
||||
if (!data.success) {
|
||||
alert('Token-Erstellung fehlgeschlagen: ' + (data.error || ''));
|
||||
dolAlert('Token-Erstellung fehlgeschlagen: ' + (data.error || ''));
|
||||
return;
|
||||
}
|
||||
const url = data.url;
|
||||
|
|
@ -1080,7 +1080,7 @@
|
|||
const del = t.querySelector('.thumb-del');
|
||||
if (del) del.addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
if (!confirm(cfg.lang.confirm_del)) return;
|
||||
if (!(await dolConfirm(cfg.lang.confirm_del))) return;
|
||||
const fd = new FormData();
|
||||
fd.append('token', cfg.token);
|
||||
fd.append('pageid', t.dataset.pageid);
|
||||
|
|
@ -1111,13 +1111,13 @@
|
|||
const data = await r.json();
|
||||
btn.textContent = '🔍';
|
||||
if (!data.success) {
|
||||
alert('Fehler: ' + (data.error || 'unbekannt'));
|
||||
dolAlert('Fehler: ' + (data.error || 'unbekannt'));
|
||||
return;
|
||||
}
|
||||
showSignatureVerifyResult(data);
|
||||
} catch (err) {
|
||||
btn.textContent = '🔍';
|
||||
alert('Netzwerkfehler: ' + err.message);
|
||||
dolAlert('Netzwerkfehler: ' + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -1261,5 +1261,97 @@
|
|||
setTimeout(() => t.remove(), 2000);
|
||||
}
|
||||
|
||||
/* ---------- Dolibarr-Style Modal-Dialoge (ersetzen alert/confirm/prompt) ---------- */
|
||||
function dolModal(opts) {
|
||||
// opts: { title, body, buttons:[{label, value, primary}], input:boolean, defaultValue }
|
||||
return new Promise((resolve) => {
|
||||
const ov = document.createElement('div');
|
||||
ov.className = 'bericht-dolmodal-overlay';
|
||||
const box = document.createElement('div');
|
||||
box.className = 'bericht-dolmodal';
|
||||
const h = document.createElement('div');
|
||||
h.className = 'bericht-dolmodal-title';
|
||||
h.textContent = opts.title || 'Bericht';
|
||||
const b = document.createElement('div');
|
||||
b.className = 'bericht-dolmodal-body';
|
||||
b.textContent = opts.body || '';
|
||||
let inputEl = null;
|
||||
if (opts.input) {
|
||||
inputEl = document.createElement('input');
|
||||
inputEl.type = 'text';
|
||||
inputEl.className = 'bericht-dolmodal-input';
|
||||
inputEl.value = opts.defaultValue || '';
|
||||
b.appendChild(document.createElement('br'));
|
||||
b.appendChild(inputEl);
|
||||
}
|
||||
const foot = document.createElement('div');
|
||||
foot.className = 'bericht-dolmodal-foot';
|
||||
(opts.buttons || [{label:'OK', value:true, primary:true}]).forEach(btn => {
|
||||
const el = document.createElement('button');
|
||||
el.type = 'button';
|
||||
el.className = btn.primary ? 'butAction butActionConfirm' : 'butAction';
|
||||
el.textContent = btn.label;
|
||||
el.addEventListener('click', () => {
|
||||
const val = opts.input ? (btn.value ? (inputEl.value || null) : null) : btn.value;
|
||||
ov.remove();
|
||||
resolve(val);
|
||||
});
|
||||
foot.appendChild(el);
|
||||
});
|
||||
box.appendChild(h); box.appendChild(b); box.appendChild(foot);
|
||||
ov.appendChild(box);
|
||||
document.body.appendChild(ov);
|
||||
if (inputEl) { inputEl.focus(); inputEl.select(); }
|
||||
ov.addEventListener('click', (e) => {
|
||||
if (e.target === ov) { ov.remove(); resolve(opts.input ? null : false); }
|
||||
});
|
||||
});
|
||||
}
|
||||
async function dolAlert(msg, title) {
|
||||
return dolModal({
|
||||
title: title || 'Hinweis',
|
||||
body: msg,
|
||||
buttons: [{label:'OK', value:true, primary:true}],
|
||||
});
|
||||
}
|
||||
async function dolConfirm(msg, title) {
|
||||
return dolModal({
|
||||
title: title || 'Bestätigen',
|
||||
body: msg,
|
||||
buttons: [
|
||||
{label:'Abbrechen', value:false},
|
||||
{label:'OK', value:true, primary:true},
|
||||
],
|
||||
});
|
||||
}
|
||||
async function dolPrompt(msg, defaultValue, title) {
|
||||
return dolModal({
|
||||
title: title || 'Eingabe',
|
||||
body: msg,
|
||||
input: true,
|
||||
defaultValue: defaultValue || '',
|
||||
buttons: [
|
||||
{label:'Abbrechen', value:false},
|
||||
{label:'OK', value:true, primary:true},
|
||||
],
|
||||
});
|
||||
}
|
||||
// Globaler Handler: Links/Buttons mit data-dolconfirm abfangen
|
||||
document.addEventListener('click', async (e) => {
|
||||
const el = e.target.closest('[data-dolconfirm]');
|
||||
if (!el) return;
|
||||
if (el.dataset._dolconfirmed === '1') return; // schon durchgelaufen
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const ok = await dolConfirm(el.getAttribute('data-dolconfirm'));
|
||||
if (!ok) return;
|
||||
el.dataset._dolconfirmed = '1';
|
||||
if (el.tagName === 'A') {
|
||||
window.location.href = el.getAttribute('href');
|
||||
} else {
|
||||
el.click();
|
||||
}
|
||||
}, true);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in a new issue