d5edbe2134
- Halaman Nilai: tabel "Nilai per Komponen" (rata-rata skor mentah tiap sesi, bisa diedit langsung) berdampingan dengan grid Sub-CPMK yang tetap presisi; kolom persentase ternilai di Hasil Ketercapaian. - Komponen Tugas: sesi bisa menyasar subset Sub-CPMK (RPS tetap batasannya), lengkap dengan field ala RTM (bentuk tugas, deskripsi, metode, luaran, indikator/bobot, jadwal) dan tombol isi-otomatis per bentuk tugas. - RPS: auto-save berkala sebagai draft, tombol ke atas, validasi total bobot komponen 100% saat ditandai selesai, komponen berbobot kosong disembunyikan dari halaman Nilai. - Admin: tampilkan kelas yang tersedia dari data mahasiswa saat mengatur penugasan dosen per kelas. - Perbaikan step="any" pada input nilai (mencegah validasi HTML5 menolak nilai desimal hasil roll-up). - Tambah METODOLOGI_ASESMEN_KOMPONEN.md: dokumentasi metodologi Sub-CPMK vs komponen, termasuk skenario tugas menyasar sebagian Sub-CPMK. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
349 lines
19 KiB
HTML
349 lines
19 KiB
HTML
{% extends "base.html" %}
|
||
{% block judul %}RPS {{ peta.nama }} — Informatika UNTAN{% endblock %}
|
||
{% block isi %}
|
||
<div class="nav-baris">
|
||
<div>MK ini: <b>RPS</b> · <a href="/nilai/{{ peta.kode }}">Input Nilai</a> · <a href="/portofolio/{{ peta.kode }}">Portofolio</a></div>
|
||
<div>
|
||
<span id="status-stamp">
|
||
{% if status == 'selesai' %}<span class="stamp stamp-ok">SELESAI</span>
|
||
{% elif status == 'draft' %}<span class="stamp stamp-draft">DRAFT</span>
|
||
{% else %}<span class="stamp stamp-no">BELUM</span>{% endif %}
|
||
</span>
|
||
<span id="status-waktu" style="color:var(--grey);font-size:13px">{% if updated_at %} · disimpan {{ updated_at }}{% if updated_by %} oleh {{ updated_by }}{% endif %}{% endif %}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<h1>Rencana Pembelajaran Semester — {{ peta.nama }} <span style="color:var(--grey)">({{ peta.kode }})</span></h1>
|
||
|
||
{% if pesan %}<div class="info">{{ pesan }}</div>{% endif %}
|
||
|
||
{% if not boleh_edit %}
|
||
<div class="info">Anda tidak memiliki hak edit RPS untuk MK ini — form terbuka
|
||
<b>hanya untuk dibaca</b>. Ini karena Anda bukan pengampu MK ini, atau peran Anda
|
||
<b>Dosen MK</b> (hanya mengelola nilai & portofolio). Hubungi kaprodi bila ini
|
||
perlu diubah.</div>
|
||
{% endif %}
|
||
|
||
{% if tahun_lain and boleh_edit %}
|
||
<div class="info">
|
||
MK ini punya RPS pada tahun ajaran lain. Salin sebagai titik awal (status draft, bisa diedit):
|
||
{% for t in tahun_lain %}
|
||
<form method="post" action="/rps/{{ peta.kode }}/salin" style="display:inline">
|
||
<input type="hidden" name="dari" value="{{ t }}">
|
||
<button class="tombol garis" type="submit" style="padding:3px 10px;font-size:13px">Salin dari {{ t }}</button>
|
||
</form>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<form method="post" action="/rps/{{ peta.kode }}" id="form-rps">
|
||
<fieldset {% if not boleh_edit %}disabled{% endif %} style="border:none;padding:0;margin:0">
|
||
|
||
<h2 class="bagian">A. IDENTITAS MATA KULIAH</h2>
|
||
<table class="grid">
|
||
<tr><td class="label">Nama Mata Kuliah</td><td>{{ peta.nama }}</td></tr>
|
||
<tr><td class="label">Kode Mata Kuliah</td><td>{{ peta.kode }}</td></tr>
|
||
<tr><td class="label">Bobot SKS</td>
|
||
<td class="isian" style="display:flex;gap:8px;align-items:center;border:none">
|
||
<input type="number" name="sks" min="0" max="8" style="width:70px" value="{{ f.identitas.sks }}"> SKS
|
||
(Teori: <input type="number" name="sks_teori" min="0" max="8" style="width:70px" value="{{ f.identitas.sks_teori }}">
|
||
| Praktikum: <input type="number" name="sks_praktikum" min="0" max="8" style="width:70px" value="{{ f.identitas.sks_praktikum }}">)
|
||
</td></tr>
|
||
<tr><td class="label">Semester</td><td class="isian"><input type="text" name="semester" value="{{ f.identitas.semester }}" placeholder="mis. 3 (Ganjil)"></td></tr>
|
||
<tr><td class="label">Rumpun MK</td><td class="isian"><input type="text" name="rumpun" value="{{ f.identitas.rumpun }}" placeholder="mis. MK Inti Keilmuan"></td></tr>
|
||
<tr><td class="label">MK Prasyarat</td><td class="isian"><input type="text" name="prasyarat" value="{{ f.identitas.prasyarat }}" placeholder="kosongkan bila tidak ada"></td></tr>
|
||
<tr><td class="label">Dosen Pengampu</td><td class="isian"><input type="text" name="pengampu" value="{{ f.identitas.pengampu }}" placeholder="Nama Dosen 1 | Nama Dosen 2"></td></tr>
|
||
<tr><td class="label">Dosen Pengembang RPS</td><td class="isian"><input type="text" name="pengembang" value="{{ f.identitas.pengembang }}" placeholder="bila kosong: diisi nama dosen pengampu"></td></tr>
|
||
<tr><td class="label">Koordinator MK</td><td class="isian"><input type="text" name="koordinator" value="{{ f.identitas.koordinator }}"></td></tr>
|
||
<tr><td class="label">Ketua Program Studi</td><td class="isian"><input type="text" name="kaprodi" value="{{ f.identitas.kaprodi }}"></td></tr>
|
||
<tr><td class="label">Tgl Penyusunan</td><td class="isian"><input type="text" name="tgl_penyusunan" value="{{ f.identitas.tgl_penyusunan }}" placeholder="mis. 13 Juli 2026"></td></tr>
|
||
<tr><td class="label">Kode Dokumen</td><td class="isian"><input type="text" name="kode_dokumen" value="{{ f.identitas.kode_dokumen }}" placeholder="diisi bagian penjaminan mutu, boleh kosong"></td></tr>
|
||
</table>
|
||
|
||
<h2 class="bagian">B. CPL YANG DIBEBANKAN PADA MK <span style="font-weight:normal;font-style:italic;color:var(--grey)">— otomatis dari pemetaan kurikulum</span></h2>
|
||
<table class="grid">
|
||
<thead><tr><th style="width:90px">Kode</th><th>Deskripsi CPL</th></tr></thead>
|
||
<tbody>
|
||
{% for c in peta.cpls %}
|
||
<tr><td class="tengah">{{ c.kode }}</td><td>{{ c.desk }}</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 class="bagian">C. CPMK <span style="font-weight:normal;font-style:italic;color:var(--grey)">— otomatis dari pemetaan kurikulum</span></h2>
|
||
<table class="grid">
|
||
<thead><tr><th style="width:110px">Kode</th><th>Deskripsi CPMK</th><th style="width:130px">CPL Didukung</th></tr></thead>
|
||
<tbody>
|
||
{% for c in peta.cpmks %}
|
||
<tr><td class="tengah">{{ c.kode }}</td><td>{{ c.desk }}</td><td class="tengah">{{ c.cpl|join(', ') }}</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2 class="bagian">D. SUB-CPMK <span style="font-weight:normal;font-style:italic;color:var(--grey)">— kode & kaitan CPMK otomatis dari pemetaan kurikulum ({{ peta.subs|length }} butir); redaksi kalimat boleh disesuaikan bila perlu</span></h2>
|
||
<div class="gulir" style="max-height:320px;overflow-y:auto">
|
||
<table class="grid">
|
||
<thead><tr><th style="width:110px">Kode</th><th>Uraian Sub-CPMK</th><th style="width:110px">CPMK</th></tr></thead>
|
||
<tbody>
|
||
{% for s in peta.subs %}
|
||
<tr><td class="tengah">{{ s.kode }}</td>
|
||
<td class="isian"><textarea name="sub_uraian_{{ s.kode }}" rows="2">{{ s.uraian }}</textarea></td>
|
||
<td class="tengah">{{ s.cpmk }}</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h2 class="bagian">E. DESKRIPSI SINGKAT MATA KULIAH</h2>
|
||
<textarea name="deskripsi" rows="4" placeholder="Topik utama, pendekatan pembelajaran, relevansi dengan profil lulusan dan CPL. Maksimal ± 100 kata.">{{ f.deskripsi }}</textarea>
|
||
|
||
<h2 class="bagian">E2. BAHAN KAJIAN — MATERI PEMBELAJARAN</h2>
|
||
<textarea name="bahan_kajian" rows="4" placeholder="Materi/bahan kajian MK secara berurutan (sesuai format RPS UNTAN).">{{ f.bahan_kajian }}</textarea>
|
||
|
||
<h2 class="bagian">E3. MEDIA PEMBELAJARAN</h2>
|
||
<textarea name="media" rows="2" placeholder="mis. LMS (e-learning UNTAN), LCD proyektor, perangkat lunak pendukung.">{{ f.media }}</textarea>
|
||
|
||
<h2 class="bagian">F. RENCANA MINGGUAN <span id="total-bobot-f" style="font-weight:normal">— total bobot: <b>0</b>%</span></h2>
|
||
<p class="keterangan">Minggu 8 = UTS, minggu 16 = UAS. Total bobot seluruh minggu harus 100 %.
|
||
{% if boleh_edit %}Pilih Sub-CPMK lalu klik <b>Isi Otomatis</b> untuk mengisi kolom kosong dengan teks
|
||
bantu (termasuk usulan Bobot — UTS 20%, UAS 30%, minggu biasa 3,5% — sesuaikan lagi agar totalnya
|
||
pas 100%).{% endif %}</p>
|
||
{% if boleh_edit %}
|
||
<details style="margin:0 0 10px">
|
||
<summary style="cursor:pointer;color:var(--blue);font-size:13px">Lihat contoh teks bantu per kolom</summary>
|
||
<div class="info" style="margin-top:6px;line-height:1.7">
|
||
<b>Indikator</b> — turunan Sub-CPMK, mis. "Mahasiswa mampu menjelaskan …"; "Ketepatan dan kelengkapan dalam …"<br>
|
||
<b>Kriteria & Teknik</b> — mis. "Rubrik holistik; tes tertulis" / "Ketepatan jawaban; unjuk kerja" / "Kelengkapan tugas; observasi"<br>
|
||
<b>Tatap Muka</b> — mis. "Ceramah, diskusi, tanya jawab [TM: 2x50 menit]" / "Studi kasus & presentasi kelompok [TM: 2x50 menit]"<br>
|
||
<b>Daring</b> — mis. "Membaca modul & kuis di LMS [BT+BM: 2x60 menit]" / "Diskusi forum LMS [BT+BM: 2x60 menit]"<br>
|
||
<b>Kegiatan Pembelajaran</b> — mis. "Mahasiswa menyimak paparan dosen, berdiskusi, dan mengerjakan latihan terkait materi minggu ini."<br>
|
||
<b>Materi [Pustaka]</b> — rujuk nomor pustaka di Bagian H, mis. "Bab 3 (Pustaka Utama #1)"
|
||
</div>
|
||
</details>
|
||
{% endif %}
|
||
<div class="gulir">
|
||
<table class="grid" id="tabel-f">
|
||
<thead>
|
||
<tr>
|
||
<th class="tengah" style="width:52px" rowspan="2">Mg</th>
|
||
<th style="min-width:190px" rowspan="2">Sub-CPMK</th>
|
||
<th colspan="2">Penilaian</th>
|
||
<th colspan="2">Bentuk/Metode Pembelajaran [Estimasi Waktu]</th>
|
||
<th style="min-width:140px" rowspan="2">Kegiatan Pembelajaran</th>
|
||
<th style="min-width:150px" rowspan="2">Materi [Pustaka]</th>
|
||
<th class="tengah" style="width:70px" rowspan="2">Bobot (%)</th>
|
||
</tr>
|
||
<tr>
|
||
<th class="sub" style="min-width:150px">Indikator</th>
|
||
<th class="sub" style="min-width:140px">Kriteria & Teknik</th>
|
||
<th class="sub" style="min-width:130px">Tatap Muka</th>
|
||
<th class="sub" style="min-width:120px">Daring</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for m in f.minggu %}
|
||
<tr class="{% if m.ke == 8 %}uts{% elif m.ke == 16 %}uas{% endif %}">
|
||
<td class="tengah">{{ m.ke }}</td>
|
||
<td class="isian">
|
||
<select name="m{{ m.ke }}_sub" {% if boleh_edit %}onchange="document.getElementById('btn-isi-m{{ m.ke }}').style.display = this.value ? '' : 'none'"{% endif %}>
|
||
<option value="">— pilih —</option>
|
||
{% for s in peta.subs %}
|
||
<option value="{{ s.kode }}" {% if m.sub == s.kode %}selected{% endif %}>{{ s.kode }} — {{ s.uraian }}</option>
|
||
<option disabled>──────────────────────</option>
|
||
{% endfor %}
|
||
<option value="__uts__" {% if m.sub == '__uts__' %}selected{% endif %}>Sub-CPMK minggu 1–7 (UTS)</option>
|
||
<option value="__uas__" {% if m.sub == '__uas__' %}selected{% endif %}>Sub-CPMK minggu 9–15 (UAS)</option>
|
||
</select>
|
||
{% if boleh_edit %}
|
||
<button type="button" id="btn-isi-m{{ m.ke }}" class="tombol garis"
|
||
style="padding:1px 6px;font-size:10px;margin-top:4px;{% if not m.sub %}display:none{% endif %}"
|
||
onclick="isiOtomatis({{ m.ke }})" title="Isi kolom kosong dengan teks bantu dari Sub-CPMK terpilih">Isi Otomatis</button>
|
||
{% endif %}
|
||
</td>
|
||
<td class="isian"><textarea name="m{{ m.ke }}_indikator" rows="2">{{ m.indikator }}</textarea></td>
|
||
<td class="isian"><textarea name="m{{ m.ke }}_kriteria" rows="2">{{ m.kriteria }}</textarea></td>
|
||
<td class="isian"><textarea name="m{{ m.ke }}_metode" rows="2">{{ m.metode }}</textarea></td>
|
||
<td class="isian"><textarea name="m{{ m.ke }}_daring" rows="2">{{ m.daring }}</textarea></td>
|
||
<td class="isian"><textarea name="m{{ m.ke }}_kegiatan" rows="2">{{ m.kegiatan }}</textarea></td>
|
||
<td class="isian"><textarea name="m{{ m.ke }}_materi" rows="2">{{ m.materi }}</textarea></td>
|
||
<td class="isian"><input type="number" class="bobot-f" name="m{{ m.ke }}_bobot" min="0" max="100" step="0.5" value="{{ m.bobot }}"></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h2 class="bagian">G. REKAP BOBOT PENILAIAN <span id="total-bobot-g" style="font-weight:normal">— total: <b>0</b>%</span></h2>
|
||
<p class="keterangan">Enam komponen teknik asesmen baku prodi. Bobot boleh dikosongkan untuk
|
||
komponen yang tidak dipakai MK ini (opsional), tapi total seluruh komponen yang diisi harus
|
||
tepat 100%. Centang Sub-CPMK yang dinilai tiap komponen; setiap Sub-CPMK harus tercakup minimal
|
||
satu komponen agar CPMK/CPL-nya terukur.</p>
|
||
<div class="gulir">
|
||
<table class="grid">
|
||
<thead>
|
||
<tr><th style="width:190px">Komponen</th><th>Sub-CPMK yang Dinilai</th><th class="tengah" style="width:90px">Bobot (%)</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for k in f.komponen %}
|
||
{% set ki = loop.index %}
|
||
<tr>
|
||
<td>{{ k.nama }}</td>
|
||
<td>
|
||
<div class="pilih-sub">
|
||
{% for s in peta.subs %}
|
||
<label><input type="checkbox" class="sub-k" name="k{{ ki }}_subs" value="{{ s.kode }}" {% if s.kode in k.subs %}checked{% endif %}>{{ s.kode }} — {{ s.uraian }}</label>
|
||
{% endfor %}
|
||
</div>
|
||
</td>
|
||
<td class="isian"><input type="number" class="bobot-g" name="k{{ ki }}_bobot" min="0" max="100" step="0.5" value="{{ k.bobot }}"></td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info" id="cek-cakupan" hidden></div>
|
||
|
||
<h2 class="bagian">H. PUSTAKA UTAMA</h2>
|
||
<p class="keterangan">Satu referensi per baris, format APA.</p>
|
||
<textarea name="referensi" rows="5" placeholder="Penulis. (Tahun). Judul. Penerbit / Jurnal, Vol(No), Hal. https://doi.org/...">{{ f.referensi_teks }}</textarea>
|
||
|
||
<h2 class="bagian">H2. PUSTAKA PENDUKUNG</h2>
|
||
<textarea name="referensi_pendukung" rows="3" placeholder="Satu referensi per baris; boleh kosong.">{{ f.referensi_pendukung_teks }}</textarea>
|
||
|
||
</fieldset>
|
||
<div class="aksi-baris">
|
||
{% if boleh_edit %}
|
||
<span style="color:var(--grey);font-size:13px">Disimpan atas nama <b>{{ user.nama }}</b></span>
|
||
<span id="autosave-status" style="color:var(--grey);font-size:13px;margin-left:10px"></span>
|
||
<span class="spacer"></span>
|
||
<button class="tombol garis" type="submit" name="aksi" value="draft">Simpan Draft</button>
|
||
<button class="tombol selesai" type="submit" name="aksi" value="selesai">Simpan & Tandai Selesai</button>
|
||
{% else %}
|
||
<span class="spacer"></span>
|
||
{% endif %}
|
||
{% if status %}<a class="tombol" href="/rps/{{ peta.kode }}/unduh">Unduh .docx</a>
|
||
<a class="tombol garis" href="/rps/{{ peta.kode }}/unduh.pdf">PDF</a>{% endif %}
|
||
</div>
|
||
</form>
|
||
|
||
<div style="text-align:center;margin-top:16px">
|
||
<button type="button" class="tombol garis" onclick="window.scrollTo({top:0, behavior:'smooth'})">▲ Ke Atas</button>
|
||
</div>
|
||
|
||
<script>
|
||
const SUB_URAIAN = {{ sub_uraian | tojson | safe }};
|
||
|
||
function isiOtomatis(mg) {
|
||
const sel = document.querySelector(`select[name="m${mg}_sub"]`);
|
||
const nilai = sel ? sel.value : '';
|
||
const isi = (nama, teks) => {
|
||
const el = document.querySelector(`[name="m${mg}_${nama}"]`);
|
||
if (el && !el.value.trim()) el.value = teks;
|
||
};
|
||
if (SUB_URAIAN[nilai]) {
|
||
const uraian = SUB_URAIAN[nilai];
|
||
isi('indikator', 'Mahasiswa ' + uraian.charAt(0).toLowerCase() + uraian.slice(1));
|
||
} else if (nilai === '__uts__') {
|
||
isi('indikator', 'Mahasiswa menguasai capaian Sub-CPMK minggu 1–7.');
|
||
} else if (nilai === '__uas__') {
|
||
isi('indikator', 'Mahasiswa menguasai capaian Sub-CPMK minggu 9–15.');
|
||
} else {
|
||
return; // belum pilih Sub-CPMK — tak ada dasar untuk mengisi
|
||
}
|
||
isi('kriteria', 'Ketepatan dan kelengkapan jawaban/tugas sesuai rubrik penilaian.');
|
||
isi('metode', 'Ceramah, diskusi, dan tanya jawab [TM: 2x50 menit]');
|
||
isi('daring', 'Membaca materi & berdiskusi di LMS [BT+BM: 2x60 menit]');
|
||
isi('kegiatan', 'Mahasiswa menyimak penjelasan dosen, berdiskusi, dan mengerjakan latihan terkait materi minggu ini.');
|
||
// bobot: usulan awal (UTS/UAS lazim lebih besar) — total tetap harus disesuaikan ke 100%
|
||
isi('bobot', mg == 8 ? '20' : mg == 16 ? '30' : '3.5');
|
||
segarkan();
|
||
}
|
||
|
||
function hitungTotal(kelas, idLabel) {
|
||
let t = 0;
|
||
document.querySelectorAll(kelas).forEach(el => { t += parseFloat(el.value) || 0; });
|
||
const label = document.querySelector(idLabel);
|
||
label.querySelector('b').textContent = (Math.round(t * 100) / 100);
|
||
label.classList.toggle('salah', Math.abs(t - 100) > 0.01);
|
||
}
|
||
function cekCakupan() {
|
||
const dinilai = new Set();
|
||
document.querySelectorAll('.sub-k:checked').forEach(cb => dinilai.add(cb.value));
|
||
const semua = [{% for s in peta.subs %}'{{ s.kode }}'{% if not loop.last %},{% endif %}{% endfor %}];
|
||
const hilang = semua.filter(k => !dinilai.has(k));
|
||
const kotak = document.getElementById('cek-cakupan');
|
||
if (hilang.length === 0) {
|
||
kotak.hidden = false;
|
||
kotak.className = 'info';
|
||
kotak.textContent = 'Semua ' + semua.length + ' Sub-CPMK sudah tercakup komponen penilaian — CPMK dan CPL mata kuliah ini akan terukur penuh.';
|
||
} else {
|
||
kotak.hidden = false;
|
||
kotak.className = 'peringatan';
|
||
kotak.textContent = 'Perhatian: ' + hilang.length + ' Sub-CPMK belum dinilai komponen mana pun (ketercapaian CPMK/CPL-nya tidak akan terukur): ' + hilang.join(', ');
|
||
}
|
||
}
|
||
function segarkan() {
|
||
hitungTotal('.bobot-f', '#total-bobot-f');
|
||
hitungTotal('.bobot-g', '#total-bobot-g');
|
||
cekCakupan();
|
||
}
|
||
document.addEventListener('input', segarkan);
|
||
segarkan();
|
||
|
||
// Auto-save berkala (selalu sebagai draft — tak pernah menandai "selesai"
|
||
// otomatis) supaya isian tak hilang kalau sinyal/listrik tiba-tiba putus.
|
||
const BOLEH_EDIT = {{ boleh_edit | tojson | safe }};
|
||
const NAMA_USER = {{ user.nama | tojson | safe }};
|
||
if (BOLEH_EDIT) {
|
||
let timerAutosave = null;
|
||
let sedangMenyimpan = false;
|
||
let perluSimpanLagi = false;
|
||
|
||
function waktuSekarang() {
|
||
const d = new Date();
|
||
const p = n => String(n).padStart(2, '0');
|
||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
||
}
|
||
|
||
async function simpanOtomatis() {
|
||
if (sedangMenyimpan) { perluSimpanLagi = true; return; }
|
||
sedangMenyimpan = true;
|
||
const status = document.getElementById('autosave-status');
|
||
if (status) status.textContent = 'Menyimpan otomatis…';
|
||
try {
|
||
const form = document.getElementById('form-rps');
|
||
const data = new FormData(form);
|
||
data.set('aksi', 'draft');
|
||
const res = await fetch(form.action, { method: 'POST', body: data });
|
||
const jam = new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' });
|
||
if (status) {
|
||
status.textContent = res.ok
|
||
? `Tersimpan otomatis ${jam}`
|
||
: 'Auto-save gagal — klik Simpan Draft manual.';
|
||
}
|
||
if (res.ok) {
|
||
// label stempel "DRAFT · disimpan ... oleh ..." di atas halaman
|
||
// dirender sekali saat page-load — perbarui juga di sini supaya
|
||
// tak kelihatan basi walau auto-save baru saja jalan di belakang layar.
|
||
const stamp = document.getElementById('status-stamp');
|
||
const waktu = document.getElementById('status-waktu');
|
||
if (stamp) stamp.innerHTML = '<span class="stamp stamp-draft">DRAFT</span>';
|
||
if (waktu) waktu.textContent = ` · disimpan ${waktuSekarang()} oleh ${NAMA_USER}`;
|
||
}
|
||
} catch (e) {
|
||
if (status) status.textContent = 'Auto-save gagal (offline?) — klik Simpan Draft manual.';
|
||
} finally {
|
||
sedangMenyimpan = false;
|
||
if (perluSimpanLagi) { perluSimpanLagi = false; jadwalkanAutosave(); }
|
||
}
|
||
}
|
||
function jadwalkanAutosave() {
|
||
clearTimeout(timerAutosave);
|
||
timerAutosave = setTimeout(simpanOtomatis, 3000);
|
||
}
|
||
document.addEventListener('input', jadwalkanAutosave);
|
||
}
|
||
</script>
|
||
{% endblock %}
|