Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - efko

Pages: [1] 2 3 ... 60
1
New Members Introduction / Re: Whats up!
« on: 29 July 2026, 16:53:24 »
Welcome to the forum  O0
Not sure how many PS players are here on forum. Join our Discord and official TQ Discord, you should have better chance to find someone there.
Also eventually you can search for topics where playstation console was mentioned, check member profile and contact. If you are unable to send personal message atm since you have new forum account, you could find few members and use @name (like this @gothrock ) so they can see you. This is especially good if someone is not active on forum for some time, but is using email if email notification is turned on on profile.

2
Forum News and Info / Re: Birthdays
« on: 20 July 2026, 21:56:22 »
Happy birthday :)

3
Titan Quest News and Info / Re: Happy Birthday Titan Quest
« on: 26 June 2026, 12:51:40 »
Weird, next year is 10 years of tqfans and it doesn't look like that to me at all.

4
Forum News and Info / Re: Happy New Year 2026
« on: 01 January 2026, 12:05:15 »
Happy New Year and holidays wishes you TitanQuestFans community.
Yet again, as I said many times before, let this year be better than previous one.
And the most important than ever before, let these monsters, titans, telkins and all other bad folks feel your power and your anger when they see you on battlegrounds.

5
Javascript / Testovi
« on: 21 November 2025, 20:06:11 »
Provera znanja - test 14.10.2025.

1 Koji selector u CSS-u bira sve elemente /<p>/na stranici?
b. p



2. Izaberite jedan odgovor:
a. .nazivKlase
b. @nazivKlase
c. %nazivKlase
d. #nazivKlase



3. Koja od sledećih vrednosti ne postoji za /position/svojstvo?
a. relative
b. absolute
c. centered
d. fixed



4. Izaberite jedan odgovor:
a. position: absolute;
b. float: left;
c. display: inline;
d. display: block;



5. Kako da selektujemo sve /<div>/elemente sa klasom box?
d. div.box



6. Izaberite jedan odgovor:
a. Povećava font
b. Postavlja element iznad ili ispod drugih
c. Menja poziciju elementa
d. Rotira element



7. Koja je razlika između em i rem jedinica u CSS-u?
a. rem je relativan na root, em na roditelja



8. Izaberite jedan odgovor:
a. <script src="stil.css">
b. <link rel="stylesheet" href="stil.css">  Tačno
c. <css src="stil.css">
d. <style href="stil.css">



9. Izaberite jedan odgovor:
a. align-content
b. text-align
c. justify-content
d. align-items


6
Javascript / Re: Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:20:30 »

Spoiler for modalV1 JS:


import { correctName } from "./helper.js";
import { createProduct } from "./api.js";
const createProductNameInput = document.getElementById("name");
const createProductPriceInput = document.getElementById("price");
const createProductImageUrlInput = document.getElementById("image");
const createProductDescriptionInput = document.getElementById("description");
const createProductCharacteristicKeyInput = document.getElementById(
  "characteristics-key"
);
const createProductCharacteristicValueInput = document.getElementById(
  "characteristics-value"
);
const errorParagraph = document.createElement("p");
const createProductBtn =
  document.getElementsByClassName("create-product-btn")[0];
const articleContainer = document.getElementsByTagName("article")[0];

const newProduct = {
  name: null,
  price: -1,
  image: null,
  description: null,
  characteristics: {},
};

articleContainer.addEventListener("click", function (event) {
  const clickedElement = event.target;
  console.log(clickedElement);

  if (
    clickedElement.matches(".delete-btn") ||
    clickedElement.matches("svg") ||
    clickedElement.matches("path")
  ) {
    const span = clickedElement.closest(".key-value-span");
    const key = span.innerText.split(": ")[0];
    delete newProduct.characteristics[key];
    console.log(newProduct);
    span.remove();
  }
});

function setUpListeners() {
  removeEventListeners();
  createProductNameInput.addEventListener("blur", validation.productName);
  createProductPriceInput.addEventListener("blur", validation.productPrice);
  createProductImageUrlInput.addEventListener(
    "blur",
    validation.productImageUrl
  );
  createProductDescriptionInput.addEventListener(
    "blur",
    validation.productDesctiption
  );
  createProductCharacteristicKeyInput.addEventListener(
    "blur",
    validation.productCharacteristicKey
  );
  createProductCharacteristicValueInput.addEventListener(
    "blur",
    validation.productCharacteristicValue
  );
  createProductBtn.removeEventListener("click", createNewProduct);
  createProductBtn.addEventListener("click", createNewProduct);

  function createNewProduct(event) {
    if (
      newProduct.name &&
      newProduct.price &&
      newProduct.image &&
      newProduct.description
    ) {
      createProduct(newProduct, "http://localhost:3000/products");
      articleContainer.innerHTML = "";
    }
    resetInputs();
  }
}

