alterzick commited on
Commit
8b97ea7
·
verified ·
1 Parent(s): 2e6530e

Add 2 files

Browse files
Files changed (1) hide show
  1. 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 untuk PDF berkualitas tinggi -->
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 untuk Excel -->
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: 14px; }
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
- .edit-mode { background: #fff3cd; padding: 10px; border-radius: 8px; margin-bottom: 20px; }
43
  @media (max-width: 768px) {
44
  .filter-group { flex-direction: column; }
45
- .tablink { font-size: 16px; padding: 12px; }
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, dll.">
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 Dasar">
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()">Reset Form</button>
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"><option value="">Semua Jenis</option></select>
 
 
106
  </div>
107
  <div>
108
  <label>Filter Kata Kunci</label>
109
- <input type="text" id="filterKata" placeholder="Cari di hasil atau kesimpulan...">
 
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 style="width:5%;">No</th>
133
- <th style="width:15%;">Tanggal</th>
134
- <th style="width:12%;">Jenis</th>
135
- <th style="width:15%;">Indicator</th>
136
- <th style="width:25%;">Hasil Pembelajaran</th>
137
- <th style="width:23%;">Kesimpulan</th>
138
- <th style="width:10%;">Aksi</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 jenisList = [...new Set(dataPembelajaran.map(d => d.jenis))].sort();
152
- if (jenisList.length === 0) jenisList = ["Matematika", "Bahasa", "Sains"];
153
- let indicatorList = [...new Set(dataPembelajaran.map(d => d.indikator))].sort();
154
- if (indicatorList.length === 0) indicatorList = ["Dasar", "Menengah", "Lanjutan"];
 
 
 
 
 
 
 
 
 
 
 
155
 
156
- let editIndex = -1; // -1 = tambah baru, >=0 = edit entri
 
 
157
 
158
- function updateDropdowns() {
159
  const jenisSelect = document.getElementById('jenisSelect');
160
  const filterJenis = document.getElementById('filterJenis');
161
- const indicatorSelect = document.getElementById('indicatorSelect');
162
 
163
  jenisSelect.innerHTML = '';
164
  filterJenis.innerHTML = '<option value="">Semua Jenis</option>';
165
- jenisList.forEach(j => {
 
 
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
- indicatorList.forEach(i => indicatorSelect.add(new Option(i, i)));
 
 
 
 
 
 
 
 
 
 
 
 
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
- updateDropdowns();
 
 
 
230
  resetForm();
 
231
  if (document.getElementById('Daftar').classList.contains('active')) tampilkanData();
232
  }
233
 
234
  function resetForm() {
235
  editIndex = -1;
236
- document.getElementById('editModeInfo').style.display = 'none';
237
- document.getElementById('jenisSelect').value = jenisList[0] || '';
238
  document.getElementById('manualJenisInput').style.display = 'none';
239
  document.getElementById('jenisManual').value = '';
240
- document.getElementById('indicatorSelect').value = indicatorList[0] || '';
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 batalEdit() {
248
- resetForm();
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 (jenisList.includes(entry.jenis)) {
264
- jenisSelect.value = entry.jenis;
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 (indicatorList.includes(entry.indikator)) {
274
- indicatorSelect.value = entry.indikator;
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 = entry.hasil;
283
- document.getElementById('kesimpulan').value = entry.kesimpulan;
 
 
 
 
284
  }
285
 
286
- function hapusEntri(index) {
287
- if (confirm('Yakin ingin menghapus entri ini?')) {
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(filterJenis = '', filterKata = '') {
 
 
 
296
  const tbody = document.querySelector('#tabelPembelajaran tbody');
297
  tbody.innerHTML = '';
298
 
299
  let filtered = dataPembelajaran;
300
- if (filterJenis) filtered = filtered.filter(d => d.jenis === filterJenis);
 
 
 
 
 
 
301
  if (filterKata) {
302
- const kata = filterKata.toLowerCase();
303
  filtered = filtered.filter(d =>
304
- d.hasil.toLowerCase().includes(kata) || d.kesimpulan.toLowerCase().includes(kata)
 
305
  );
306
  }
307
 
308
  filtered.forEach((d, i) => {
309
- const actualIndex = dataPembelajaran.indexOf(d);
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="secondary small" onclick="editEntri(${actualIndex})">Edit</button>
321
- <button class="danger small" onclick="hapusEntri(${actualIndex})">Hapus</button>
322
  `;
323
  });
324
  }
325
 
326
  function terapkanFilter() {
327
- const filterJenis = document.getElementById('filterJenis').value;
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 (Sub Bab)'] || row['Indikator'] || row['indicator'] || row['sub bab'] || '',
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
- updateDropdowns();
 
 
 
374
  tampilkanData();
375
- alert(`Berhasil mengimport ${imported} data pembelajaran!`);
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 untuk diekspor!');
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 untuk diekspor!');
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
- alternateRowStyles: { fillColor: [245, 248, 255] },
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
- updateDropdowns();
 
438
  tampilkanData();
439
  }
440
  }
441
 
442
  // Inisialisasi
443
- updateDropdowns();
444
- tampilkanData(); // jika langsung buka tab daftar
 
 
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>