-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
497 lines (475 loc) · 18.8 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
const schoolInputs = document.querySelectorAll(".modal input, .modal select");
const schoolFormSubmit = document.querySelector(".btn-outline-primary");
const schoolNameHeader = document.querySelector("main h1");
const classNum = document.getElementById("class-num");
const className = document.getElementById("class-name");
const studentNo = document.getElementById("student-no");
const studentName = document.getElementById("fullname");
const studentGrades = document.querySelectorAll(".grades");
const studentForm = document.querySelector("main");
const tableBody = document.querySelector("tbody");
const alertBox = document.getElementById("alert-box");
const resetBtn = document.querySelector("#reset");
const schoolForm = document.getElementById("staticBackdrop");
/** başlangıçta modal açılması için verilen bootstrap5 destekli kodlar fakat problem çıkarıyor
var myModal = new bootstrap.Modal(schoolForm, {})
schoolForm.show()
*/
// fonksiyonları yukarıda topladım
// localstorage da kayıt varsa içinden sınıf sayılarını çeker ve bunlar ile select içne options koyar
function fillSelect() {
classNum.innerHTML = "";
classNum.innerHTML = `<option selected disabled>Select Grade</option>`;
Object.keys(data).forEach((item) => {
classNum.innerHTML += `<option value="${item}">${item}</option>`;
});
}
//! tablonun üst kısmında yapılan işleme göre alarm div oluşturuyor. str=metin kısmı/ alertType= "warning", "success" bootstrap classları/ strongStr= Dikkat edilmesini istediğiniz metin, başta çıkıyor. burada default değerler de koydum. strongStr opsiyonel.
function showAlert(str = "Error", alertType = "warning", strongStr = "") {
let alertDiv = `<div class="alert alert-${alertType} alert-dismissible fade show" role="alert">
<strong>${strongStr}</strong> ${str}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>`;
//* burada tablonun üst kısmında bulunan boş div içine alert oluşturuyoruz. faydası üst üste oluşan alertler aynı yerde tek çıkıyor. alert içinde kapatma butonu da var */
alertBox.innerHTML = alertDiv;
}
// burada eğer localStorage içinde daha önce kayıtlarımız varsa çekiyoruz. yoksa boş bir obje oluşturuyoruz
let data = JSON.parse(localStorage.getItem("school")) || {};
function exportToJsonFile() {
data = JSON.parse(localStorage.getItem("school"));
let dataStr = JSON.stringify(data);
let dataUri =
"data:application/json;charset=utf-8," + encodeURIComponent(dataStr);
let exportFileDefaultName = "yedek.json";
let linkElement = document.createElement("a");
linkElement.setAttribute("href", dataUri);
linkElement.setAttribute("download", exportFileDefaultName);
linkElement.click();
}
//okul sınıf numaralarını oluştururken kullandığımız boş değişkenler
let clsNumbers = [];
let letters = [];
// datayı çektikten sonra sınıf listesini doldurduk
fillSelect();
/** burada okul genel bilgilerinin local'de kayıtlı olup olmadığını okul ismiyle
kontrol ediyoruz. varsa okul başlığını değiştirdik, eğer yoksa modal açma linki oluşturup click'ledik. */
if (localStorage.getItem("schoolName")) {
schoolNameHeader.innerHTML = `${localStorage.getItem(
"schoolName"
)}<br><span class="badge rounded-pill bg-info fs-4">${localStorage.getItem(
"schoolType"
)}</span>`;
} else {
window.onload = () => {
const modalLaunch = document.createElement("a");
modalLaunch.setAttribute("data-bs-toggle", "modal");
modalLaunch.setAttribute("data-bs-target", "#staticBackdrop");
document.body.appendChild(modalLaunch);
modalLaunch.click();
};
/*
if (!localStorage.getItem("schoolName")) {
}; */
//modal açıldığında ilk inputu aktif etme
schoolForm.addEventListener("shown.bs.modal", function () {
schoolInputs[0].focus();
});
}
//** bu kısım modal kısmında ki form. */
schoolFormSubmit.addEventListener("click", (e) => {
// preventDefault iptal sebebim bu kısım doldurulup onaylandıktan sonra bir daha ihtiyaç duymamam ve sayfaya bir kaç komut eklemek yerine yenilenmesi daha kolay :)
// e.preventDefault();
console.log(schoolInputs[3].value, schoolInputs[2].value,schoolInputs[0].value,schoolInputs[1].value );
if (+schoolInputs[3].value > +schoolInputs[2].value) {
//aşağıda bulunan okul objemize okul ismi ve türünü aktarıyoruz.
school.schoolName = schoolInputs[0].value;
school.schoolType = schoolInputs[1].value;
//** burada sınıfların başlangıç ve bitiş array'ini oluşturuyoruz
//! özetle [...Array(5).keys()].splice(1) == [1,2,3,4]
/*! 5 elemanlı bir array oluşturup bunun "keys()" index'leriyle başka bir
array yapıyoruz. index 0 dan başladığı için yapmak istediğimiz diziden bir fazlasını
yapıp ilk elemanı splice ile siliyoruz.*/
clsNumbers = [...Array(+schoolInputs[3].value + 1).keys()].splice(
schoolInputs[2].value
);
//! letters ve clsNumbers globalde oluşturmamızın sebebi daha sonra school metodunda kullanacak olmamız
// burada formda belirtilen harf kadar bir array dizisi oluşturduk
const alphabet = "ABCDEFGHIJK";
letters = alphabet.slice(0, schoolInputs[4].value).split("");
//sınıf kademeleri select'ini doldurduk.
fillSelect();
/* burada localStorage'da "school" key ile, school.makeClasses metodunda oluşturduğumuz
objemizi json metnine dönüştürüp kaydettik
ayrıca okul ismi ve tipini de kaydettik*/
localStorage.setItem("school", JSON.stringify(school.makeClasses()));
localStorage.setItem("schoolName", school.schoolName);
localStorage.setItem("schoolType", school.schoolType);
// kayıt işleminden sonra başlıklarımızı yeniledik
schoolNameHeader.innerHTML = `${localStorage.getItem(
"schoolName"
)}<br><span class="badge rounded-pill bg-info fs-4">${localStorage.getItem(
"schoolType"
)}</span>`;
// son halini local storage dan çekerek data değişkenimizi yeniledik
data = JSON.parse(localStorage.getItem("school"));
} else {
// hatalı bilgi girilmesi durumunda sayfa yenilenmesin
e.preventDefault();
alert("Wrong entries!");
}
});
// sınıf seviyesi seçilince ilgili sınıflar select menüye ekleniyor
studentForm.addEventListener("change", (e) => {
if (e.target.id == "class-num") {
className.innerHTML = "";
/** data ile classnumber value ile birleştirip
* key'leri yani sınıf adlarını foreach ile çekerek class name
* selectine options olarak ekledik. kısaca "data[x].keys().foreach gibi */
data = JSON.parse(localStorage.getItem("school"));
Object.keys(data[e.target.value]).forEach((item) => {
className.innerHTML += `<option value="${item}">${item}</option>`;
});
}
});
//* öğrenci formu click eventleri */
studentForm.addEventListener("click", (e) => {
// öğrenci arama listeleme
if (e.target.id == "search") {
// sayfa yenilememesi için
e.preventDefault();
//sınıf adı boşsa alert ver
if (!className.value) {
return showAlert("Select Class Name", "warning");
}
// boşluklar doluysa öğrenciyi çek ve
if (studentNo.value && classNum.value) {
let studentList = school.clsStudents.getStudents(
classNum.value,
className.value,
studentNo.value
);
//gelen verileri tabloya yazdır
if (studentList) {
let tableRow = `<tr>
<th scope="row">${className.value}</th>
<td>${studentNo.value}</td>
<td>${studentList.info[0]}</td>
<td>${studentList.info[1]}</td>
</tr>`;
tableBody.innerHTML = "";
tableBody.innerHTML += tableRow;
} else {
//gelen veri yoksa alert ver
showAlert(
"There is not a student with search arguments",
"alert alert-warning"
);
}
// öğrenci no yosa sınıf listesini getirir
} else {
let studentList = school.clsStudents.getStudents(
classNum.value,
className.value
);
//tabloyu boşalt
tableBody.innerHTML = "";
// getstudents ile gelen listeden restructure yöntemiyle yeni variable lar tanımladık. gelen verileri tabloya foreach ile yazdırıyoruz
Object.keys(studentList).forEach((studentNo) => {
let {
[studentNo]: {
info: [fullname, [grades]],
},
} = studentList;
let tableRow = `<tr>
<th scope="row">${className.value}</th>
<td >${studentNo}</td>
<td class="text-capitalize">${fullname}</td>
<td>${grades}<i class="bi bi-person-x fs-5 py-0 float-end btn"></i></td>
</tr>`;
tableBody.innerHTML += tableRow;
});
}
}
//* öğrenci ekleme
if (e.target.id == "register") {
e.preventDefault();
// addStudent metodumuza input value'ları gönderdik ve result ile return ettiğimiz sonucu aldık
let result = school.clsStudents.addStnt(
classNum.value,
className.value,
studentNo.value,
studentName.value,
//studentGrades queryselectorall ile gelen nodelist.
//bunu array yaptık ve map ile valuelarını aldık
[...studentGrades].map((x) => x.value)
);
//metodumuz kayıt başarılı ile bir metin döndürüyor. sonuca göre alert veriyoruz.
if (result) {
let tableRow =""
switch (result[0]) {
case 1:
showAlert(
result[1], "warning",
);
break;
case 2:
showAlert(
`${studentNo.value} : ${studentName.value}'s record has been added.`,
"success",
result[1]
);
tableRow = `<tr>
<th scope="row">${className.value}</th>
<td >${studentNo.value}</td>
<td class="text-capitalize">${studentName.value}</td>
<td>${[...studentGrades].map(
(x) => x.value
)}<i class="bi bi-person-x fs-5 py-0 float-end btn"></i></td>
</tr>`;
tableBody.innerHTML += tableRow;
break;
case 3:
showAlert(
result[1], "warning",
);
break;
case 4:
showAlert(
`${studentNo.value} : ${studentName.value}'s record has been added.`,
"success",
result[1]
);
tableRow = `<tr>
<th scope="row">${className.value}</th>
<td >${studentNo.value}</td>
<td class="text-capitalize">${studentName.value}</td>
<td>${[...studentGrades].map(
(x) => x.value
)}<i class="bi bi-person-x fs-5 py-0 float-end btn"></i></td>
</tr>`;
tableBody.innerHTML += tableRow;
break;
}
return;
}
showAlert("Error : Please control student information", "danger", result);
}
if (e.target == resetBtn) {
className.innerHTML = "";
}
//localStorage silme metodunu çağırdık
if (
e.target.id == "delete-all" &&
confirm("Are you sure you want to delete all entries!!!")
) {
e.preventDefault();
school.clsStudents.deleteAll();
// burada tekrar okul kayıt penceresini açıyoruz
const modalLaunch = document.createElement("a");
modalLaunch.setAttribute("data-bs-toggle", "modal");
modalLaunch.setAttribute("data-bs-target", "#staticBackdrop");
document.body.appendChild(modalLaunch);
modalLaunch.click();
}
// tablodaki öğrenciyi silme işlemi
if (e.target.classList.contains("bi-person-x")) {
if (confirm("Are you sure you want to delete student entry!")) {
/*!!! burada resutructuring işlemi ile tablo satırındaki tüm metinleri ayrı ayrı değişkenlere atıyoruz. */
let [clsName, no, studentName] = [
...e.target.parentElement.parentElement.children,
].map((x) => x.innerHTML);
//! bu değişkenleri deleteStudent metodumuza gönderdik
school.clsStudents.deleteStudent(clsName[0], clsName, no);
// tablo satırını sildik
e.target.parentElement.parentElement.remove();
//ve son olarak alert verdik
showAlert(`${no} : ${studentName}'s record has been deleted.`, "danger");
}
}
// localdeki veriyi json dosyası olarak indirmemizi sağlıyor.
if (e.target.id == "backup") {
e.preventDefault();
data = JSON.parse(localStorage.getItem("school"));
let dataStr = JSON.stringify(data);
let dataUri =
"data:application/json;charset=utf-8," + encodeURIComponent(dataStr);
let exportFileDefaultName = "yedek.json";
let linkElement = document.createElement("a");
linkElement.setAttribute("href", dataUri);
linkElement.setAttribute("download", exportFileDefaultName);
linkElement.click();
}
// yedeklediğimiz json dosyasından data ve localstorage'a geri yüklüyor
if (e.target.id == "restore") {
e.preventDefault();
const getFile = document.createElement("input");
getFile.setAttribute("type", "file");
getFile.setAttribute("id", "selectFiles");
getFile.click();
console.log(getFile);
getFile.addEventListener("change", () => {
let files = getFile.files;
if (files.length <= 0) {
return false;
}
let fileReader = new FileReader();
fileReader.onload = function (e) {
var result = JSON.parse(e.target.result);
console.log(result);
data = JSON.stringify(result);
localStorage.setItem("school", data);
};
fileReader.readAsText(files.item(0));
});
/* !! html localde ise çalışır
fetch("./yedek.json")
.then((response) => {
return response.json();
})
.then((jsondata) =>
localStorage.setItem("school", JSON.stringify(jsondata))
);
console.log(data); !! html localde ise çalışır*/
}
});
//! tüm işler için kullandığımız objemiz
const school = {
schoolName: "",
schoolType: "",
/*okul bilgileri formundan aldığımız sınıf sayısı ve şube sayısı
verileriyle sınıf objemizi oluşturan metod. okul formunu submit ettiğimizde çağırmıştık*/
makeClasses: function () {
// https://www.linkedin.com/pulse/creating-nested-objects-javascript-dynamically-ahmed-ellithy/?trk=articles_directory
let obj = {};
let makeClasses = {};
let d = clsNumbers[0];
let classNames = this.findClassesWithLetters(d);
for (const i of clsNumbers) {
for (const j of classNames) {
obj[j] = {};
}
d++;
makeClasses[i] = obj;
obj = {};
classNames = this.findClassesWithLetters(d);
}
return makeClasses;
},
classGroups: () => {
//yoruma aldığım kısımda iş görüyor ama benim başta oluşturduğum yapı bozuluyor
// let clsWithLttrs = Object.keys(school.clsStudents.getStudents()[1]);
// burada temp "1-A","1-B".. item ise 1,2,3 sonuç olarak sınıf sayısı ve harfleri birleştirerek şubelerisınıflar ve map olarak döndürüyor
const clsWithLttrs = new Map();
clsNumbers.forEach((item) => {
for (let i = 0; i < letters.length; i++) {
let temp = `${item}-${letters[i]}`;
clsWithLttrs.set(temp, item);
}
});
return clsWithLttrs;
},
findClassesWithLetters: function (number) {
/*classGroups metodundan dönen map'i key, value parçalarıyla array yapıp
metod parametresinden aldığımız sınıf numarası ile filtreliyoruz*/
let filteredClasses = [...this.classGroups().entries()].filter(
(item) => item[1] === number
);
// gereksiz boşlukları kaldırdık
filteredClasses.forEach((e) => {
e.splice(1, 1);
});
//içiçe(nested) arrayi düz array yaptık
let flatClassList = filteredClasses.flat();
return flatClassList;
},
classes: function () {
/*classGroups dan aldığımız ["A-1":1]... şeklindeki veriyi [A-1:0] olarak değiştirdim.
amacım sınıf mevcudu ve devamsızlık gibi veriler için kullanmaktı.
sonra bakılacak.*/
const classList = new Map(school.classGroups());
[...classList.keys()].forEach((key) => {
classList.set(key, 0);
});
// classList.forEach((_,i) => {classList.set(i,0)});
return classList;
},
//! öğrenci işleri...
clsStudents: {
//öğrenci ekleme
addStnt: function (clsNum, clsName, no, studentName, grades) {
// not dışındaki veriler gelmişse
if (clsNum && clsName && no && studentName) {
function checkGrade(grade) {
// console.log(grade);
return grade > 100;
}
if (grades.some(checkGrade)) {
return [1,"Grades must be between 0-100"];
} else {
// burada nullish kullanmıştım localde kayıt yoksa diye fakat gerek kalmadı
let data = JSON.parse(localStorage.getItem("school")); //?? school.makeClasses();
let res;
// kaydedilecek öğrenci no kayıtlarda var mı?
Object.keys(data).forEach((dtClsNum) => {
Object.keys(data[dtClsNum]).forEach((dtClsName) => {
Object.keys(data[dtClsNum][dtClsName]).forEach((dtNo) => {
if (dtNo == no) {
if (
confirm(
`At ${dtClsName} class there is same ${dtNo} number. Do you want to update student name and grades?`
)
) {
data[dtClsNum][dtClsName][dtNo] = {
info: [studentName, grades],
};
localStorage.setItem("school", JSON.stringify(data));
//nested yapıda return yerine kullanılabilir
res = [2,"Record change success"];
} else {
res = [3,"Record change cancel"];
}
}
});
});
});
//yukarıda kullandığım return benzeri yapıyla kayıt işleminin tekrarlanmasını engelledim
if (res) {
return res;
} else {
data[clsNum][clsName][no] = { info: [studentName, grades] };
localStorage.setItem("school", JSON.stringify(data));
return [4,"New student added"];
}
}
} else {
// hiç bir işlem yapılamadıysa hata vermesi için
return null;
}
},
// girilen veriye göre sıralı öğrenci listeleme
getStudents: function (clsNum, clsName, no) {
let data = JSON.parse(localStorage.getItem("school"));
if (clsNum && clsName && no) {
return data[clsNum][clsName][no];
} else if (clsNum && clsName) {
return data[clsNum][clsName];
} else if (clsNum) {
return data[clsNum];
} else {
return data;
}
},
//* öğrenci silme
deleteStudent: (clsNum, clsName, no) => {
let data = JSON.parse(localStorage.getItem("school"));
delete data[clsNum][clsName][no];
localStorage.setItem("school", JSON.stringify(data));
},
//* tüm öğrenci ve okul kayıtlarını silme
deleteAll: () => {
localStorage.removeItem("school");
localStorage.removeItem("schoolName");
localStorage.removeItem("schoolType");
},
},
};