function removeEventListeners() {
  createProductNameInput.removeEventListener("blur", validation.productName);
  createProductPriceInput.removeEventListener("blur", validation.productPrice);
  createProductImageUrlInput.removeEventListener(
    "blur",
    validation.productImageUrl
  );
  createProductDescriptionInput.removeEventListener(
    "blur",
    validation.productDesctiption
  );
  createProductCharacteristicKeyInput.removeEventListener(
    "blur",
    validation.productCharacteristicKey
  );
  createProductCharacteristicValueInput.removeEventListener(
    "blur",
    validation.productCharacteristicValue
  );
}

const validation = {
  productName: function (event) {
    removeErrorMsg();
    const nameInputValue = event.target.value.trim();
    if (nameInputValue.length > 3) {
      newProduct.name = correctName(nameInputValue);

      //   console.log(newProduct);
    } else {
      renderError(createProductNameInput, "Product name is not correct.");
    }
  },
  productPrice: function (event) {
    removeErrorMsg();
    const priceInputValue = parseFloat(event.target.value);
    // console.log(priceInputValue);
    if (priceInputValue > 0 && priceInputValue < 10000) {
      newProduct.price = priceInputValue;
      //   console.log(newProduct);
    } else {
      renderError(
        createProductPriceInput,
        "Product price is not in defined range."
      );
      //   console.log("Product price is not in defined range.");
    }
  },
  productImageUrl: function (event) {
    removeErrorMsg();
    const imageInputValue = event.target.value;

    const allowedProtocols = ["www", "http://", "https://"];
    const allowedExtensions = [".png", ".jpg", ".jpeg"];

    let isCorrectProtocol = false;
    let isCorrectExtension = false;

    for (const protocol of allowedProtocols) {
      if (imageInputValue.startsWith(protocol)) {
        isCorrectProtocol = true;
      }
    }

    for (const extension of allowedExtensions) {
      if (imageInputValue.endsWith(extension)) {
        isCorrectExtension = true;
      }
    }

    if (isCorrectExtension && isCorrectProtocol) {
      newProduct.image = imageInputValue;
      //   console.log(newProduct);
    } else {
      renderError(createProductImageUrlInput, "Url is not valid!");
      //   console.log("Url is not valid!");
    }
  },
  productDesctiption: function (event) {
    removeErrorMsg();
    const descriptionInputValue = event.target.value;

    if (
      descriptionInputValue.length > 20 &&
      descriptionInputValue.length < 200
    ) {
      newProduct.description = descriptionInputValue;
      //   console.log(newProduct);
    } else {
      renderError(
        createProductDescriptionInput,
        "Description is not defined well!"
      );
      //   console.log("Description is not defined well!");
    }
  },
  productCharacteristicKey: function (event) {
    const keyInputValue = event.target.value.trim();
    handleNewCharacteristics(
      keyInputValue,
      createProductCharacteristicValueInput.value
    );
  },
  productCharacteristicValue: function (event) {
    const valueInputValue = event.target.value.trim();
    handleNewCharacteristics(
      createProductCharacteristicKeyInput.value,
      valueInputValue
    );
  },
};

function handleNewCharacteristics(key, value) {
  removeErrorMsg();
  if (key && value) {
    createCharacteristicsElement(key, value);
    newProduct.characteristics[key] = value;
    resetCharacteristics();
    console.log(newProduct);
  } else {
    renderError(articleContainer, "Key or value is not defined!");
  }
  function resetCharacteristics() {
    createProductCharacteristicKeyInput.value = "";
    createProductCharacteristicValueInput.value = "";
  }
}

function createCharacteristicsElement(key, value) {
  const spanEl = `
  <span class="key-value-span"
                >${key}: ${value}
                <div class="delete-btn">
                  <svg
                    width="15px"
                    height="15px"
                    viewBox="0 0 24 24"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
                    <g
                      id="SVGRepo_tracerCarrier"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    ></g>
                    <g id="SVGRepo_iconCarrier">
                      <g id="Menu / Close_MD">
                        <path
                          id="Vector"
                          d="M18 18L12 12M12 12L6 6M12 12L18 6M12 12L6 18"
                          stroke="#000000"
                          stroke-width="2"
                          stroke-linecap="round"
                          stroke-linejoin="round"
                        ></path>
                      </g>
                    </g>
                  </svg>
                </div>
              </span>`;

  articleContainer.insertAdjacentHTML("beforeend", spanEl);
}

function resetInputs() {
  createProductNameInput.value = "";
  createProductPriceInput.value = "";
  createProductImageUrlInput.value = "";
  createProductDescriptionInput.value = "";
  createProductCharacteristicKeyInput.value = "";
  createProductCharacteristicValueInput.value = "";
}

function renderError(element, msg) {
  errorParagraph.classList.add("errParagraph");
  errorParagraph.innerText = msg;

  element.insertAdjacentElement("afterend", errorParagraph);
}

function removeErrorMsg() {
  errorParagraph.remove();
}

export { setUpListeners };

