Spaces:
Running
Running
Add 2 files
Browse files- index.html +154 -116
index.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>Aplikasi Catatan Pembelajaran</title>
|
| 7 |
-
<!-- jsPDF + autoTable
|
| 8 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
| 9 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
|
| 10 |
-
<!-- SheetJS
|
| 11 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
|
| 12 |
<style>
|
| 13 |
body { font-family: 'Segoe UI', Arial, sans-serif; margin: 0; background: #f0f2f5; }
|
|
@@ -29,7 +29,7 @@
|
|
| 29 |
button.secondary:hover { background: #545b62; }
|
| 30 |
button.danger { background: #dc3545; }
|
| 31 |
button.danger:hover { background: #c82333; }
|
| 32 |
-
button.small { padding: 6px 12px; font-size:
|
| 33 |
.form-group { margin-bottom: 10px; }
|
| 34 |
.filter-group { display: flex; gap: 15px; flex-wrap: wrap; align-items: end; margin-bottom: 20px; }
|
| 35 |
.filter-group > div { flex: 1; min-width: 200px; }
|
|
@@ -39,12 +39,10 @@
|
|
| 39 |
tr:hover { background: #f8f9fa; }
|
| 40 |
.text-wrap { white-space: pre-wrap; word-wrap: break-word; }
|
| 41 |
.actions { margin: 20px 0; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
|
| 42 |
-
.
|
| 43 |
@media (max-width: 768px) {
|
| 44 |
.filter-group { flex-direction: column; }
|
| 45 |
-
.
|
| 46 |
-
table { font-size: 14px; }
|
| 47 |
-
td, th { padding: 8px; }
|
| 48 |
}
|
| 49 |
</style>
|
| 50 |
</head>
|
|
@@ -60,27 +58,22 @@
|
|
| 60 |
|
| 61 |
<!-- Tab Input -->
|
| 62 |
<div id="Input" class="tabcontent active">
|
| 63 |
-
<h2 style="margin-top:0; color:#333;">Input Data Pembelajaran</h2>
|
| 64 |
-
|
| 65 |
-
<div id="editModeInfo" class="edit-mode" style="display:none;">
|
| 66 |
-
<strong>Sedang mengedit entri #<span id="editIndex"></span></strong>
|
| 67 |
-
<button class="secondary small" onclick="batalEdit()">Batal Edit</button>
|
| 68 |
-
</div>
|
| 69 |
|
| 70 |
<label>Jenis Pembelajaran</label>
|
| 71 |
-
<select id="jenisSelect"></select>
|
| 72 |
|
| 73 |
<div id="manualJenisInput" class="form-group" style="display:none;">
|
| 74 |
<label>Tambah Jenis Baru</label>
|
| 75 |
-
<input type="text" id="jenisManual" placeholder="Contoh: Pemrograman, Fisika,
|
| 76 |
</div>
|
| 77 |
|
| 78 |
<label>Indicator (Sub Bab yang Dibahas)</label>
|
| 79 |
<select id="indicatorSelect"></select>
|
| 80 |
|
| 81 |
<div id="manualIndicatorInput" class="form-group" style="display:none;">
|
| 82 |
-
<label>Tambah Sub Bab Baru</label>
|
| 83 |
-
<input type="text" id="indicatorManual" placeholder="Contoh: Aljabar, HTML
|
| 84 |
</div>
|
| 85 |
|
| 86 |
<label>Hasil Pembelajaran</label>
|
|
@@ -91,8 +84,12 @@
|
|
| 91 |
|
| 92 |
<div>
|
| 93 |
<button onclick="simpanData()">Simpan Pembelajaran</button>
|
| 94 |
-
<button class="secondary" onclick="resetForm()">
|
| 95 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
</div>
|
| 97 |
|
| 98 |
<!-- Tab Daftar -->
|
|
@@ -102,11 +99,14 @@
|
|
| 102 |
<div class="filter-group">
|
| 103 |
<div>
|
| 104 |
<label>Filter Jenis</label>
|
| 105 |
-
<select id="filterJenis"
|
|
|
|
|
|
|
| 106 |
</div>
|
| 107 |
<div>
|
| 108 |
<label>Filter Kata Kunci</label>
|
| 109 |
-
<input type="text" id="filterKata" placeholder="
|
|
|
|
| 110 |
</div>
|
| 111 |
<div>
|
| 112 |
<button onclick="terapkanFilter()">Terapkan Filter</button>
|
|
@@ -129,13 +129,13 @@
|
|
| 129 |
<table id="tabelPembelajaran">
|
| 130 |
<thead>
|
| 131 |
<tr>
|
| 132 |
-
<th
|
| 133 |
-
<th
|
| 134 |
-
<th
|
| 135 |
-
<th
|
| 136 |
-
<th
|
| 137 |
-
<th
|
| 138 |
-
<th
|
| 139 |
</tr>
|
| 140 |
</thead>
|
| 141 |
<tbody></tbody>
|
|
@@ -148,33 +148,86 @@
|
|
| 148 |
const { jsPDF } = window.jspdf;
|
| 149 |
|
| 150 |
let dataPembelajaran = JSON.parse(localStorage.getItem('pembelajaran')) || [];
|
| 151 |
-
let
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
-
|
|
|
|
|
|
|
| 157 |
|
| 158 |
-
function
|
| 159 |
const jenisSelect = document.getElementById('jenisSelect');
|
| 160 |
const filterJenis = document.getElementById('filterJenis');
|
| 161 |
-
const
|
| 162 |
|
| 163 |
jenisSelect.innerHTML = '';
|
| 164 |
filterJenis.innerHTML = '<option value="">Semua Jenis</option>';
|
| 165 |
-
|
|
|
|
|
|
|
| 166 |
jenisSelect.add(new Option(j, j));
|
| 167 |
filterJenis.add(new Option(j, j));
|
| 168 |
});
|
| 169 |
jenisSelect.add(new Option('--- Tambah Jenis Baru ---', 'new'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
indicatorSelect.innerHTML = '';
|
| 172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
indicatorSelect.add(new Option('--- Tambah Sub Bab Baru ---', 'new'));
|
| 174 |
}
|
| 175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
document.getElementById('jenisSelect').addEventListener('change', function() {
|
| 177 |
document.getElementById('manualJenisInput').style.display = this.value === 'new' ? 'block' : 'none';
|
|
|
|
| 178 |
});
|
| 179 |
|
| 180 |
document.getElementById('indicatorSelect').addEventListener('change', function() {
|
|
@@ -186,20 +239,12 @@
|
|
| 186 |
if (jenis === 'new') {
|
| 187 |
jenis = document.getElementById('jenisManual').value.trim();
|
| 188 |
if (!jenis) return alert('Masukkan nama jenis baru!');
|
| 189 |
-
if (!jenisList.includes(jenis)) {
|
| 190 |
-
jenisList.push(jenis);
|
| 191 |
-
jenisList.sort();
|
| 192 |
-
}
|
| 193 |
}
|
| 194 |
|
| 195 |
let indikator = document.getElementById('indicatorSelect').value;
|
| 196 |
if (indikator === 'new') {
|
| 197 |
indikator = document.getElementById('indicatorManual').value.trim();
|
| 198 |
if (!indikator) return alert('Masukkan nama sub bab baru!');
|
| 199 |
-
if (!indicatorList.includes(indikator)) {
|
| 200 |
-
indicatorList.push(indikator);
|
| 201 |
-
indicatorList.sort();
|
| 202 |
-
}
|
| 203 |
}
|
| 204 |
|
| 205 |
const hasil = document.getElementById('hasil').value.trim();
|
|
@@ -219,94 +264,99 @@
|
|
| 219 |
|
| 220 |
if (editIndex === -1) {
|
| 221 |
dataPembelajaran.push(entry);
|
| 222 |
-
alert('Data pembelajaran berhasil disimpan!');
|
| 223 |
} else {
|
| 224 |
dataPembelajaran[editIndex] = entry;
|
| 225 |
-
alert('Data pembelajaran berhasil diperbarui!');
|
| 226 |
}
|
| 227 |
|
| 228 |
localStorage.setItem('pembelajaran', JSON.stringify(dataPembelajaran));
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
| 230 |
resetForm();
|
|
|
|
| 231 |
if (document.getElementById('Daftar').classList.contains('active')) tampilkanData();
|
| 232 |
}
|
| 233 |
|
| 234 |
function resetForm() {
|
| 235 |
editIndex = -1;
|
| 236 |
-
document.getElementById('
|
| 237 |
-
|
| 238 |
document.getElementById('manualJenisInput').style.display = 'none';
|
| 239 |
document.getElementById('jenisManual').value = '';
|
| 240 |
-
|
| 241 |
document.getElementById('manualIndicatorInput').style.display = 'none';
|
| 242 |
document.getElementById('indicatorManual').value = '';
|
| 243 |
document.getElementById('hasil').value = '';
|
| 244 |
document.getElementById('kesimpulan').value = '';
|
| 245 |
}
|
| 246 |
|
| 247 |
-
function
|
| 248 |
-
|
| 249 |
-
}
|
| 250 |
-
|
| 251 |
-
function editEntri(index) {
|
| 252 |
-
const entry = dataPembelajaran[index];
|
| 253 |
editIndex = index;
|
| 254 |
|
| 255 |
-
// Pindah ke tab Input
|
| 256 |
openTab(null, 'Input');
|
|
|
|
|
|
|
| 257 |
|
| 258 |
-
document.getElementById('editModeInfo').style.display = 'block';
|
| 259 |
-
document.getElementById('editIndex').textContent = index + 1;
|
| 260 |
-
|
| 261 |
-
// Set nilai form
|
| 262 |
let jenisSelect = document.getElementById('jenisSelect');
|
| 263 |
-
if (
|
| 264 |
-
jenisSelect.
|
| 265 |
-
document.getElementById('manualJenisInput').style.display = 'none';
|
| 266 |
-
} else {
|
| 267 |
-
jenisSelect.value = 'new';
|
| 268 |
-
document.getElementById('manualJenisInput').style.display = 'block';
|
| 269 |
-
document.getElementById('jenisManual').value = entry.jenis;
|
| 270 |
}
|
|
|
|
|
|
|
| 271 |
|
| 272 |
let indicatorSelect = document.getElementById('indicatorSelect');
|
| 273 |
-
if (
|
| 274 |
-
indicatorSelect.
|
| 275 |
-
document.getElementById('manualIndicatorInput').style.display = 'none';
|
| 276 |
-
} else {
|
| 277 |
-
indicatorSelect.value = 'new';
|
| 278 |
-
document.getElementById('manualIndicatorInput').style.display = 'block';
|
| 279 |
-
document.getElementById('indicatorManual').value = entry.indikator;
|
| 280 |
}
|
|
|
|
| 281 |
|
| 282 |
-
document.getElementById('hasil').value =
|
| 283 |
-
document.getElementById('kesimpulan').value =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
}
|
| 285 |
|
| 286 |
-
function
|
| 287 |
-
if (confirm('Yakin ingin menghapus
|
| 288 |
dataPembelajaran.splice(index, 1);
|
| 289 |
localStorage.setItem('pembelajaran', JSON.stringify(dataPembelajaran));
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
tampilkanData();
|
| 291 |
alert('Data berhasil dihapus!');
|
| 292 |
}
|
| 293 |
}
|
| 294 |
|
| 295 |
-
function tampilkanData(
|
|
|
|
|
|
|
|
|
|
| 296 |
const tbody = document.querySelector('#tabelPembelajaran tbody');
|
| 297 |
tbody.innerHTML = '';
|
| 298 |
|
| 299 |
let filtered = dataPembelajaran;
|
| 300 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
if (filterKata) {
|
| 302 |
-
const kata = filterKata.toLowerCase();
|
| 303 |
filtered = filtered.filter(d =>
|
| 304 |
-
d.hasil.toLowerCase().includes(
|
|
|
|
| 305 |
);
|
| 306 |
}
|
| 307 |
|
| 308 |
filtered.forEach((d, i) => {
|
| 309 |
-
const
|
| 310 |
const row = tbody.insertRow();
|
| 311 |
row.insertCell(0).textContent = i + 1;
|
| 312 |
row.insertCell(1).textContent = d.tanggal;
|
|
@@ -316,17 +366,16 @@
|
|
| 316 |
row.insertCell(5).innerHTML = '<div class="text-wrap">' + d.kesimpulan.replace(/\n/g, '<br>') + '</div>';
|
| 317 |
|
| 318 |
const cellAksi = row.insertCell(6);
|
|
|
|
| 319 |
cellAksi.innerHTML = `
|
| 320 |
-
<button class="
|
| 321 |
-
<button class="danger
|
| 322 |
`;
|
| 323 |
});
|
| 324 |
}
|
| 325 |
|
| 326 |
function terapkanFilter() {
|
| 327 |
-
|
| 328 |
-
const filterKata = document.getElementById('filterKata').value;
|
| 329 |
-
tampilkanData(filterJenis, filterKata);
|
| 330 |
}
|
| 331 |
|
| 332 |
function resetFilter() {
|
|
@@ -335,7 +384,6 @@
|
|
| 335 |
tampilkanData();
|
| 336 |
}
|
| 337 |
|
| 338 |
-
// Import dan Export tetap sama (dipertahankan dari versi sebelumnya)
|
| 339 |
function importExcel() {
|
| 340 |
const fileInput = document.getElementById('importFile');
|
| 341 |
const file = fileInput.files[0];
|
|
@@ -354,25 +402,24 @@
|
|
| 354 |
const entry = {
|
| 355 |
tanggal: row['Tanggal'] || row['tanggal'] || new Date().toLocaleString('id-ID'),
|
| 356 |
jenis: row['Jenis'] || row['jenis'] || '',
|
| 357 |
-
indikator: row['Indicator
|
| 358 |
hasil: row['Hasil Pembelajaran'] || row['Hasil'] || row['hasil'] || '',
|
| 359 |
kesimpulan: row['Kesimpulan'] || row['kesimpulan'] || ''
|
| 360 |
};
|
| 361 |
|
| 362 |
if (entry.jenis && entry.indikator && entry.hasil && entry.kesimpulan) {
|
| 363 |
dataPembelajaran.push(entry);
|
| 364 |
-
if (!jenisList.includes(entry.jenis)) jenisList.push(entry.jenis);
|
| 365 |
-
if (!indicatorList.includes(entry.indikator)) indicatorList.push(entry.indikator);
|
| 366 |
imported++;
|
| 367 |
}
|
| 368 |
});
|
| 369 |
|
| 370 |
-
jenisList = [...new Set(jenisList)].sort();
|
| 371 |
-
indicatorList = [...new Set(indicatorList)].sort();
|
| 372 |
localStorage.setItem('pembelajaran', JSON.stringify(dataPembelajaran));
|
| 373 |
-
|
|
|
|
|
|
|
|
|
|
| 374 |
tampilkanData();
|
| 375 |
-
alert(`Berhasil mengimport ${imported} data
|
| 376 |
fileInput.value = '';
|
| 377 |
} catch (err) {
|
| 378 |
alert('Gagal membaca file: ' + err.message);
|
|
@@ -382,7 +429,7 @@
|
|
| 382 |
}
|
| 383 |
|
| 384 |
function exportExcel() {
|
| 385 |
-
if (dataPembelajaran.length === 0) return alert('Tidak ada data
|
| 386 |
const ws = XLSX.utils.json_to_sheet(dataPembelajaran);
|
| 387 |
const wb = XLSX.utils.book_new();
|
| 388 |
XLSX.utils.book_append_sheet(wb, ws, "Pembelajaran");
|
|
@@ -390,8 +437,7 @@
|
|
| 390 |
}
|
| 391 |
|
| 392 |
function exportPDF() {
|
| 393 |
-
if (dataPembelajaran.length === 0) return alert('Tidak ada data
|
| 394 |
-
|
| 395 |
const doc = new jsPDF('l', 'mm', 'a4');
|
| 396 |
doc.setFontSize(18);
|
| 397 |
doc.text("Laporan Catatan Pembelajaran", 14, 20);
|
|
@@ -399,10 +445,7 @@
|
|
| 399 |
doc.text("Dicetak pada: " + new Date().toLocaleString('id-ID'), 14, 30);
|
| 400 |
|
| 401 |
const tableData = dataPembelajaran.map((d, i) => [
|
| 402 |
-
i + 1,
|
| 403 |
-
d.tanggal,
|
| 404 |
-
d.jenis,
|
| 405 |
-
d.indikator,
|
| 406 |
d.hasil.length > 80 ? d.hasil.substring(0,80) + '...' : d.hasil,
|
| 407 |
d.kesimpulan.length > 80 ? d.kesimpulan.substring(0,80) + '...' : d.kesimpulan
|
| 408 |
]);
|
|
@@ -413,15 +456,7 @@
|
|
| 413 |
startY: 40,
|
| 414 |
styles: { fontSize: 10, cellPadding: 3 },
|
| 415 |
headStyles: { fillColor: [0, 123, 255] },
|
| 416 |
-
|
| 417 |
-
columnStyles: {
|
| 418 |
-
0: { cellWidth: 15 },
|
| 419 |
-
1: { cellWidth: 35 },
|
| 420 |
-
2: { cellWidth: 35 },
|
| 421 |
-
3: { cellWidth: 40 },
|
| 422 |
-
4: { cellWidth: 70 },
|
| 423 |
-
5: { cellWidth: 70 }
|
| 424 |
-
}
|
| 425 |
});
|
| 426 |
|
| 427 |
doc.save("Catatan_Pembelajaran_" + new Date().toISOString().slice(0,10) + ".pdf");
|
|
@@ -434,14 +469,17 @@
|
|
| 434 |
if (evt) evt.currentTarget.classList.add("active");
|
| 435 |
|
| 436 |
if (tabName === 'Daftar') {
|
| 437 |
-
|
|
|
|
| 438 |
tampilkanData();
|
| 439 |
}
|
| 440 |
}
|
| 441 |
|
| 442 |
// Inisialisasi
|
| 443 |
-
|
| 444 |
-
|
|
|
|
|
|
|
| 445 |
</script>
|
| 446 |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=alterzick/notepad-v1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 447 |
</html>
|
|
|
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>Aplikasi Catatan Pembelajaran</title>
|
| 7 |
+
<!-- jsPDF + autoTable -->
|
| 8 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
| 9 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
|
| 10 |
+
<!-- SheetJS -->
|
| 11 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
|
| 12 |
<style>
|
| 13 |
body { font-family: 'Segoe UI', Arial, sans-serif; margin: 0; background: #f0f2f5; }
|
|
|
|
| 29 |
button.secondary:hover { background: #545b62; }
|
| 30 |
button.danger { background: #dc3545; }
|
| 31 |
button.danger:hover { background: #c82333; }
|
| 32 |
+
button.small { padding: 6px 12px; font-size: 13px; }
|
| 33 |
.form-group { margin-bottom: 10px; }
|
| 34 |
.filter-group { display: flex; gap: 15px; flex-wrap: wrap; align-items: end; margin-bottom: 20px; }
|
| 35 |
.filter-group > div { flex: 1; min-width: 200px; }
|
|
|
|
| 39 |
tr:hover { background: #f8f9fa; }
|
| 40 |
.text-wrap { white-space: pre-wrap; word-wrap: break-word; }
|
| 41 |
.actions { margin: 20px 0; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
|
| 42 |
+
.action-buttons { white-space: nowrap; }
|
| 43 |
@media (max-width: 768px) {
|
| 44 |
.filter-group { flex-direction: column; }
|
| 45 |
+
.action-buttons button { display: block; width: 100%; margin: 5px 0; }
|
|
|
|
|
|
|
| 46 |
}
|
| 47 |
</style>
|
| 48 |
</head>
|
|
|
|
| 58 |
|
| 59 |
<!-- Tab Input -->
|
| 60 |
<div id="Input" class="tabcontent active">
|
| 61 |
+
<h2 style="margin-top:0; color:#333;">Input / Edit Data Pembelajaran</h2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
<label>Jenis Pembelajaran</label>
|
| 64 |
+
<select id="jenisSelect" onchange="updateIndicatorDropdown()"></select>
|
| 65 |
|
| 66 |
<div id="manualJenisInput" class="form-group" style="display:none;">
|
| 67 |
<label>Tambah Jenis Baru</label>
|
| 68 |
+
<input type="text" id="jenisManual" placeholder="Contoh: Pemrograman, Fisika, Sejarah">
|
| 69 |
</div>
|
| 70 |
|
| 71 |
<label>Indicator (Sub Bab yang Dibahas)</label>
|
| 72 |
<select id="indicatorSelect"></select>
|
| 73 |
|
| 74 |
<div id="manualIndicatorInput" class="form-group" style="display:none;">
|
| 75 |
+
<label>Tambah Sub Bab Baru (untuk jenis ini)</label>
|
| 76 |
+
<input type="text" id="indicatorManual" placeholder="Contoh: Aljabar, HTML, Perang Dunia II">
|
| 77 |
</div>
|
| 78 |
|
| 79 |
<label>Hasil Pembelajaran</label>
|
|
|
|
| 84 |
|
| 85 |
<div>
|
| 86 |
<button onclick="simpanData()">Simpan Pembelajaran</button>
|
| 87 |
+
<button class="secondary" onclick="resetForm()">Batal / Baru</button>
|
| 88 |
</div>
|
| 89 |
+
|
| 90 |
+
<p id="editStatus" style="color:#007bff; font-style:italic; margin-top:15px; display:none;">
|
| 91 |
+
Sedang mengedit entri nomor: <span id="editIndex"></span>
|
| 92 |
+
</p>
|
| 93 |
</div>
|
| 94 |
|
| 95 |
<!-- Tab Daftar -->
|
|
|
|
| 99 |
<div class="filter-group">
|
| 100 |
<div>
|
| 101 |
<label>Filter Jenis</label>
|
| 102 |
+
<select id="filterJenis" onchange="terapkanFilter()">
|
| 103 |
+
<option value="">Semua Jenis</option>
|
| 104 |
+
</select>
|
| 105 |
</div>
|
| 106 |
<div>
|
| 107 |
<label>Filter Kata Kunci</label>
|
| 108 |
+
<input type="text" id="filterKata" list="suggestions" placeholder="Ketik untuk mencari..." oninput="terapkanFilter()">
|
| 109 |
+
<datalist id="suggestions"></datalist>
|
| 110 |
</div>
|
| 111 |
<div>
|
| 112 |
<button onclick="terapkanFilter()">Terapkan Filter</button>
|
|
|
|
| 129 |
<table id="tabelPembelajaran">
|
| 130 |
<thead>
|
| 131 |
<tr>
|
| 132 |
+
<th>No</th>
|
| 133 |
+
<th>Tanggal</th>
|
| 134 |
+
<th>Jenis</th>
|
| 135 |
+
<th>Indicator</th>
|
| 136 |
+
<th>Hasil Pembelajaran</th>
|
| 137 |
+
<th>Kesimpulan</th>
|
| 138 |
+
<th>Aksi</th>
|
| 139 |
</tr>
|
| 140 |
</thead>
|
| 141 |
<tbody></tbody>
|
|
|
|
| 148 |
const { jsPDF } = window.jspdf;
|
| 149 |
|
| 150 |
let dataPembelajaran = JSON.parse(localStorage.getItem('pembelajaran')) || [];
|
| 151 |
+
let subBabByJenis = {};
|
| 152 |
+
let editIndex = -1;
|
| 153 |
+
|
| 154 |
+
function buildSubBabMapping() {
|
| 155 |
+
subBabByJenis = {};
|
| 156 |
+
dataPembelajaran.forEach(entry => {
|
| 157 |
+
if (!subBabByJenis[entry.jenis]) {
|
| 158 |
+
subBabByJenis[entry.jenis] = new Set();
|
| 159 |
+
}
|
| 160 |
+
subBabByJenis[entry.jenis].add(entry.indikator);
|
| 161 |
+
});
|
| 162 |
+
Object.keys(subBabByJenis).forEach(jenis => {
|
| 163 |
+
subBabByJenis[jenis] = Array.from(subBabByJenis[jenis]).sort();
|
| 164 |
+
});
|
| 165 |
+
}
|
| 166 |
|
| 167 |
+
function getJenisList() {
|
| 168 |
+
return [...new Set(dataPembelajaran.map(d => d.jenis))].sort();
|
| 169 |
+
}
|
| 170 |
|
| 171 |
+
function updateJenisDropdown() {
|
| 172 |
const jenisSelect = document.getElementById('jenisSelect');
|
| 173 |
const filterJenis = document.getElementById('filterJenis');
|
| 174 |
+
const jenisList = getJenisList();
|
| 175 |
|
| 176 |
jenisSelect.innerHTML = '';
|
| 177 |
filterJenis.innerHTML = '<option value="">Semua Jenis</option>';
|
| 178 |
+
|
| 179 |
+
const defaultJenis = jenisList.length === 0 ? ["Matematika", "Bahasa", "Sains"] : jenisList;
|
| 180 |
+
defaultJenis.forEach(j => {
|
| 181 |
jenisSelect.add(new Option(j, j));
|
| 182 |
filterJenis.add(new Option(j, j));
|
| 183 |
});
|
| 184 |
jenisSelect.add(new Option('--- Tambah Jenis Baru ---', 'new'));
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
function updateIndicatorDropdown() {
|
| 188 |
+
const jenis = document.getElementById('jenisSelect').value;
|
| 189 |
+
const indicatorSelect = document.getElementById('indicatorSelect');
|
| 190 |
+
const manualDiv = document.getElementById('manualIndicatorInput');
|
| 191 |
|
| 192 |
indicatorSelect.innerHTML = '';
|
| 193 |
+
manualDiv.style.display = 'none';
|
| 194 |
+
|
| 195 |
+
if (jenis === 'new' || !jenis) {
|
| 196 |
+
indicatorSelect.innerHTML = '<option value="">-- Pilih jenis dulu --</option>';
|
| 197 |
+
return;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
const subBabList = subBabByJenis[jenis] || [];
|
| 201 |
+
if (subBabList.length === 0) {
|
| 202 |
+
indicatorSelect.add(new Option('-- Belum ada sub bab --', ''));
|
| 203 |
+
} else {
|
| 204 |
+
subBabList.forEach(sb => indicatorSelect.add(new Option(sb, sb)));
|
| 205 |
+
}
|
| 206 |
indicatorSelect.add(new Option('--- Tambah Sub Bab Baru ---', 'new'));
|
| 207 |
}
|
| 208 |
|
| 209 |
+
function updateAutocompleteSuggestions() {
|
| 210 |
+
const datalist = document.getElementById('suggestions');
|
| 211 |
+
datalist.innerHTML = '';
|
| 212 |
+
|
| 213 |
+
const allWords = new Set();
|
| 214 |
+
dataPembelajaran.forEach(entry => {
|
| 215 |
+
[...entry.hasil.split(/\s+/), ...entry.kesimpulan.split(/\s+/)].forEach(word => {
|
| 216 |
+
word = word.replace(/[.,!?()"]/g, '').toLowerCase();
|
| 217 |
+
if (word.length >= 3) allWords.add(word);
|
| 218 |
+
});
|
| 219 |
+
});
|
| 220 |
+
|
| 221 |
+
Array.from(allWords).sort().slice(0, 50).forEach(word => {
|
| 222 |
+
const option = document.createElement('option');
|
| 223 |
+
option.value = word;
|
| 224 |
+
datalist.appendChild(option);
|
| 225 |
+
});
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
document.getElementById('jenisSelect').addEventListener('change', function() {
|
| 229 |
document.getElementById('manualJenisInput').style.display = this.value === 'new' ? 'block' : 'none';
|
| 230 |
+
updateIndicatorDropdown();
|
| 231 |
});
|
| 232 |
|
| 233 |
document.getElementById('indicatorSelect').addEventListener('change', function() {
|
|
|
|
| 239 |
if (jenis === 'new') {
|
| 240 |
jenis = document.getElementById('jenisManual').value.trim();
|
| 241 |
if (!jenis) return alert('Masukkan nama jenis baru!');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
}
|
| 243 |
|
| 244 |
let indikator = document.getElementById('indicatorSelect').value;
|
| 245 |
if (indikator === 'new') {
|
| 246 |
indikator = document.getElementById('indicatorManual').value.trim();
|
| 247 |
if (!indikator) return alert('Masukkan nama sub bab baru!');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 248 |
}
|
| 249 |
|
| 250 |
const hasil = document.getElementById('hasil').value.trim();
|
|
|
|
| 264 |
|
| 265 |
if (editIndex === -1) {
|
| 266 |
dataPembelajaran.push(entry);
|
|
|
|
| 267 |
} else {
|
| 268 |
dataPembelajaran[editIndex] = entry;
|
|
|
|
| 269 |
}
|
| 270 |
|
| 271 |
localStorage.setItem('pembelajaran', JSON.stringify(dataPembelajaran));
|
| 272 |
+
buildSubBabMapping();
|
| 273 |
+
updateJenisDropdown();
|
| 274 |
+
updateIndicatorDropdown();
|
| 275 |
+
updateAutocompleteSuggestions();
|
| 276 |
resetForm();
|
| 277 |
+
alert(editIndex === -1 ? 'Data berhasil disimpan!' : 'Data berhasil diperbarui!');
|
| 278 |
if (document.getElementById('Daftar').classList.contains('active')) tampilkanData();
|
| 279 |
}
|
| 280 |
|
| 281 |
function resetForm() {
|
| 282 |
editIndex = -1;
|
| 283 |
+
document.getElementById('editStatus').style.display = 'none';
|
| 284 |
+
updateJenisDropdown();
|
| 285 |
document.getElementById('manualJenisInput').style.display = 'none';
|
| 286 |
document.getElementById('jenisManual').value = '';
|
| 287 |
+
updateIndicatorDropdown();
|
| 288 |
document.getElementById('manualIndicatorInput').style.display = 'none';
|
| 289 |
document.getElementById('indicatorManual').value = '';
|
| 290 |
document.getElementById('hasil').value = '';
|
| 291 |
document.getElementById('kesimpulan').value = '';
|
| 292 |
}
|
| 293 |
|
| 294 |
+
function editData(index) {
|
| 295 |
+
const data = dataPembelajaran[index];
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
editIndex = index;
|
| 297 |
|
|
|
|
| 298 |
openTab(null, 'Input');
|
| 299 |
+
document.querySelector('.tablink.active').classList.remove('active');
|
| 300 |
+
document.querySelector('[onclick*="Input"]').classList.add('active');
|
| 301 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
let jenisSelect = document.getElementById('jenisSelect');
|
| 303 |
+
if (!Array.from(jenisSelect.options).some(opt => opt.value === data.jenis)) {
|
| 304 |
+
jenisSelect.add(new Option(data.jenis, data.jenis));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
}
|
| 306 |
+
jenisSelect.value = data.jenis;
|
| 307 |
+
updateIndicatorDropdown();
|
| 308 |
|
| 309 |
let indicatorSelect = document.getElementById('indicatorSelect');
|
| 310 |
+
if (!Array.from(indicatorSelect.options).some(opt => opt.value === data.indikator)) {
|
| 311 |
+
indicatorSelect.add(new Option(data.indikator, data.indikator), indicatorSelect.options[indicatorSelect.options.length - 1]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
}
|
| 313 |
+
indicatorSelect.value = data.indikator;
|
| 314 |
|
| 315 |
+
document.getElementById('hasil').value = data.hasil;
|
| 316 |
+
document.getElementById('kesimpulan').value = data.kesimpulan;
|
| 317 |
+
|
| 318 |
+
document.getElementById('editStatus').style.display = 'block';
|
| 319 |
+
document.getElementById('editIndex').textContent = index + 1;
|
| 320 |
+
window.scrollTo(0, 0);
|
| 321 |
}
|
| 322 |
|
| 323 |
+
function deleteData(index) {
|
| 324 |
+
if (confirm('Yakin ingin menghapus data ini?')) {
|
| 325 |
dataPembelajaran.splice(index, 1);
|
| 326 |
localStorage.setItem('pembelajaran', JSON.stringify(dataPembelajaran));
|
| 327 |
+
buildSubBabMapping();
|
| 328 |
+
updateJenisDropdown();
|
| 329 |
+
updateIndicatorDropdown();
|
| 330 |
+
updateAutocompleteSuggestions();
|
| 331 |
tampilkanData();
|
| 332 |
alert('Data berhasil dihapus!');
|
| 333 |
}
|
| 334 |
}
|
| 335 |
|
| 336 |
+
function tampilkanData() {
|
| 337 |
+
const filterJenis = document.getElementById('filterJenis').value;
|
| 338 |
+
const filterKata = document.getElementById('filterKata').value.toLowerCase().trim();
|
| 339 |
+
|
| 340 |
const tbody = document.querySelector('#tabelPembelajaran tbody');
|
| 341 |
tbody.innerHTML = '';
|
| 342 |
|
| 343 |
let filtered = dataPembelajaran;
|
| 344 |
+
|
| 345 |
+
// Terapkan filter jenis terlebih dahulu
|
| 346 |
+
if (filterJenis) {
|
| 347 |
+
filtered = filtered.filter(d => d.jenis === filterJenis);
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
// Kemudian filter kata kunci pada hasil yang sudah difilter jenis
|
| 351 |
if (filterKata) {
|
|
|
|
| 352 |
filtered = filtered.filter(d =>
|
| 353 |
+
d.hasil.toLowerCase().includes(filterKata) ||
|
| 354 |
+
d.kesimpulan.toLowerCase().includes(filterKata)
|
| 355 |
);
|
| 356 |
}
|
| 357 |
|
| 358 |
filtered.forEach((d, i) => {
|
| 359 |
+
const originalIndex = dataPembelajaran.indexOf(d);
|
| 360 |
const row = tbody.insertRow();
|
| 361 |
row.insertCell(0).textContent = i + 1;
|
| 362 |
row.insertCell(1).textContent = d.tanggal;
|
|
|
|
| 366 |
row.insertCell(5).innerHTML = '<div class="text-wrap">' + d.kesimpulan.replace(/\n/g, '<br>') + '</div>';
|
| 367 |
|
| 368 |
const cellAksi = row.insertCell(6);
|
| 369 |
+
cellAksi.className = 'action-buttons';
|
| 370 |
cellAksi.innerHTML = `
|
| 371 |
+
<button class="small" onclick="editData(${originalIndex})" style="background:#28a745;">Edit</button>
|
| 372 |
+
<button class="small danger" onclick="deleteData(${originalIndex})">Hapus</button>
|
| 373 |
`;
|
| 374 |
});
|
| 375 |
}
|
| 376 |
|
| 377 |
function terapkanFilter() {
|
| 378 |
+
tampilkanData();
|
|
|
|
|
|
|
| 379 |
}
|
| 380 |
|
| 381 |
function resetFilter() {
|
|
|
|
| 384 |
tampilkanData();
|
| 385 |
}
|
| 386 |
|
|
|
|
| 387 |
function importExcel() {
|
| 388 |
const fileInput = document.getElementById('importFile');
|
| 389 |
const file = fileInput.files[0];
|
|
|
|
| 402 |
const entry = {
|
| 403 |
tanggal: row['Tanggal'] || row['tanggal'] || new Date().toLocaleString('id-ID'),
|
| 404 |
jenis: row['Jenis'] || row['jenis'] || '',
|
| 405 |
+
indikator: row['Indicator'] || row['Indikator'] || row['indicator'] || row['sub bab'] || '',
|
| 406 |
hasil: row['Hasil Pembelajaran'] || row['Hasil'] || row['hasil'] || '',
|
| 407 |
kesimpulan: row['Kesimpulan'] || row['kesimpulan'] || ''
|
| 408 |
};
|
| 409 |
|
| 410 |
if (entry.jenis && entry.indikator && entry.hasil && entry.kesimpulan) {
|
| 411 |
dataPembelajaran.push(entry);
|
|
|
|
|
|
|
| 412 |
imported++;
|
| 413 |
}
|
| 414 |
});
|
| 415 |
|
|
|
|
|
|
|
| 416 |
localStorage.setItem('pembelajaran', JSON.stringify(dataPembelajaran));
|
| 417 |
+
buildSubBabMapping();
|
| 418 |
+
updateJenisDropdown();
|
| 419 |
+
updateIndicatorDropdown();
|
| 420 |
+
updateAutocompleteSuggestions();
|
| 421 |
tampilkanData();
|
| 422 |
+
alert(`Berhasil mengimport ${imported} data!`);
|
| 423 |
fileInput.value = '';
|
| 424 |
} catch (err) {
|
| 425 |
alert('Gagal membaca file: ' + err.message);
|
|
|
|
| 429 |
}
|
| 430 |
|
| 431 |
function exportExcel() {
|
| 432 |
+
if (dataPembelajaran.length === 0) return alert('Tidak ada data!');
|
| 433 |
const ws = XLSX.utils.json_to_sheet(dataPembelajaran);
|
| 434 |
const wb = XLSX.utils.book_new();
|
| 435 |
XLSX.utils.book_append_sheet(wb, ws, "Pembelajaran");
|
|
|
|
| 437 |
}
|
| 438 |
|
| 439 |
function exportPDF() {
|
| 440 |
+
if (dataPembelajaran.length === 0) return alert('Tidak ada data!');
|
|
|
|
| 441 |
const doc = new jsPDF('l', 'mm', 'a4');
|
| 442 |
doc.setFontSize(18);
|
| 443 |
doc.text("Laporan Catatan Pembelajaran", 14, 20);
|
|
|
|
| 445 |
doc.text("Dicetak pada: " + new Date().toLocaleString('id-ID'), 14, 30);
|
| 446 |
|
| 447 |
const tableData = dataPembelajaran.map((d, i) => [
|
| 448 |
+
i + 1, d.tanggal, d.jenis, d.indikator,
|
|
|
|
|
|
|
|
|
|
| 449 |
d.hasil.length > 80 ? d.hasil.substring(0,80) + '...' : d.hasil,
|
| 450 |
d.kesimpulan.length > 80 ? d.kesimpulan.substring(0,80) + '...' : d.kesimpulan
|
| 451 |
]);
|
|
|
|
| 456 |
startY: 40,
|
| 457 |
styles: { fontSize: 10, cellPadding: 3 },
|
| 458 |
headStyles: { fillColor: [0, 123, 255] },
|
| 459 |
+
columnStyles: { 0: { cellWidth: 15 }, 1: { cellWidth: 35 }, 2: { cellWidth: 35 }, 3: { cellWidth: 40 }, 4: { cellWidth: 70 }, 5: { cellWidth: 70 } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
});
|
| 461 |
|
| 462 |
doc.save("Catatan_Pembelajaran_" + new Date().toISOString().slice(0,10) + ".pdf");
|
|
|
|
| 469 |
if (evt) evt.currentTarget.classList.add("active");
|
| 470 |
|
| 471 |
if (tabName === 'Daftar') {
|
| 472 |
+
updateJenisDropdown();
|
| 473 |
+
updateAutocompleteSuggestions();
|
| 474 |
tampilkanData();
|
| 475 |
}
|
| 476 |
}
|
| 477 |
|
| 478 |
// Inisialisasi
|
| 479 |
+
buildSubBabMapping();
|
| 480 |
+
updateJenisDropdown();
|
| 481 |
+
updateIndicatorDropdown();
|
| 482 |
+
updateAutocompleteSuggestions();
|
| 483 |
</script>
|
| 484 |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=alterzick/notepad-v1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 485 |
</html>
|