+
+
+
-
+ Library
+Add books to your virtual library
+
+
-
-
+
+
+
+
diff --git a/debugging/book-library/script.js b/debugging/book-library/script.js
index 75ce6c1d..77a6c933 100644
--- a/debugging/book-library/script.js
+++ b/debugging/book-library/script.js
@@ -7,7 +7,7 @@ window.addEventListener("load", function (e) {
function populateStorage() {
if (myLibrary.length == 0) {
- let book1 = new Book("Robison Crusoe", "Daniel Defoe", "252", true);
+ let book1 = new Book("Robinson Crusoe", "Daniel Defoe", "252", true);
let book2 = new Book(
"The Old Man and the Sea",
"Ernest Hemingway",
@@ -28,33 +28,66 @@ const check = document.getElementById("check");
//check the right input from forms and if its ok -> add the new book (object in array)
//via Book function and start render function
function submit() {
+ const titleValue = title.value.trim();
+ const authorValue = author.value.trim();
+ const pagesValue = pages.value.trim();
if (
- title.value == null ||
- title.value == "" ||
- pages.value == null ||
- pages.value == ""
+ !titleValue ||
+ !authorValue ||
+ !pagesValue ||
+ Number(pagesValue) <= 0 ||
+ Number.isNaN(Number(pagesValue)) ||
+ !/^[1-9]\d*$/.test(pagesValue)
) {
- alert("Please fill all fields!");
+ alert("Please fill all fields with valid input!");
return false;
} else {
- let book = new Book(title.value, title.value, pages.value, check.checked);
- library.push(book);
+ let book = new Book(
+ titleValue,
+ authorValue,
+ Number(pagesValue),
+ check.checked
+ );
+ myLibrary.push(book);
render();
+
+ //clears the form for new entries
+ title.value = "";
+ author.value = "";
+ pages.value = "";
+ check.checked = false;
}
}
function Book(title, author, pages, check) {
this.title = title;
this.author = author;
- this.pages = pages;
+ this.pages = Number(pages);
this.check = check;
}
+function escapeSpecialCharacters(str) {
+ return str
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+}
+function alertDeleteToast(message) {
+ const toast = document.getElementById("toast");
+ toast.innerHTML = message;
+ toast.classList.add("visible");
+
+ setTimeout(() => {
+ toast.classList.remove("visible");
+ }, 4000);
+}
function render() {
let table = document.getElementById("display");
let rowsNumber = table.rows.length;
//delete old table
- for (let n = rowsNumber - 1; n > 0; n-- {
+ for (let n = rowsNumber - 1; n > 0; n--) {
table.deleteRow(n);
}
//insert updated row and cells
@@ -71,33 +104,31 @@ function render() {
pagesCell.innerHTML = myLibrary[i].pages;
//add and wait for action for read/unread button
- let changeBut = document.createElement("button");
- changeBut.id = i;
- changeBut.className = "btn btn-success";
- wasReadCell.appendChild(changeBut);
- let readStatus = "";
- if (myLibrary[i].check == false) {
- readStatus = "Yes";
- } else {
- readStatus = "No";
- }
- changeBut.innerText = readStatus;
+ let changeBtn = document.createElement("button");
+ changeBtn.className = "btn btn-success";
+ wasReadCell.appendChild(changeBtn);
+
+ let readStatus = myLibrary[i].check ? "Yes" : "No";
+ changeBtn.innerText = readStatus;
- changeBut.addEventListener("click", function () {
+ changeBtn.addEventListener("click", function () {
myLibrary[i].check = !myLibrary[i].check;
render();
});
//add delete button to every row and render again
- let delButton = document.createElement("button");
- delBut.id = i + 5;
- deleteCell.appendChild(delBut);
- delBut.className = "btn btn-warning";
- delBut.innerHTML = "Delete";
- delBut.addEventListener("clicks", function () {
- alert(`You've deleted title: ${myLibrary[i].title}`);
+ let deleteBtn = document.createElement("button");
+ deleteBtn.className = "btn btn-warning";
+ deleteBtn.innerHTML = "Delete";
+ deleteCell.appendChild(deleteBtn);
+
+ deleteBtn.addEventListener("click", function () {
+ const deleteTitle = myLibrary[i].title;
myLibrary.splice(i, 1);
render();
+ alertDeleteToast(
+ `You've deleted title:
${escapeSpecialCharacters(deleteTitle)}` + ); }); } } diff --git a/debugging/book-library/style.css b/debugging/book-library/style.css index 302950cb..187711fc 100644 --- a/debugging/book-library/style.css +++ b/debugging/book-library/style.css @@ -1,19 +1,94 @@ +.jumbotron { + padding: 1.5rem 2rem; + margin-bottom: 1rem; + text-align: center; +} + +.jumbotron h2 { + font-size: 1.5rem; + font-weight: 300; + margin-top: 0.5rem; +} + .form-group { width: 400px; height: 300px; - align-self: left; - padding-left: 20px; + padding-left: 50px; +} + +#check { + margin-left: 0; + margin-top: 10px; } .btn { display: block; } +.form-control { + border-style: solid; + border-color: lightslategrey; +} + .form-check-label { padding-left: 20px; margin: 5px 0px 5px 0px; } -button.btn-info { - margin: 20px; +.btn-info { + background-color: blue; + border-color: blue; + color: #fff; + margin: 20px 20px 20px 50px; +} + +.btn-success { + background-color: #0d4a0d; + border-color: #0d4a0d; + color: #fff; +} + +.btn-success:hover, +.btn-success:focus { + background-color: #1f6e1f; + border-color: #1f6e1f; + color: #fff; +} + +.btn-warning { + background-color: #9f6000; + border-color: #9f6000; + color: #fff; +} + +.btn-warning:hover, +.btn-warning:focus { + background-color: #b76e01; + border-color: #b76e01; + color: #fff; +} + +/* for delete alert */ +.toast { + position: fixed; + top: 130px; + left: 50%; + font-size: 1rem; + transform: translateX(-50%); + background: #a84600; + color: white; + min-width: 300px; + width: fit-content; + white-space: normal; + word-wrap: break-word; + text-align: center; + padding: 10px 15px; + border-radius: 5px; + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; +} + +.toast.visible { + opacity: 1; }
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+ type="submit"
+ value="Submit"
+ class="btn btn-primary"
+ onclick="submit()"
+ />
+
+
| Title | -Author | -Number of Pages | -Read | -- |
|---|---|---|---|---|
| - | - | - | - | - |
| Title | +Author | +Number of Pages | +Read | ++ |
|---|
${escapeSpecialCharacters(deleteTitle)}` + ); }); } } diff --git a/debugging/book-library/style.css b/debugging/book-library/style.css index 302950cb..187711fc 100644 --- a/debugging/book-library/style.css +++ b/debugging/book-library/style.css @@ -1,19 +1,94 @@ +.jumbotron { + padding: 1.5rem 2rem; + margin-bottom: 1rem; + text-align: center; +} + +.jumbotron h2 { + font-size: 1.5rem; + font-weight: 300; + margin-top: 0.5rem; +} + .form-group { width: 400px; height: 300px; - align-self: left; - padding-left: 20px; + padding-left: 50px; +} + +#check { + margin-left: 0; + margin-top: 10px; } .btn { display: block; } +.form-control { + border-style: solid; + border-color: lightslategrey; +} + .form-check-label { padding-left: 20px; margin: 5px 0px 5px 0px; } -button.btn-info { - margin: 20px; +.btn-info { + background-color: blue; + border-color: blue; + color: #fff; + margin: 20px 20px 20px 50px; +} + +.btn-success { + background-color: #0d4a0d; + border-color: #0d4a0d; + color: #fff; +} + +.btn-success:hover, +.btn-success:focus { + background-color: #1f6e1f; + border-color: #1f6e1f; + color: #fff; +} + +.btn-warning { + background-color: #9f6000; + border-color: #9f6000; + color: #fff; +} + +.btn-warning:hover, +.btn-warning:focus { + background-color: #b76e01; + border-color: #b76e01; + color: #fff; +} + +/* for delete alert */ +.toast { + position: fixed; + top: 130px; + left: 50%; + font-size: 1rem; + transform: translateX(-50%); + background: #a84600; + color: white; + min-width: 300px; + width: fit-content; + white-space: normal; + word-wrap: break-word; + text-align: center; + padding: 10px 15px; + border-radius: 5px; + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; +} + +.toast.visible { + opacity: 1; }