//ZADATAK:
//napisati drugi nacin za kreiranje karakteristika u newProduct.characteristic, tako da se pri kliku na dugme "create product" , pokupe sve vrednosti i tek tad dodaju u objekat

//2.zadatak
//registracija i logovanje


7
Javascript / Re: Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:19:45 »

Spoiler for modal JS:


import { correctName } from "./helper.js";
const createProductNameInput = document.getElementById("name");
const createProductPriceInput = document.getElementById("price");
const createProductImageUrlInput = document.getElementById("image");
const createProductDescriptionInput = document.getElementById("description");
const createProductCharacteristicKeyInput = document.getElementById(
  "characteristics-key"
);
const createProductCharacteristicValueInput = document.getElementById(
  "characteristics-value"
);

const articleContainer = document.getElementsByTagName("article")[0];

const newProduct = {
  name: null,
  price: -1,
  image: null,
  description: null,
  characteristics: {},
};

articleContainer.addEventListener("click", function (event) {
  const clickedElement = event.target;
  console.log(clickedElement);

  if (
    clickedElement.matches(".delete-btn") ||
    clickedElement.matches("svg") ||
    clickedElement.matches("path")
  ) {
    const span = clickedElement.closest(".key-value-span");
    const key = span.innerText.split(": ")[0];
    delete newProduct.characteristics[key];
    console.log(newProduct);
    span.remove();
  }
});

createProductNameInput.addEventListener("blur", function (event) {
  const nameInputValue = correctName(event.target.value.trim());
  if (nameInputValue.length > 3) {
    newProduct.name = nameInputValue;

    console.log(newProduct);
  } else {
    console.log("Product name input is empty.");
  }
});

createProductPriceInput.addEventListener("blur", function (event) {
  const priceInputValue = parseFloat(event.target.value);
  console.log(priceInputValue);

  if (priceInputValue > 0 && priceInputValue < 10000) {
    newProduct.price = priceInputValue;
    console.log(newProduct);
  } else {
    console.log("Product price is not in defined range.");
  }
});

createProductImageUrlInput.addEventListener("blur", function (event) {
  const imageInputValue = event.target.value;

  const allowedProtocols = ["www", "http://", "https://"];
  const allowedExtensions = [".png", ".jpg", ".jpeg"];

  let isCorrectProtocol = false;
  let isCorrectExtension = false;

  for (const protocol of allowedProtocols) {
    if (imageInputValue.startsWith(protocol)) {
      isCorrectProtocol = true;
    }
  }

  for (const extension of allowedExtensions) {
    if (imageInputValue.endsWith(extension)) {
      isCorrectExtension = true;
    }
  }

  if (isCorrectExtension && isCorrectProtocol) {
    newProduct.image = imageInputValue;
    console.log(newProduct);
  } else {
    console.log("Url is not valid!");
  }
});

createProductDescriptionInput.addEventListener("blur", function (event) {
  const descriptionInputValue = event.target.value;

  if (descriptionInputValue.length > 20 && descriptionInputValue.length < 200) {
    newProduct.description = descriptionInputValue;
    console.log(newProduct);
  } else {
    console.log("Description is not defined well!");
  }
});

createProductCharacteristicKeyInput.addEventListener("blur", function (event) {
  const keyInputValue = event.target.value.trim();
  handleNewCharacteristics(
    keyInputValue,
    createProductCharacteristicValueInput.value
  );
});

createProductCharacteristicValueInput.addEventListener(
  "blur",
  function (event) {
    const valueInputValue = event.target.value.trim();
    handleNewCharacteristics(
      createProductCharacteristicKeyInput.value,
      valueInputValue
    );
  }
);

function handleNewCharacteristics(key, value) {
  if (key && value) {
    createCharacteristicsElement(key, value);
    newProduct.characteristics[key] = value;
    resetCharacteristics();
    console.log(newProduct);
  }
  function resetCharacteristics() {
    createProductCharacteristicKeyInput.value = "";
    createProductCharacteristicValueInput.value = "";
  }
}

function createCharacteristicsElement(key, value) {
  const spanEl = `
  <span class="key-value-span"
                >${key}: ${value}
                <div class="delete-btn">
                  <svg
                    width="15px"
                    height="15px"
                    viewBox="0 0 24 24"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
                    <g
                      id="SVGRepo_tracerCarrier"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    ></g>
                    <g id="SVGRepo_iconCarrier">
                      <g id="Menu / Close_MD">
                        <path
                          id="Vector"
                          d="M18 18L12 12M12 12L6 6M12 12L18 6M12 12L6 18"
                          stroke="#000000"
                          stroke-width="2"
                          stroke-linecap="round"
                          stroke-linejoin="round"
                        ></path>
                      </g>
                    </g>
                  </svg>
                </div>
              </span>`;

  articleContainer.insertAdjacentHTML("beforeend", spanEl);
}

