Sprečeno dupliranje prodaje/servisa, alat za usklađivanje šifri artikla, ispravke osvežavanja stranica, zaštita od duplikata kategorije/artikla/usluge/troška
- Prodaja i servis: broj naloga se generiše unutar transakcije upisa umesto unapred u handleru, čime se otklanja duplo kreiranje naloga pri dvostrukom slanju forme - Servis izmena: uklonjen sudar generičkog i sopstvenog auto-snimanja forme (dva paralelna POST-a) - Magacin: novi alat 'Uskladi šifre sa kategorijama' za masovnu ispravku šifri artikala posle uvođenja šifarnika po kategoriji - Ispravljeno da forme na 9 stranica (kategorije, admin korisnici/dozvole, profil, podešavanja) posle akcije osveže prikaz umesto da ostanu zastarele do F5 - Kategorija, artikal, usluga i trošak: sprečeno dupliranje naziva/šifre/koda (UNIQUE indeksi + razumljive poruke grešaka)
This commit is contained in:
@@ -1,3 +1,26 @@
|
||||
// generička zaštita od duplog slanja forme: onemogući submit dugme(ad) čim
|
||||
// forma krene da se šalje (spor internet/dupli klik/Enter+klik ne pravi drugi
|
||||
// POST). Dodaj data-ne-onemoguci="1" na formu da se isključi (npr. forme sa
|
||||
// više imenovanih submit dugmadi gde različit klik nosi različitu vrednost).
|
||||
document.addEventListener('submit', function(e) {
|
||||
var forma = e.target;
|
||||
if (!(forma instanceof HTMLFormElement)) return;
|
||||
if (forma.dataset.neOnemoguci === '1') return;
|
||||
var dugmad = forma.querySelectorAll('button[type="submit"]:not([name]), input[type="submit"]:not([name])');
|
||||
setTimeout(function() {
|
||||
dugmad.forEach(function(btn) { btn.disabled = true; });
|
||||
}, 0);
|
||||
}, true);
|
||||
|
||||
// ako se stranica vrati iz bfcache-a (dugme nazad/napred), vrati dugmad u
|
||||
// normalno stanje da forma ostane upotrebljiva
|
||||
window.addEventListener('pageshow', function(e) {
|
||||
if (!e.persisted) return;
|
||||
document.querySelectorAll('button[type="submit"]:disabled, input[type="submit"]:disabled').forEach(function(btn) {
|
||||
btn.disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
// otvara/zatvara podmeni u sidebaru — radi i kad je sidebar skupljen i kad je proširen
|
||||
// (sidebar ostaje u zatečenom stanju). U isto vreme sme biti otvoren samo jedan podmeni.
|
||||
function ntechTogglePodmeni(btn) {
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
<div class="kolona" style="gap:20px;">
|
||||
|
||||
<!-- matrica dozvola — editabilna forma -->
|
||||
<div class="kartica animiraj" style="padding:0;overflow:hidden;">
|
||||
<div id="dozvole-kartica" class="kartica animiraj" style="padding:0;overflow:hidden;">
|
||||
<div style="padding:14px 16px;border-bottom:0.5px solid var(--ivica);">
|
||||
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Dozvole po ulogama</span>
|
||||
</div>
|
||||
<form method="POST" action="/admin/dozvole/sacuvaj">
|
||||
<form method="POST" action="/admin/dozvole/sacuvaj" data-refresh="#dozvole-kartica">
|
||||
<div style="overflow-x:auto;">
|
||||
<table class="tabela">
|
||||
<thead>
|
||||
@@ -299,7 +299,7 @@
|
||||
</form>
|
||||
|
||||
<!-- zasebna forma za reset, bez vidljivih elemenata -->
|
||||
<form id="forma-reset" method="POST" action="/admin/dozvole/reset"></form>
|
||||
<form id="forma-reset" method="POST" action="/admin/dozvole/reset" data-refresh="#dozvole-kartica"></form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
{{if eq .Uloga "superadmin"}}
|
||||
<span class="pomocni-tekst">Superadmin</span>
|
||||
{{else if eq $.KorisnikUloga "superadmin"}}
|
||||
<form method="POST" action="/admin/korisnici/{{.ID}}/uloga" style="display:inline;">
|
||||
<form method="POST" action="/admin/korisnici/{{.ID}}/uloga" data-refresh="#lista-korisnika-kartica" style="display:inline;">
|
||||
<select name="uloga" onchange="this.form.submit()"
|
||||
style="padding:4px 8px;border:0.5px solid var(--ivica);border-radius:6px;background:var(--pozadina);color:var(--tekst-glavni);font-size:12px;">
|
||||
<option value="admin" {{if eq .Uloga "admin"}}selected{{end}}>Admin</option>
|
||||
@@ -74,14 +74,14 @@
|
||||
Istorija prijava
|
||||
</a>
|
||||
{{if ne .KorisnickoIme $.KorisnikIme}}
|
||||
<form method="POST" action="/admin/korisnici/{{.ID}}/aktivan" style="display:inline;">
|
||||
<form method="POST" action="/admin/korisnici/{{.ID}}/aktivan" data-refresh="#lista-korisnika-kartica" style="display:inline;">
|
||||
<button type="submit"
|
||||
style="padding:5px 12px;border:0.5px solid var(--ivica);border-radius:6px;background:transparent;color:var(--tekst-sporedni);font-size:12px;cursor:pointer;">
|
||||
{{if .Aktivan}}Deaktiviraj{{else}}Aktiviraj{{end}}
|
||||
</button>
|
||||
</form>
|
||||
{{if eq .Uloga "radnik"}}
|
||||
<form method="POST" action="/admin/korisnici/{{.ID}}/obrisi" style="display:inline;">
|
||||
<form method="POST" action="/admin/korisnici/{{.ID}}/obrisi" data-refresh="#lista-korisnika-kartica" style="display:inline;">
|
||||
<button type="submit"
|
||||
class="btn-obrisi-ghost"
|
||||
data-potvrda="Obrisati korisnika {{.KorisnickoIme}}? Ova radnja je trajna.">
|
||||
|
||||
@@ -19,17 +19,19 @@
|
||||
{{define "sadrzaj"}}
|
||||
<div class="kolona" style="gap:16px;">
|
||||
|
||||
{{if .Sacuvano}}
|
||||
<div class="poruka-uspeh poruka-animacija">Kategorija je uspešno sačuvana.</div>
|
||||
{{end}}
|
||||
{{if .Obrisana}}
|
||||
<div class="poruka-uspeh poruka-animacija">Kategorija je uspešno obrisana.</div>
|
||||
{{end}}
|
||||
{{if .PrikaziSifreDod}}
|
||||
<div class="poruka-uspeh poruka-animacija">
|
||||
{{if eq .SifreDodeljene 0}}Svi artikli već imaju šifru.{{else}}Dodeljena šifra za {{.SifreDodeljene}} artikal(a).{{end}}
|
||||
<div id="kat-poruke">
|
||||
{{if .Sacuvano}}
|
||||
<div class="poruka-uspeh poruka-animacija">Kategorija je uspešno sačuvana.</div>
|
||||
{{end}}
|
||||
{{if .Obrisana}}
|
||||
<div class="poruka-uspeh poruka-animacija">Kategorija je uspešno obrisana.</div>
|
||||
{{end}}
|
||||
{{if .PrikaziSifreDod}}
|
||||
<div class="poruka-uspeh poruka-animacija">
|
||||
{{if eq .SifreDodeljene 0}}Svi artikli već imaju šifru.{{else}}Dodeljena šifra za {{.SifreDodeljene}} artikal(a).{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- nazad dugme -->
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;">
|
||||
@@ -38,12 +40,18 @@
|
||||
Nazad na magacin
|
||||
</a>
|
||||
{{if index $.Dozvole "artikal.izmeni"}}
|
||||
<form method="POST" action="/magacin/kategorije/dodeli-sifre">
|
||||
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;"
|
||||
data-potvrda="Proći kroz sve artikle bez šifre i dodeliti im šifru na osnovu prefiksa njihove kategorije?">
|
||||
Dodeli šifre artiklima bez šifre
|
||||
</button>
|
||||
</form>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;">
|
||||
<form method="POST" action="/magacin/kategorije/dodeli-sifre" data-refresh="#kat-poruke, #kategorije-lista">
|
||||
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;"
|
||||
data-potvrda="Proći kroz sve artikle bez šifre i dodeliti im šifru na osnovu prefiksa njihove kategorije?">
|
||||
Dodeli šifre artiklima bez šifre
|
||||
</button>
|
||||
</form>
|
||||
<a href="/magacin/kategorije/uskladi-sifre" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;"
|
||||
hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML">
|
||||
Uskladi šifre sa kategorijama
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -53,7 +61,7 @@
|
||||
<div style="margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
|
||||
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Nova kategorija</span>
|
||||
</div>
|
||||
<form method="POST" action="/magacin/kategorije/dodaj">
|
||||
<form method="POST" action="/magacin/kategorije/dodaj" data-refresh="#kat-poruke, #kategorije-lista">
|
||||
<div class="kolona" style="gap:12px;">
|
||||
<div>
|
||||
<label class="polje-labela">
|
||||
@@ -90,7 +98,7 @@
|
||||
{{end}}
|
||||
|
||||
<!-- lista kategorija -->
|
||||
<div class="kartica" style="padding:0;overflow:hidden;">
|
||||
<div id="kategorije-lista" class="kartica" style="padding:0;overflow:hidden;">
|
||||
<div style="padding:14px 16px;border-bottom:0.5px solid var(--ivica);">
|
||||
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Postojeće kategorije</span>
|
||||
</div>
|
||||
@@ -116,7 +124,7 @@
|
||||
<h3>Izmeni kategoriju</h3>
|
||||
<button type="submit" class="premesti-zatvori" aria-label="Zatvori">×</button>
|
||||
</form>
|
||||
<form method="POST" action="/magacin/kategorije/izmeni/{{.ID}}" style="display:flex;flex-direction:column;gap:12px;padding:16px;">
|
||||
<form method="POST" action="/magacin/kategorije/izmeni/{{.ID}}" data-refresh="#kat-poruke, #kategorije-lista" style="display:flex;flex-direction:column;gap:12px;padding:16px;">
|
||||
<div>
|
||||
<label class="polje-labela">Naziv <span style="color:#dc2626;">*</span></label>
|
||||
<input type="text" name="naziv" value="{{.Naziv}}" required
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "naslov"}}Usklađivanje šifri — NTech{{end}}
|
||||
|
||||
{{define "sadrzaj"}}
|
||||
<div class="kolona" style="gap:16px;">
|
||||
|
||||
<!-- nazad dugme -->
|
||||
<div>
|
||||
<a href="/magacin/kategorije" class="nazad-link" hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
Nazad na kategorije
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{if not .Plan}}
|
||||
<div class="kartica animiraj">
|
||||
<p style="margin:0;color:var(--tekst-sekundarni);">Sve šifre su već usklađene sa prefiksima svojih kategorija.</p>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="kartica animiraj" style="padding:0;overflow:hidden;">
|
||||
<div style="padding:14px 16px;border-bottom:0.5px solid var(--ivica);">
|
||||
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Predložene izmene ({{len .Plan}})</span>
|
||||
<p class="pomocni-tekst" style="margin:4px 0 0;">Ovo su artikli čija šifra ne odgovara prefiksu njihove kategorije. Pregledaj i potvrdi.</p>
|
||||
</div>
|
||||
<div style="overflow-x:auto;">
|
||||
<table class="tabela">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Artikal</th>
|
||||
<th>Kategorija</th>
|
||||
<th>Stara šifra</th>
|
||||
<th>Nova šifra</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Plan}}
|
||||
<tr>
|
||||
<td>{{.Naziv}}</td>
|
||||
<td>{{if .KategorijaNaziv}}{{.KategorijaNaziv}}{{else}}—{{end}}</td>
|
||||
<td>{{if .StaraSifra}}{{.StaraSifra}}{{else}}<em>(bez šifre)</em>{{end}}</td>
|
||||
<td><strong>{{.NovaSifra}}</strong></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="/magacin/kategorije/uskladi-sifre" style="align-self:flex-end;">
|
||||
{{range .Plan}}
|
||||
<input type="hidden" name="artikal_id" value="{{.ArtikalID}}">
|
||||
<input type="hidden" name="nova_sifra" value="{{.NovaSifra}}">
|
||||
{{end}}
|
||||
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 20px;"
|
||||
data-potvrda="Primeniti prikazane izmene šifri za {{len .Plan}} artikal(a)?">
|
||||
Potvrdi izmenu
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -16,20 +16,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
||||
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Pozadinska slika prijave</span>
|
||||
</div>
|
||||
{{if .LoginPozadina}}
|
||||
<div style="margin-bottom:14px;display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap;">
|
||||
<img src="{{.LoginPozadina}}" alt="Trenutna pozadina"
|
||||
style="width:160px;height:90px;object-fit:cover;border:0.5px solid var(--ivica);border-radius:8px;">
|
||||
<form method="POST" action="/podesavanja/login-pozadina/ukloni">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit"
|
||||
class="btn-obrisi-ghost" style="padding:7px 14px;border-radius:8px;"
|
||||
data-potvrda="Ukloniti pozadinsku sliku?">
|
||||
Ukloni sliku
|
||||
</button>
|
||||
</form>
|
||||
<div id="login-pozadina-blok">
|
||||
{{if .LoginPozadina}}
|
||||
<div style="margin-bottom:14px;display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap;">
|
||||
<img src="{{.LoginPozadina}}" alt="Trenutna pozadina"
|
||||
style="width:160px;height:90px;object-fit:cover;border:0.5px solid var(--ivica);border-radius:8px;">
|
||||
<form method="POST" action="/podesavanja/login-pozadina/ukloni" data-refresh="#login-pozadina-blok">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit"
|
||||
class="btn-obrisi-ghost" style="padding:7px 14px;border-radius:8px;"
|
||||
data-potvrda="Ukloniti pozadinsku sliku?">
|
||||
Ukloni sliku
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
<form method="POST" action="/podesavanja/login-pozadina" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
||||
|
||||
@@ -15,19 +15,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
||||
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Logo firme</span>
|
||||
</div>
|
||||
{{if .LogoPutanja}}
|
||||
<div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
|
||||
<img src="{{.LogoPutanja}}" alt="Trenutni logo"
|
||||
style="max-height:60px;max-width:200px;object-fit:contain;border:0.5px solid var(--ivica);border-radius:8px;padding:6px;background:var(--kartica);flex-shrink:0;">
|
||||
<form method="POST" action="/podesavanja/logo/ukloni" style="margin:0;">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit"
|
||||
style="padding:6px 14px;background:none;border:0.5px solid #dc2626;color:#dc2626;border-radius:8px;font-size:13px;cursor:pointer;white-space:nowrap;">
|
||||
Ukloni sliku
|
||||
</button>
|
||||
</form>
|
||||
<div id="logo-blok">
|
||||
{{if .LogoPutanja}}
|
||||
<div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
|
||||
<img src="{{.LogoPutanja}}" alt="Trenutni logo"
|
||||
style="max-height:60px;max-width:200px;object-fit:contain;border:0.5px solid var(--ivica);border-radius:8px;padding:6px;background:var(--kartica);flex-shrink:0;">
|
||||
<form method="POST" action="/podesavanja/logo/ukloni" data-refresh="#logo-blok" style="margin:0;">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit"
|
||||
style="padding:6px 14px;background:none;border:0.5px solid #dc2626;color:#dc2626;border-radius:8px;font-size:13px;cursor:pointer;white-space:nowrap;">
|
||||
Ukloni sliku
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
<form method="POST" action="/podesavanja/logo" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;">
|
||||
|
||||
@@ -192,28 +192,30 @@
|
||||
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Moj avatar</span>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;align-items:center;gap:16px;margin-bottom:16px;">
|
||||
<div style="width:64px;height:64px;border-radius:10px;overflow:hidden;border:0.5px solid var(--ivica);flex-shrink:0;background:var(--pozadina);display:flex;align-items:center;justify-content:center;">
|
||||
{{if .AvatarPutanja}}
|
||||
<img src="{{.AvatarPutanja}}" alt="Moj avatar" style="width:100%;height:100%;object-fit:cover;">
|
||||
{{else}}
|
||||
<span style="font-size:22px;font-weight:600;color:var(--tekst-sporedni);">{{if .KorisnikIme}}{{slice .KorisnikIme 0 2}}{{else}}NT{{end}}</span>
|
||||
{{end}}
|
||||
<div id="avatar-blok">
|
||||
<div style="display:flex;align-items:center;gap:16px;margin-bottom:16px;">
|
||||
<div style="width:64px;height:64px;border-radius:10px;overflow:hidden;border:0.5px solid var(--ivica);flex-shrink:0;background:var(--pozadina);display:flex;align-items:center;justify-content:center;">
|
||||
{{if .AvatarPutanja}}
|
||||
<img src="{{.AvatarPutanja}}" alt="Moj avatar" style="width:100%;height:100%;object-fit:cover;">
|
||||
{{else}}
|
||||
<span style="font-size:22px;font-weight:600;color:var(--tekst-sporedni);">{{if .KorisnikIme}}{{slice .KorisnikIme 0 2}}{{else}}NT{{end}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.5;">
|
||||
Slika se prikazuje kao dugme u gornjoj traci.<br>
|
||||
Dozvoljeni formati: JPG, PNG, WebP. Maksimum 2 MB.
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.5;">
|
||||
Slika se prikazuje kao dugme u gornjoj traci.<br>
|
||||
Dozvoljeni formati: JPG, PNG, WebP. Maksimum 2 MB.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if .AvatarPutanja}}
|
||||
<form method="POST" action="/profil/avatar/ukloni" style="display:inline;margin-bottom:12px;">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit" style="background:none;border:0.5px solid #dc2626;color:#dc2626;padding:6px 14px;border-radius:8px;font-size:13px;cursor:pointer;margin-bottom:12px;">
|
||||
Ukloni avatar
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{if .AvatarPutanja}}
|
||||
<form method="POST" action="/profil/avatar/ukloni" data-refresh="#avatar-blok" style="display:inline;margin-bottom:12px;">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit" style="background:none;border:0.5px solid #dc2626;color:#dc2626;padding:6px 14px;border-radius:8px;font-size:13px;cursor:pointer;margin-bottom:12px;">
|
||||
Ukloni avatar
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<form method="POST" action="/profil/avatar" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
@@ -240,20 +242,22 @@
|
||||
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Moja pozadinska slika</span>
|
||||
</div>
|
||||
|
||||
{{if .LokalnaPozadina}}
|
||||
<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px;">
|
||||
<img src="{{.LokalnaPozadina}}" alt="Trenutna lična pozadina"
|
||||
style="width:120px;height:70px;object-fit:cover;border-radius:6px;border:0.5px solid var(--ivica);flex-shrink:0;">
|
||||
<form method="POST" action="/profil/pozadina/ukloni">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit"
|
||||
class="btn-obrisi-ghost" style="padding:7px 14px;border-radius:8px;font-size:13px;"
|
||||
data-potvrda="Ukloniti ličnu pozadinsku sliku?">
|
||||
Ukloni
|
||||
</button>
|
||||
</form>
|
||||
<div id="pozadina-blok">
|
||||
{{if .LokalnaPozadina}}
|
||||
<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px;">
|
||||
<img src="{{.LokalnaPozadina}}" alt="Trenutna lična pozadina"
|
||||
style="width:120px;height:70px;object-fit:cover;border-radius:6px;border:0.5px solid var(--ivica);flex-shrink:0;">
|
||||
<form method="POST" action="/profil/pozadina/ukloni" data-refresh="#pozadina-blok">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
<button type="submit"
|
||||
class="btn-obrisi-ghost" style="padding:7px 14px;border-radius:8px;font-size:13px;"
|
||||
data-potvrda="Ukloniti ličnu pozadinsku sliku?">
|
||||
Ukloni
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<form method="POST" action="/profil/pozadina" enctype="multipart/form-data">
|
||||
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
||||
|
||||
@@ -25,7 +25,11 @@
|
||||
<div class="poruka-greska greska-animacija" style="margin-bottom:16px;">{{.Greska}}</div>
|
||||
{{end}}
|
||||
|
||||
<form id="forma-nalog" method="POST" action="{{if .Izmena}}/servis/izmeni/{{.Nalog.ID}}{{else}}/servis/novi{{end}}"{{if .Izmena}} data-autosave="1"{{end}}>
|
||||
<!-- data-autosave-custom (NE data-autosave) — ova forma ima SOPSTVENI auto-save skript
|
||||
ispod (šalje X-Autosave header, prikazuje status "Čuvam.../Sačuvano ✓"). Generički
|
||||
data-autosave mehanizam iz base.html bi se kačio na isti 'change' event i slao
|
||||
DRUGI, konfliktni POST bez tog headera — otud namerno drugačije ime atributa. -->
|
||||
<form id="forma-nalog" method="POST" action="{{if .Izmena}}/servis/izmeni/{{.Nalog.ID}}{{else}}/servis/novi{{end}}"{{if .Izmena}} data-autosave-custom="1"{{end}}>
|
||||
|
||||
<!-- broj naloga ide kao hidden — server ga je generisao, vraćamo ga pri POST-u -->
|
||||
<input type="hidden" name="broj_naloga" value="{{.Nalog.BrojNaloga}}">
|
||||
@@ -311,7 +315,7 @@
|
||||
// a za select/date/checkbox na izbor — jedan slušalac pokriva sve tipove.
|
||||
(function () {
|
||||
var forma = document.getElementById('forma-nalog');
|
||||
if (!forma || forma.dataset.autosave !== '1') return;
|
||||
if (!forma || forma.dataset.autosaveCustom !== '1') return;
|
||||
var status = document.getElementById('autosave-status');
|
||||
var slanjeUToku = false;
|
||||
var ponoviPoZavrsetku = false;
|
||||
|
||||
@@ -441,6 +441,23 @@
|
||||
});
|
||||
}
|
||||
});
|
||||
// flash poruka (SetFlash, npr. greška validacije) možda NIJE postojala
|
||||
// u trenutnom DOM-u pre ovog zahteva — replaceWith gore je ne bi ubacio
|
||||
// (menja samo postojeće elemente), pa je ovde dodajemo posebno ako se
|
||||
// pojavila u svežem odgovoru.
|
||||
var flashNovi = doc.getElementById('flash-toast');
|
||||
if (flashNovi) {
|
||||
var flashStari = document.getElementById('flash-toast');
|
||||
if (flashStari) flashStari.remove();
|
||||
var glavni = document.getElementById('sadrzaj');
|
||||
if (glavni) {
|
||||
glavni.insertBefore(flashNovi, glavni.firstChild);
|
||||
setTimeout(function () {
|
||||
flashNovi.classList.add('flash-izlaz');
|
||||
setTimeout(function () { if (flashNovi.parentElement) flashNovi.remove(); }, 350);
|
||||
}, 4000);
|
||||
}
|
||||
}
|
||||
if (sc) sc.scrollTop = syDoc;
|
||||
var gsNovi = document.getElementById('sadrzaj');
|
||||
if (gsNovi) gsNovi.scrollTop = syGs;
|
||||
|
||||
Reference in New Issue
Block a user