function resetInputs() {
  createProductNameInput.value = "";
  createProductPriceInput.value = "";
  createProductImageUrlInput.value = "";
  createProductDescriptionInput.value = "";
  createProductCharacteristicKeyInput.value = "";
  createProductCharacteristicValueInput.value = "";
}


8
Javascript / Re: Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:19:08 »

Spoiler for helper JS:


function truncateData(value, limit = 10) {
  if (typeof value === "string") {
    value = value.split(" ");
  }
  if (limit > value.length) {
    limit = value.length;
  }
  const noviNiz = [];
  for (let i = 0; i <= limit - 1; i++) {
    noviNiz.push(value[i]);
  }
  return noviNiz.join(" ") + "...";
}

function debaunce(callback, delay) {
  let timeoutID;
  return function () {
    if (timeoutID) clearTimeout(timeoutID);
    timeoutID = setTimeout(function () {
      callback();
    }, delay);
  };
}

function correctName(text) {
  const arrOfWord = text.toLowerCase().split(" ");
  console.log(arrOfWord);
  return arrOfWord
    .map((word) => word[0].toUpperCase() + word.slice(1))
    .join(" ");
}
export { correctName, truncateData, debaunce };


9
Javascript / Re: Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:18:17 »

Spoiler for style CSS:


* {
  box-sizing: border-box;
}

body {
  margin: 0;
  position: relative;
  min-height: 100vh;
  width: 100%;
  background-color: rgb(245, 255, 253);
  padding-bottom: 5rem;
}
body header {
  padding: 1rem;
  background-color: rgb(2, 130, 100);
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 1rem;
}
body header h1 {
  margin: 0;
  color: white;
}
body main {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 1rem;
}
body main .search-section {
  padding: 1rem;
  margin-bottom: 1rem;
  width: 100%;
  text-align: center;
}
body main .search-section input {
  padding: 0.5rem;
  border-radius: 5px;
  box-shadow: 0 0 10px rgb(2, 130, 100);
  font-size: 1.1rem;
  width: 90%;
}
body .container-section {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.5rem;
}
body .container-section .product {
  border: 1px solid rgb(2, 130, 100);
  border-radius: 10px;
  width: 25%;
  min-width: 350px;
  box-shadow: 0 0 10px rgb(2, 130, 100);
  color: rgb(1, 73, 56);
}
body .container-section .product .product-img {
  width: 100%;
  max-height: 300px;
}
body .container-section .product .product-info {
  padding: 0.5rem;
  display: flex;
  justify-content: center;
  align-items: center;
  align-content: center;
  flex-direction: column;
}
body .container-section .product .product-info .product-name {
  margin: 0;
}
body .container-section .product .product-info .product-price {
  margin: 0.5rem;
}
body .container-section .product .product-info p {
  margin: 0.5rem;
}
body .container-section .product:hover {
  transform: scale(1.03);
}
body footer {
  position: absolute;
  bottom: 0;
  background-color: rgb(2, 130, 100);
  width: 100%;
}
body footer p {
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  text-transform: uppercase;
  font-weight: 600;
}
body .btn-add {
  position: fixed;
  bottom: 5rem;
  right: 3rem;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background-color: rgb(158, 2, 2);
}
body .btn-add div {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
body .btn-add svg {
  width: 70%;
  height: 70%;
}
body .container-modal-body {
  display: flex;
  flex-direction: column;
  align-items: center;
}
body .container-modal-body .errParagraph {
  margin-top: 5px;
  color: red;
  margin: 0;
}
body .container-modal-body #name,
body .container-modal-body #price,
body .container-modal-body #image,
body .container-modal-body #description {
  box-sizing: border-box;
  width: 90%;
  font-size: 1.2rem;
}
body .container-modal-body .characteristics {
  width: 90%;
}
body .container-modal-body .characteristics div {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  justify-content: space-around;
  margin-bottom: 1rem;
}
body .container-modal-body .characteristics div input {
  width: 40%;
}
body .container-modal-body article {
  display: flex;
  gap: 1rem;
  width: 90%;
  margin: 0 auto;
  flex-wrap: wrap;
}
body .container-modal-body article .key-value-span {
  position: relative;
  text-align: center;
  padding: 5px 10px;
  background-color: rgb(255, 0, 0);
  color: white;
  border-radius: 10px;
}
body .container-modal-body article .key-value-span .delete-btn {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: white;
  border: 1px solid black;
  display: flex;
  justify-content: center;
  align-items: center;
  align-items: center;
}/*# sourceMappingURL=style.css.map */







Spoiler for style SCSS:


$font-color: white;
$default-color: rgb(2, 130, 100);

@mixin centar() {
  display: flex;
  justify-content: center;
  align-items: center;
}
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  position: relative;
  min-height: 100vh;
  width: 100%;
  background-color: rgb(245, 255, 253);
  padding-bottom: 5rem;

  header {
    padding: 1rem;
    background-color: $default-color;
    @include centar();
    margin-bottom: 1rem;
    h1 {
      margin: 0;
      color: $font-color;
    }
  }
  main {
    @include centar();
    flex-direction: column;
    padding: 1rem;

    .search-section {
      padding: 1rem;
      margin-bottom: 1rem;
      width: 100%;
      text-align: center;

      input {
        padding: 0.5rem;
        border-radius: 5px;
        box-shadow: 0 0 10px $default-color;
        font-size: 1.1rem;
        width: 90%;
      }
    }
  }
  .container-section {
    width: 100%;
    height: 100%;
    @include centar();
    flex-wrap: wrap;
    gap: 1.5rem;

    .product {
      border: 1px solid $default-color;
      border-radius: 10px;
      width: 25%;
      min-width: 350px;
      box-shadow: 0 0 10px $default-color;
      color: rgb(1, 73, 56);

      .product-img {
        width: 100%;
        max-height: 300px;
      }

      .product-info {
        padding: 0.5rem;
        @include centar();
        align-content: center;
        flex-direction: column;

        .product-name {
          margin: 0;
        }
        .product-price {
          margin: 0.5rem;
        }
        p {
          margin: 0.5rem;
        }
      }
      &:hover {
        transform: scale(1.03);
      }
    }
  }
  footer {
    position: absolute;
    bottom: 0;
    background-color: $default-color;
    width: 100%;

    p {
      color: $font-color;
      @include centar();
      text-transform: uppercase;
      font-weight: 600;
    }
  }

  .btn-add {
    position: fixed;
    bottom: 5rem;
    right: 3rem;
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background-color: rgb(158, 2, 2);

    div {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    svg {
      width: 70%;
      height: 70%;
    }
  }
  .container-modal-body {
    display: flex;
    flex-direction: column;
    align-items: center;

    .errParagraph {
      margin-top: 5px;
      color: red;
      margin: 0;
    }
    #name,
    #price,
    #image,
    #description {
      box-sizing: border-box;
      width: 90%;
      font-size: 1.2rem;
    }
    .characteristics {
      width: 90%;

      div {
        width: 100%;
        @include centar();
        justify-content: space-around;
        margin-bottom: 1rem;
        input {
          width: 40%;
        }
      }
    }
    article {
      display: flex;
      gap: 1rem;
      width: 90%;
      margin: 0 auto;
      flex-wrap: wrap;

      .key-value-span {
        position: relative;
        text-align: center;
        // width: 100px;
        padding: 5px 10px;
        // height: 30px;
        background-color: rgb(255, 0, 0);
        color: white;
        border-radius: 10px;

        .delete-btn {
          position: absolute;
          top: -8px;
          right: -8px;
          width: 20px;
          height: 20px;
          border-radius: 50%;
          background-color: white;
          border: 1px solid black;
          @include centar();
          align-items: center;
        }
      }
    }
  }
}


10
Javascript / Re: Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:17:01 »

Spoiler for main JS:


import { truncateData, debaunce } from "./helper.js";
import { fetchData } from "./api.js";
import { setUpListeners } from "./modal-v1.js";

const containerProducts =
  document.getElementsByClassName("container-section")[0];
const searchInput = document.getElementById("search-input");

const url = "http://localhost:3000/products";

function renderProducts(products) {
  products = filterData(products);
  containerProducts.innerHTML = products
    .map((product) => {
      return `
    <div class="product">
          <img class="product-img" src="${product.image}" alt="${
        product.name
      }" />
          <div class="product-info">
            <h2 class="product-name">${product.name}</h2>
            <h4 class="product-price">${product.price} $</h4>
            <p class="product-description">${truncateData(
              product.description
            )}</p>
            <p class="product-characteristics">${
              product.characteristics
                ? getCharacteristics(product.characteristics)
                : "No additional attributes."
            }</p>
          </div>
        </div>`;
    })
    .join("");

  function getCharacteristics(obj) {
    let template = "";
    for (const [key, value] of Object.entries(obj)) {
      //[['color', 'Cloudy White'], ['capacity', '512 GB']]
      template += `<p>${key}: ${value}</p>`;
    }
    return template;
  }
}

function filterData(data) {
  const searchValue = searchInput.value.toLowerCase().trim();
  const filteredData = data.filter((item) =>
    item.name.toLowerCase().includes(searchValue)
  );
  return filteredData;
}

function searchInputLogic() {
  fetchData(renderProducts, url);
}

document.addEventListener("DOMContentLoaded", function () {
  fetchData(renderProducts, url);
  const debaunceLogic = debaunce(searchInputLogic, 2000);
  searchInput.addEventListener("input", function (event) {
    debaunceLogic();
  });
  setUpListeners();
});


11
Javascript / Re: Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:16:16 »

Spoiler for api JS:


async function fetchData(callback, url) {
  try {
    const response = await fetch(url);
    const result = await response.json();
    callback(result);
  } catch (err) {
    console.log(err.message);
  }
}

async function createProduct(product, url) {
  try {
    const result = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(product),
    });

    const response = await result.json();
    console.log(response);
  } catch (err) {
    console.log(err.message);
  }
}

export { fetchData, createProduct };







Spoiler for products JSON:


{
  "products": [
    {
      "id": "1",
      "name": "Google Pixel 6 Pro",
      "price": 899.99,
      "image": "https://amateurphotographer.com/wp-content/uploads/sites/7/2021/11/pixel-6-pro-rear-P1088727_cropped.jpg?w=435&h=350&crop=1",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Cloudy White",
        "capacity": "128 GB"
      }
    },
    {
      "id": "2",
      "name": "Apple iPhone 12 Mini, 256GB, Blue",
      "price": 699.99,
      "image": "https://www.tehnomedia.rs/image/71882.jpg?tip=webp&tip_slike=0",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": null
    },
    {
      "id": "3",
      "name": "Apple iPhone 12 Pro Max",
      "price": 1099.99,
      "image": "https://www.dxomark.com/wp-content/uploads/medias/post-61584/iphone-12-pro-max-graphite-hero.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Cloudy White",
        "capacity": "512 GB"
      }
    },
    {
      "id": "4",
      "name": "Apple iPhone 11, 64GB",
      "price": 389.99,
      "image": "https://www.winwin.rs/media/catalog/product/cache/aa01455892d233ac3aea63acd876143d/1/1/1131867_000000000001131867-main-webp-580-conversion-media-format_1.webp",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Purple"
      }
    },
    {
      "id": "5",
      "name": "Samsung Galaxy Z Fold2",
      "price": 689.99,
      "image": "https://images.samsung.com/is/image/samsung/p5/au/smartphones/galaxy-z-fold2/buy/002_Z-Fold2-MysticBlack-dynamic-GalleryImage-MO-img80.jpg?$ORIGIN_JPG$?imbypass=true",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Brown"
      }
    },
    {
      "id": "6",
      "name": "Apple AirPods",
      "price": 120,
      "image": "https://www.apple.com/newsroom/images/tile-images/Apple-AirPods-world-most-popular-wireless-headphones_03202019.jpg.landing-big_2x.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "generation": "3rd"
      }
    },
    {
      "id": "7",
      "name": "Apple MacBook Pro 16",
      "price": 1849.99,
      "image": "https://techpoets.com/img-product/428/apple-macbook-pro-16-m1-pro-1tb.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "year": 2019,
        "cpu model": "Intel Core i9",
        "hard disk size": "1 TB"
      }
    },
    {
      "id": "8",
      "name": "Apple Watch Series 8",
      "price": 399.99,
      "image": "https://cdn.mos.cms.futurecdn.net/mfJNvNwN8CjPvLF7H8fSnQ.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "strap Colour": "Elderberry",
        "case Size": "41mm"
      }
    },
    {
      "id": "9",
      "name": "Beats Studio3 Wireless",
      "price": 349.99,
      "image": "https://i5.walmartimages.com/seo/Beats-Studio3-Wireless-Noise-Cancelling-Headphones-with-Apple-W1-Headphone-Chip-Defiant-Black-Red_61f9e0aa-b519-4ad1-95f5-8a8265f388f7.3430280295f34ec3d87cc41fb9d73657.jpeg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Red",
        "reason-to-buy": "High-performance wireless noise cancelling headphones"
      }
    },
    {
      "id": "10",
      "name": "Apple iPad Mini 5th Gen",
      "price": 399.99,
      "image": "https://m.media-amazon.com/images/I/71ZZtEr4kaL.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "capacity": "64 GB",
        "screen size": 7.9
      }
    },
    {
      "id": "11",
      "name": "Apple iPad Air",
      "price": 419.99,
      "image": "https://fdn2.gsmarena.com/vv/pics/apple/apple-ipad-air-1.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "generation": "4th",
        "capacity": "64 GB"
      }
    },
    {
      "id": "11",
      "name": "Apple iPad Air",
      "price": 419.99,
      "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS7VqdDzEX8komd9WwWvjtcpWMWfSyPovrT66RUUTgb_PY_tgdSn-eQTXYyimf07AqHf-Q&usqp=CAU",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "generation": "4th",
        "capacity": "64 GB"
      }
    },
    {
      "id": "8586",
      "name": "Iphone 17",
      "price": 2555,
      "image": "https://mediamobile.rs/image/cache/catalog/Telefoni/Samsung/A%20serija/A17/galaxy-a17-4g-black-283x283.jpg",
      "description": "sbdsnj a;skdjjsakdj skdjfskdjfhdjs skjdskjd",
      "characteristics": {
        "color": "blue"
      }
    },
    {
      "id": "518a",
      "name": "Apple Max Pro Air 64",
      "price": 1025,
      "image": "https://mediamobile.rs/image/cache/catalog/Telefoni/Samsung/A%20serija/A17/galaxy-a17-4g-black-283x283.jpg",
      "description": "lkdsjksjf dsjishfuhs jdnsufsubfudb dishuhaihdi jadbaubuah ajhduahia",
      "characteristics": {}
    },
    {
      "id": "3d39",
      "name": "Apple Max Pro Air 64",
      "price": 2525,
      "image": "https://mediamobile.rs/image/cache/catalog/Telefoni/Samsung/A%20serija/A17/galaxy-a17-4g-black-283x283.jpg",
      "description": "fdfgsdfghgdfghfdsa dfggd asdsd asv ASDSDSSD fgrfg",
      "characteristics": {
        "kjhgfgh": "hhhgh"
      }
    }
  ],
  "users": []
}


12
Javascript / Java Script 17 Dan 28 MODAL
« on: 09 November 2025, 22:14:33 »

Spoiler for HTML index:


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
      crossorigin="anonymous"
    ></script>
    <link rel="stylesheet" href="style.css" />
    <script src="main.js" type="module" defer></script>
  </head>
  <body>
    <header>
      <h1>TechPoint</h1>
    </header>
    <main>
      <section class="search-section">
        <input type="search" id="search-input" placeholder="Product name" />
      </section>

      <section class="container-section"></section>
    </main>
    <footer>
      <p>Made with JSON-server !</p>
    </footer>

    <!-- button -->
    <div class="btn-add" data-bs-toggle="modal" data-bs-target="#modal">
      <div>
        <svg
          width="30px"
          height="30px"
          viewBox="0 0 24 24"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
        >
          <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
          <g
            id="SVGRepo_tracerCarrier"
            stroke-linecap="round"
            stroke-linejoin="round"
          ></g>
          <g id="SVGRepo_iconCarrier">
            <path
              d="M4 12H20M12 4V20"
              stroke="#fff"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            ></path>
          </g>
        </svg>
      </div>
    </div>

    <!-- bootstrap modal -->

    <!-- Modal -->
    <div
      class="modal fade"
      id="modal"
      tabindex="-1"
      aria-labelledby="modalLabel"
      aria-hidden="true"
    >
      <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="modalLabel">Create product</h5>
            <button
              type="button"
              class="btn-close"
              data-bs-dismiss="modal"
              aria-label="Close"
            ></button>
          </div>
          <div class="modal-body container-modal-body">
            <input
              type="text"
              placeholder="Name of product"
              id="name"
              minlength="3"
            />
            <br />
            <input
              type="number"
              min="0"
              max="10000"
              placeholder="Price"
              id="price"
            />
            <br />
            <input type="url" placeholder="Image url" id="image" />
            <br />
            <textarea
              name="description"
              id="description"
              placeholder="Description"
            ></textarea>
            <fieldset class="characteristics">
              <legend>Characteristics</legend>
              <div>
                <input type="text" placeholder="Key" id="characteristics-key" />
                <input
                  type="text"
                  placeholder="Value"
                  id="characteristics-value"
                />
              </div>
            </fieldset>
            <article></article>
          </div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
              data-bs-dismiss="modal"
            >
              Close
            </button>
            <button type="button" class="btn btn-primary create-product-btn">
              Create product
            </button>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>



13
Javascript / Re: Java Script 16 Dan 27
« on: 09 November 2025, 22:11:09 »

Spoiler for modal JS:


const createProductNameInput = document.getElementById("name");
const createProductPriceInput = document.getElementById("price");
const createProductImageUrlInput = document.getElementById("image");
const createProductDescriptionInput = document.getElementById("description");
const createProductCharacteristicKeyInput = document.getElementById(
  "characteristics-key"
);
const createProductCharacteristicValueInput = document.getElementById(
  "characteristics-value"
);

const newProduct = {
  name: null,
  price: -1,
  image: null,
  description: null,
  characteristics: {},
};

createProductNameInput.addEventListener("blur", function (event) {
  const nameInputValue = event.target.value.trim();
  if (nameInputValue.length > 3) {
    newProduct.name = nameInputValue;
    console.log(newProduct);
  } else {
    console.log("Product name input is empty.");
  }
});

createProductPriceInput.addEventListener("blur", function (event) {
  const priceInputValue = parseFloat(event.target.value);
  console.log(priceInputValue);

  if (priceInputValue > 0 && priceInputValue < 10000) {
    newProduct.price = priceInputValue;
    console.log(newProduct);
  } else {
    console.log("Product price is not in defined range.");
  }
});

createProductImageUrlInput.addEventListener("blur", function (event) {
  const imageInputValue = event.target.value;
  console.log(imageInputValue);

  if (
    (imageInputValue.startsWith("www") ||
      imageInputValue.startsWith("http://") ||
      imageInputValue.startsWith("https://")) &&
    (imageInputValue.endsWith(".jpg") ||
      imageInputValue.endsWith(".jpeg") ||
      imageInputValue.endsWith(".png"))
  ) {
    newProduct.image = imageInputValue;
    console.log(newProduct);
  } else {
    console.log("Image url doesn't have right format!");
  }
});


14
Javascript / Re: Java Script 16 Dan 27
« on: 09 November 2025, 22:10:31 »

Spoiler for api JS:


export async function fetchData(callback) {
  try {
    const response = await fetch("http://localhost:3000/products");
    const result = await response.json();
    callback(result);
  } catch (err) {
    console.log(err.message);
  }
}


15
Javascript / Re: Java Script 16 Dan 27
« on: 09 November 2025, 22:08:43 »
Spoiler for products JSON:


{
  "products": [
    {
      "id": "1",
      "name": "Google Pixel 6 Pro",
      "price": 899.99,
      "image": "https://amateurphotographer.com/wp-content/uploads/sites/7/2021/11/pixel-6-pro-rear-P1088727_cropped.jpg?w=435&h=350&crop=1",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Cloudy White",
        "capacity": "128 GB"
      }
    },
    {
      "id": "2",
      "name": "Apple iPhone 12 Mini, 256GB, Blue",
      "price": 699.99,
      "image": "https://www.tehnomedia.rs/image/71882.jpg?tip=webp&tip_slike=0",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": null
    },
    {
      "id": "3",
      "name": "Apple iPhone 12 Pro Max",
      "price": 1099.99,
      "image": "https://www.dxomark.com/wp-content/uploads/medias/post-61584/iphone-12-pro-max-graphite-hero.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Cloudy White",
        "capacity": "512 GB"
      }
    },
    {
      "id": "4",
      "name": "Apple iPhone 11, 64GB",
      "price": 389.99,
      "image": "https://www.winwin.rs/media/catalog/product/cache/aa01455892d233ac3aea63acd876143d/1/1/1131867_000000000001131867-main-webp-580-conversion-media-format_1.webp",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Purple"
      }
    },
    {
      "id": "5",
      "name": "Samsung Galaxy Z Fold2",
      "price": 689.99,
      "image": "https://images.samsung.com/is/image/samsung/p5/au/smartphones/galaxy-z-fold2/buy/002_Z-Fold2-MysticBlack-dynamic-GalleryImage-MO-img80.jpg?$ORIGIN_JPG$?imbypass=true",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Brown"
      }
    },
    {
      "id": "6",
      "name": "Apple AirPods",
      "price": 120,
      "image": "https://www.apple.com/newsroom/images/tile-images/Apple-AirPods-world-most-popular-wireless-headphones_03202019.jpg.landing-big_2x.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "generation": "3rd"
      }
    },
    {
      "id": "7",
      "name": "Apple MacBook Pro 16",
      "price": 1849.99,
      "image": "https://techpoets.com/img-product/428/apple-macbook-pro-16-m1-pro-1tb.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "year": 2019,
        "cpu model": "Intel Core i9",
        "hard disk size": "1 TB"
      }
    },
    {
      "id": "8",
      "name": "Apple Watch Series 8",
      "price": 399.99,
      "image": "https://cdn.mos.cms.futurecdn.net/mfJNvNwN8CjPvLF7H8fSnQ.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "strap Colour": "Elderberry",
        "case Size": "41mm"
      }
    },
    {
      "id": "9",
      "name": "Beats Studio3 Wireless",
      "price": 349.99,
      "image": "https://i5.walmartimages.com/seo/Beats-Studio3-Wireless-Noise-Cancelling-Headphones-with-Apple-W1-Headphone-Chip-Defiant-Black-Red_61f9e0aa-b519-4ad1-95f5-8a8265f388f7.3430280295f34ec3d87cc41fb9d73657.jpeg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "color": "Red",
        "reason-to-buy": "High-performance wireless noise cancelling headphones"
      }
    },
    {
      "id": "10",
      "name": "Apple iPad Mini 5th Gen",
      "price": 399.99,
      "image": "https://m.media-amazon.com/images/I/71ZZtEr4kaL.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "capacity": "64 GB",
        "screen size": 7.9
      }
    },
    {
      "id": "11",
      "name": "Apple iPad Air",
      "price": 419.99,
      "image": "https://fdn2.gsmarena.com/vv/pics/apple/apple-ipad-air-1.jpg",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "generation": "4th",
        "capacity": "64 GB"
      }
    },
    {
      "id": "11",
      "name": "Apple iPad Air",
      "price": 419.99,
      "image": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS7VqdDzEX8komd9WwWvjtcpWMWfSyPovrT66RUUTgb_PY_tgdSn-eQTXYyimf07AqHf-Q&usqp=CAU",
      "description": "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Perferendis commodi laborum rem. Temporibus sequi sunt accusantium reprehenderit doloremque accusamus error consectetur? Consectetur voluptatibus sed nihil repellendus explicabo consequatur nobis vel?",
      "characteristics": {
        "generation": "4th",
        "capacity": "64 GB"
      }
    }
  ]
}



Pages: [1] 2 3 ... 60

SimplePortal 2.3.7 © 2008-2026, SimplePortal