İs C sufficient for learning for beginners

I began learning programming since this September and a lot of people ı saw online recommending C for learning as its closer to hardware and learning it would make learning high level languages much easier. Should ı give a shot on C?

Some people also recommended Javascript and Python as they’re high on demand in the job market.

React Aria FileTrigger onSelect not firing on first file selection in Chrome iOS, subsequent selections trigger cancel event

I’m encountering an inconsistent event behavior with the FileTrigger component from @react-aria/components in a React application. The issue is observed specifically in ​​Chrome on iOS (version 140)​​ based on user analytics, and is difficult to reproduce.

Problem Description​​

After a user selects an image file:

​​First selection​​: The onSelect event handler does not fire at all.

​​Second and subsequent selections​​: The file dialog opens, but immediately after a file is selected, a cancel event is triggered follow by the button click event. The selected files are not processed, which no triggered the onSelect event.

Environment​​

  • ​​React​​: 18.x

  • Library​​: @react-aria/components(1.2.1)

  • ​​Browser & Platform​​: Chrome 140, iOS (iPhone/iPad)
    ​​
    ​​Simplified Code Example​​
    Here is a simplified version of the component focusing on the event handling:

import React, { useEffect, useRef } from 'react';
import { FileTrigger } from 'react-aria-components';

const UploadComponent = ({ onFileSelected }) => {
  const uploadInputRef = useRef(null);

  // This handler does not fired at all
  const handleFileSelect = (fileList) => {
    console.log('onSelect fired', fileList);
    if (fileList) {
      onFileSelected(Array.from(fileList));
    }
  };

  // This event fires immediately on subsequent selections
  const handleCancel = () => {
    console.log('Cancel event fired from user selection');
  };

  useEffect(() => {
    const currentInput = uploadInputRef.current;

    // this code will run after second upload
    currentInput?.addEventListener('cancel', handleCancel);

    return () => {
      currentInput?.removeEventListener('cancel', handleCancel);
    };
  }, []);

  return (
    <FileTrigger
      // didn't triggered 
      onSelect={handleFileSelect}
      acceptedFileTypes={['image/*', 'image/heic', 'image/heif']}
      allowsMultiple={true}
      ref={uploadInputRef}
    >
      {/* we got the click logs from this button */}
      <button onClick={() => {console.log('clicked');}}>Select Images</button>
    </FileTrigger>
  );
};

export default UploadComponent;

onSelect can be triggered, and got the file from user.

How to remove header ‘Host’ using supertest

I have condiiton in my http server that check if req.headers["host"] is undefined or not. I am using supertest and mocha to send GET request. I tried to use unset("Host"), but supertest still send header “Host”

http server:

const http_server = http.createServer(function (req, res) {
  console.log("http", req.method, req.url, req.headers);

  const url_path = url.parse(req.url, true).pathname;
  const query = url.parse(req.url, true).query;

  if (req.method === "GET" && req.headers["host"] !== undefined) {
    // force create session
    const session = getSession(req);
    console.log(`HOST === ${req.headers["host"]}`)

    res.removeHeader("Date");
    res.removeHeader("Transfer-Encoding");

    res.writeHead(302, {
      Location: getNewLocation(req.headers["host"], url_path, query),
      Connection: "close",
    });

    res.end();
    return;
  }

  handler(req, res);
});

test

  it("should return index.html", (done) => {
    request(http_server)
      .get("/")
      .unset("Host")
      .expect(200)
      .expect("Connection", "close")
      .expect("Etag", '"167-110-5f0633df"')
      .expect("Last-Modified", "Wed, 08 Jul 2020 21:00:15 GMT")
      .expect("Date", date_regex)
      .expect("Cache-Control", "no-cache")
      .expect("Expires", "0")
      .expect("Content-Type", "text/html")
      .expect("Content-Length", `<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="refresh" content="0; URL=/webpages/login.html" />
</head>
</html>
`.length)
      .expect(res => assert.strictEqual(res.text, `<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="refresh" content="0; URL=/webpages/login.html" />
</head>
</html>
`))
      .end(done)
  })

I am trying to remove header “Host”, so code would not fall into condition where it sends 302 status code

how do i create a sort function on a table?

The page is here for reference: https://songscape-helgasonpete.replit.app/artist/clarencewilliams.html

I have two tables that are activated by hitting the two buttons. But I want to be able to sort the information within those two tables. So under the “songs as writer” button – I want to be able to sort the information under the “Song” “Writer” “Originally By” headers alphabetically and information under the “Original Release” header by date.

Likewise under the “Songs as Performer” button – I want to be able to sort the information under the “Title” and “Performer” headers alphabetically, the information under the “Release Date” by date and the information under the “Streamcount” header numerically.

I tried creating two tables of differing data similar to the table I did on this link here: https://songscape-helgasonpete.replit.app/artist/bessiesmith.html. The table would be button activated.

I was able to get the buttons work, but I was unable to sort the table once I clicked on it. Here is the code for reference:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Clarence Williams</title>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <style>
        th {
            color: white;
        }
    </style>


  </head>
  <body>

<h1>Clarence Williams</h1>
<img src="/images/clarencewilliams.jpg"><br>
Born: October 8, 1898<br>
Died: November 6, 1965<br>
Rankings: <br>
<a href="https://songscape-helgasonpete.replit.app/statistics/writers.html">1st</a> most streamed writer<br>
<a href="https://songscape-helgasonpete.replit.app/statistics/performers.html">2nd</a> most streamed performer<br>
    <button type="button" onclick="updateDisplay('demo')">Songs As Writer</button>
    <button type="button" onclick="updateDisplay('demo2')">Songs As Performer</button>


    <table id="demo" style="display:none" class="specialTable table table-striped">
      <tr class="bg-info">
      <th id="songCol">Song</th>
      <th id="writerCol">Writer</th>
      <th id="originalperformerCol">Originally By</th>
      <th id="releaseCol">Original Release</th>
       </tr>

      <tr>
      <td><a href="https://songscape-helgasonpete.replit.app/work/gulfcoastblues.html">Gulf Coast Blues</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/clarencewilliams.html">Clarence Williams</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/bessiesmith+clarencewilliams.html">Bessie Smith - Clarence Williams at the Piano</a></td>
      <td>May 1923</td>
       </tr>

      <tr>
      <td><a href="https://songscape-helgasonpete.replit.app/work/babywontyoupleasecomehome.html">Baby, Won't You Please Come Home</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/charleswarfield.html">Charles Warfield</a> <a href="https://songscape-helgasonpete.replit.app/artist/clarencewilliams.html">Clarence Williams</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/bessiesmith+clarencewilliams.html">Bessie Smith - Clarence Williams at the Piano</a></td>
      <td>June 1923</td>
       </tr>

      </table>

      <table id="demo2" style="display:none" class="specialTable table table-striped">
      <tr class="bg-info">
      <th id="titleCol">Title</th>
      <th id="performerCol">Performer</th>
      <th id="releasetwoCol">Release Date</th>
      <th id="streamCol">Stream Count</th>
       </tr>

      <tr>
      <td><a href="https://songscape-helgasonpete.replit.app/performance/downheartedblues.html">Down Hearted Blues</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/bessiesmith+clarencewilliams.html">Bessie Smith - Clarence Williams at the Piano</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/statistics/1923releases.html">May 1923</a></td>
      <td>1294462</td>
       </tr>

      <tr>
      <td><a href="https://songscape-helgasonpete.replit.app/performance/gulfcoastblues.html">Gulf Coast Blues</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/bessiesmith+clarencewilliams.html">Bessie Smith - Clarence Williams at the Piano</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/statistics/1923releases.html">May 1923</a></td>
      <td>89052</td>
       </tr>

      <tr>
      <td><a href="https://songscape-helgasonpete.replit.app/performance/babywontyoupleasecomehome.html">Baby Won't You Please Come Home Blues</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/bessiesmith+clarencewilliams.html">Bessie Smith - Clarence Williams at the Piano</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/statistics/1923releases.html">June 1923</a></td>
      <td>1832242</td>
       </tr>

      <tr>
      <td><a href="https://songscape-helgasonpete.replit.app/performance/ohdaddyblues.html">Oh Daddy Blues</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/artist/bessiesmith+clarencewilliams.html">Bessie Smith - Clarence Williams at the Piano</a></td>
      <td><a href="https://songscape-helgasonpete.replit.app/statistics/1923releases.html">June 1923</a></td>
      <td>37590</td>
       </tr>

      </table>




      <script>

      // Create a function to update your display area
      function updateDisplay(tableId) {

        // The function receives the id of the table to show (give each table a unique id, but the same class)

        // Set the display value of all tables with the target class to none
        document.querySelectorAll(".specialTable").forEach(el => {
          el.style.display = "none";
        });

        // Set the display value of the table with the target id to block
        document.getElementById(tableId).style.display = "block";

        $('#songCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Song";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#writerCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Writer";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#originalperformerCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Originally By";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#releaseCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Original Release";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#titleCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Title";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#performerCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Performer";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#releasetwoCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Release Date";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });

        $('#streamCol').on('click', async function () {
            let newSortOrder;
            sortKey = "Stream Count";
            if (lastSortOrder != "asc") {
                newSortOrder = "asc";
            } else {
                newSortOrder = "desc";
            }

            myArray = await performSort(myArray, sortKey, newSortOrder);
            buildtable(myArray);
        });
      }

      </script>

      </body>


</html>

Loader in conditional statements is not showing after navigation or making new API calls

I had an API call for fetch products for wishlist and cart however since both share same UI I decided to do in single page component and at first refresh the loader is showing but after I navigation loader is not showing and Header and Product is different components.

Loader is not showing when I navigation between components as it took 0.1s for get data and I can’t see loader when I navigation through it

"use client";

import { useState, useEffect } from "react";
import { useParams } from "next/navigation";
import axios from "axios";
import Image from "next/image";
import { CircularProgress } from "@mui/material";

export default function ViewResouce() {
  const { resource } = useParams();
  const [isCart, setIsCart] = useState(false);
  const [resourcesData, setResourcesData] = useState<any[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [dataFind, setDataFind] = useState(false);

  useEffect(() => {
    if (!resource) {
      return;
    }

    if (resource === "cart") {
      setIsCart(true);
      return;
    }

    setIsCart(false);
  }, [resource]);

  useEffect(() => {
    if (!resource) {
      setIsLoading(false);
      setDataFind(false);
      setResourcesData([]);
      return;
    }

    setIsLoading(true);
    setDataFind(false);
    setResourcesData([]);

    const abortController = new AbortController();

    async function getResource() {
      try {
        const res = await axios.get(
          `/api/client/manage?resource=${resource}`,
          { signal: abortController.signal }
        );
        setResourcesData(res.data.data || []);
      } catch (e) {
        setResourcesData([]);
      } finally {
        setIsLoading(false);
        setDataFind(true);
      }
    }

    getResource();

    return () => {
      abortController.abort();
    };
  }, [resource]);

  if (isLoading && !dataFind) {
    return (
      <div
        className="d-flex justify-content-center align-items-center"
        style={{ height: "50vh" }}
      >
        <CircularProgress size={80} />
      </div>
    );
  }

  if (dataFind && !isLoading && resourcesData.length <= 0) {
    return (
      <div className="no-product-card">
        {isCart && (
          <Image
            src="/assests/no-items-cart.png"
            alt="no-products"
            width={400}
            height={400}
            style={{
              maxWidth: "100%",
              width: "auto",
              objectFit: "cover",
            }}
            loading="lazy"
            unoptimized
          />
        )}
        {!isCart && (
          <Image
            src="/assests/no-items-wishlist.png"
            alt="no-products"
            width={400}
            height={400}
            style={{
              maxWidth: "100%",
              width: "auto",
              objectFit: "cover",
            }}
            loading="lazy"
            unoptimized
          />
        )}
        <h6>No {isCart ? "Cart" : "Wishlist"} Items Found</h6>
      </div>
    );
  }

  if (dataFind && !isLoading && resourcesData.length > 0 && isCart) {
    return (
      <div className="main-resource-container">
        <h6>Your Cart Items</h6>
      </div>
    );
  }

  if (dataFind && !isLoading && resourcesData.length > 0 && !isCart) {
    return (
      <div className="main-resource-container">
        <h6>Your Wishlist Items</h6>
      </div>
    );
  }

  return null;
}

Loader in conditional statements is not showing after I navigation or new API calls in nextjs

I had an API call for fetch products for wishlist and cart however since both share same UI I decided to do in single page component and at first refresh the loader is showing but after I navigation loader is not showing and Header and Product is different components.

"use client";

import { useState, useEffect } from "react";
import { useParams } from "next/navigation";
import axios from "axios";
import Image from "next/image";
import { CircularProgress } from "@mui/material";

export default function ViewResouce() {
  const { resource } = useParams();
  const [isCart, setIsCart] = useState(false);
  const [resourcesData, setResourcesData] = useState<any[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [dataFind, setDataFind] = useState(false);

  useEffect(() => {
    if (!resource) {
      return;
    }

    if (resource === "cart") {
      setIsCart(true);
      return;
    }

    setIsCart(false);
  }, [resource]);

  useEffect(() => {
    if (!resource) {
      setIsLoading(false);
      setDataFind(false);
      setResourcesData([]);
      return;
    }

    setIsLoading(true);
    setDataFind(false);
    setResourcesData([]);

    const abortController = new AbortController();

    async function getResource() {
      try {
        const res = await axios.get(
          `/api/client/manage?resource=${resource}`,
          { signal: abortController.signal }
        );
        setResourcesData(res.data.data || []);
      } catch (e) {
        setResourcesData([]);
      } finally {
        setIsLoading(false);
        setDataFind(true);
      }
    }

    getResource();

    return () => {
      abortController.abort();
    };
  }, [resource]);

  if (isLoading && !dataFind) {
    return (
      <div
        className="d-flex justify-content-center align-items-center"
        style={{ height: "50vh" }}
      >
        <CircularProgress size={80} />
      </div>
    );
  }

  if (dataFind && !isLoading && resourcesData.length <= 0) {
    return (
      <div className="no-product-card">
        {isCart && (
          <Image
            src="/assests/no-items-cart.png"
            alt="no-products"
            width={400}
            height={400}
            style={{
              maxWidth: "100%",
              width: "auto",
              objectFit: "cover",
            }}
            loading="lazy"
            unoptimized
          />
        )}
        {!isCart && (
          <Image
            src="/assests/no-items-wishlist.png"
            alt="no-products"
            width={400}
            height={400}
            style={{
              maxWidth: "100%",
              width: "auto",
              objectFit: "cover",
            }}
            loading="lazy"
            unoptimized
          />
        )}
        <h6>No {isCart ? "Cart" : "Wishlist"} Items Found</h6>
      </div>
    );
  }

  if (dataFind && !isLoading && resourcesData.length > 0 && isCart) {
    return (
      <div className="main-resource-container">
        <h6>Your Cart Items</h6>
      </div>
    );
  }

  if (dataFind && !isLoading && resourcesData.length > 0 && !isCart) {
    return (
      <div className="main-resource-container">
        <h6>Your Wishlist Items</h6>
      </div>
    );
  }

  return null;
}

Thymeleaf page not rendering correctly on iOS when using LIFF SDK

Now I am having a problem:
I am building a chat application, when from the LINE app click on the start chat button, it will transfer the user to the chat website dedicated to them. Currently when processing on Android, everything is still displayed normally, but when I build on iOS, nothing is displayed.

Regarding the technology used, I use spring boot, thymeleaf combined with jQuery + LIFF SDK.

The process when init the screen I am processing: When init the screen for the first time, the backend will check the isInit variable passed is null, then it will return the html of that screen.
My Server:

  public String init(
      @RequestParam(value = "liffChannelId") String liffChannelId,
      @RequestParam(value = "messageChannelId") String messageChannelId,
      @RequestParam(value = "isInit", required = false) String isInit,
      @RequestParam(value = "idToken", required = false) String idToken,
      HttpServletRequest request, Model model) {
    if (Objects.isNull(isInit)) {
      return "s2013_chat";
    }

    ChatForm form = chatHelper.init(liffChannelId, messageChannelId, idToken, page, request);

    return "s2013_chat";
  }

And in my js:

$(document).ready(function () {
  const urlParams = new URLSearchParams(window.location.search);
  const isInit = urlParams.get("isInit");
  if (!isInit) {
    initLiffApp();
  }
});

function initLiffApp() {
  const messageChannelId = new URLSearchParams(window.location.search).get("messageChannelId");
  if (!messageChannelId) {
    alert("MessageChannelId is missing");
    return;
  }

  const liffChannelId = new URLSearchParams(window.location.search).get("liffChannelId");
  if (!liffChannelId) {
    alert("LiffChannelId is missing");
    return;
  }

  const liffId = new URLSearchParams(window.location.search).get("liffId");
  if (!liffId) {
    alert("LiffId is missing");
    return;
  }

  liff
    .init({
      liffId: liffId
    })
    .then(() => {
      const idToken = liff.getIDToken();
      if (!idToken) {
        alert("Failed to get ID Token");
        return;
      }
      sendToServer(liffChannelId, messageChannelId, idToken);
    })
    .catch(err => {
      console.error("LIFF init error", err);
    });
}

function sendToServer(liffChannelId, messageChannelId, idToken) {
  const redirectUrl = `/counseling/chat/client?liffChannelId=${encodeURIComponent(liffChannelId)}&messageChannelId=${encodeURIComponent(messageChannelId)}&isInit=1&idToken=${encodeURIComponent(idToken)}`;
  window.location.href = redirectUrl;
}

When returning for the first time, in js make a call to the liff server to get idToken and at this time will call back to the server 1 more time with isInit is true. At this time the backend will start processing. However, when building on iOS, I noticed that when init for the first time, it returns the screen UI without displaying anything (I think it’s due to the processing when isInit is null, it returns without calling liff anymore).

I tried commenting out the isInit variable check, and now the UI is displayed but does not receive any css and js events.

//if (Objects.isNull(isInit)) {
//   return "s2013_chat";
//}

I used Web Inspector on Safari browser to check and saw that the css and js files were loaded successfully, but the console log is reporting an error as shown.

enter image description here
enter image description here
enter image description here

Please help me with this problem, I have been trying to solve it for 3 days but still don’t know the reason why?

displaying and filtering images with a click event vanillajs

I want to dynamically display images and list items. I then want to filter the images based on the list item(genre) that is clicked. There are 2 images per list item. The list items are displayed in the middle of the page with one image on either side of the page.
I’ve created this function that I know is wrong but I’m not exactly sure where I’m going wrong. I don’t necessarily need the answer but let me know if I’m going in the right direction and if not, what errors I am making.

HTML

    <div class="content-wrapper-2">
      <div class="image-container-1"></div>
      <ul id="genre-list"></ul>
      <div class="image-container-2"></div>
    </div>

JS

const imageContainer1 = document.querySelectorAll('.image-container-1');
const imageContainer2 = document.querySelectorAll('.image-container-2');
const genreList = document.getElementById('genre-list');
const albums = [
  {
    id: 1,
    genre: 'Rock',
    image1: '/images/album-covers/jimihindrix-areyouexperienced.jpg',
    image2: '/images/album-covers/thedoors.jpg',
  },
  {
    id: 2,
    genre: 'Jazz',
    image1: '/images/album-covers/somethinelse.jpg',
    image2: '/images/album-covers/MilesDavis-BitchesBrew.jpg',
  },
  {
    id: 3,
    genre: 'Hiphop',
    image1: '/images/album-covers/mfdoom-mmfood.jpg',
    image2: '/images/album-covers/nas-illmatic.jpg',
  },
  {
    id: 4,
    genre: 'Soul',
    image1: '/images/album-covers/aliciakeys-diary.jpeg',
    image2: '/images/album-covers/ettajames-tellmama.jpg',
  },
  {
    id: 5,
    genre: 'Electronic',
    image1: '/images/album-covers/burial-tunes.jpg',
    image2: '/images/album-covers/björk-homogenic.jpg',
  },
  {
    id: 6,
    genre: 'Classic',
    image1: '/images/album-covers/sparks-kimonomyhouse.jpg',
    image2: '/images/album-covers/chakakhan-rufus.jpg',
  },

  {
    id: 7,
    genre: 'Pop',
    image1: '/images/album-covers/beatles-sgtpeppers.jpg',
    image2: '/images/album-covers/prince-purplerain.png.webp',
  },
];

const handleClick = (e) => {
  const clickedElement = e.target.id;
  albums.map((album) => {
    genreList.innerHTML = `<li id=${album.genre}>${album.genre}</li>`;
  });
  document.getElementById(`${albums.genre}`).addEventListener('click', () => {
    albums.filter((p) => {
      if (p.name === clickedElement) {
        imageContainer1.innerHTML = `<img src=${p.image1}/>`;
        imageContainer2.innerHTML = `<img src=${p.image2}/>`;
        
      }
    });
  });
};

document.addEventListener('DOMContentLoaded', (e) => {
  handleClick(e);
});

To Do List JS project Saving Lists logic [closed]

I need help with my javaScript file in my To Do List project, I thought i could handle it but there is too much to think about in this type of project and i am overwhelmed, if someone could help with the list saving logic then reach me out and I will send the details of what I would like to implement.
project repo: https://github.com/Dudek10/To-Do-List-Advanced-Project

I have tried to implement the logic of renaming each list but it got too complicated and I don’t want to mess things up even more, I will additionaly send the JS file:

let tasks = [];

// Constants LocalStorage keys
const TASKS_KEY = 'tasks';
const CONTAINER_KEY = 'containerOpenState';
const TASK_INPUT_KEY = 'taskInputDraft';
const SAVED_LISTS_KEY = 'SavedLists';
const SAVE_LIMIT = 5;

// Constants for functions like 'addTask()' etc. 
const tasksDiv = document.getElementById("tasks");
const input = document.getElementById("TaskInput");
const addTaskButton = document.getElementById("AddTaskButton");

//main DOM content
document.addEventListener('DOMContentLoaded', () => {
  
  // the list cotainer logic
  const OpenListBtn = document.getElementById("OpenList");
  const DeleteAllTaskBtn = document.getElementById("TaskDelete");
  const NameForm = document.querySelector(".name-form");
  const Container = document.querySelector(".container");
  const SaveBtn = document.querySelector(".save-button");
  const IconClose = document.querySelector(".icon-close");

  // Checks whether container is open
  const savedState = localStorage.getItem(CONTAINER_KEY);
  if (Container && NameForm && SaveBtn) {
    if (savedState === 'open') {
      Container.classList.add('visible');
      NameForm.classList.add('visible');
      SaveBtn.classList.add('visible');
    } else {
      Container.classList.remove('visible');
      NameForm.classList.remove('visible');
      SaveBtn.classList.remove('visible');
    }
  }

  // Opens the list and sets the state to local storage
  if (OpenListBtn && Container && NameForm && SaveBtn) {
    OpenListBtn.addEventListener('click', () => {
      Container.classList.add('visible');
      NameForm.classList.add('visible');
      SaveBtn.classList.add('visible');
      localStorage.setItem(CONTAINER_KEY, 'open');

    });
  }
  if (IconClose && Container && NameForm && SaveBtn) {
    IconClose.addEventListener('click', () => {
      Container.classList.remove('visible');
      NameForm.classList.remove('visible');
      SaveBtn.classList.remove('visible');
      localStorage.setItem(CONTAINER_KEY, 'closed');
    });
  }
  
  // draft input retrieve
  const draft = localStorage.getItem(TASK_INPUT_KEY);
  if (draft !== null) input.value = draft;
  
  input.addEventListener('input', () => {
    localStorage.setItem(TASK_INPUT_KEY, input.value);
  });

  // Load tasks on startup
  loadTasks();

  renderSavedListsDropdown();

  // Saved list logic
  const SavedListBtn = document.getElementById("SavedLists");
  const SavedListsDropdown = document.querySelector('.saved-lists-dropdown');
  const ListSavingBtn = document.querySelector('.save-button');

  // Toggle dropdown visibility when clicking SavedLists button
  SavedListBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    SavedListsDropdown.classList.toggle('show');
  });

  // Save the current tasks under the typed name
  ListSavingBtn.addEventListener('click', () => {
        //first we declare the things we want to save

        const nameInput = document.getElementById("NameBtn");
        const name = (nameInput?.value || '').trim();
        if (!name) return; // don’t save if no name
        if (tasks.length === 0) return; 

        //makes a map of all the elements
        const map = getSavedListsMap();

        //sets a variable for the names and then checks their number
        const existingNames = Object.keys(map);
        if (!map[name] && existingNames.length >= SAVE_LIMIT) {
            
            return;
        }
        
        map[name] = [...tasks];  // store a copy of tasks under given name 
        localStorage.setItem(SAVED_LISTS_KEY, JSON.stringify(map));
        
        //render the saved lists
        renderSavedListsDropdown();
        SavedListsDropdown.classList.add('show');
  })

  // Load a saved list when clicking its button in the dropdown
  SavedListsDropdown.addEventListener('click', (e) => {
        const btn = e.target.closest('.saved-list-button');
        if (!btn) return;
        const name = btn.dataset.name;
        const map = getSavedListsMap();

        // Show the list and fill the name field
        document.getElementById('NameBtn').value = name;
        tasks = map[name] ? [...map[name]] : [];

        Container.classList.add('visible');
        NameForm.classList.add('visible');
        SaveBtn.classList.add('visible');

        renderTasks(); // render loaded tasks
  });

  // Close dropdown when clicking outside
  document.addEventListener('click', (e) => {
    if (!SavedListBtn.contains(e.target) && !SavedListsDropdown.contains(e.target)) {
      SavedListsDropdown.classList.remove('show');
    }
  });

  // mobile toogle button for nav menu
  const toggleBtn = document.querySelector('.ToggleBtn');
  const dropdownMenu = document.querySelector('.DropdownMenu');
  const toggleBtnIcon = toggleBtn?.querySelector('i');
  let isOpen = false;
  
  // on button click change its icon to appropriate one
  if (toggleBtn && dropdownMenu && toggleBtnIcon) {
    toggleBtn.addEventListener('click', (e) => {
      e.stopPropagation();

      if (!isOpen) {
        dropdownMenu.classList.add('show');
        dropdownMenu.classList.remove('hide');
        toggleBtnIcon.className = 'fa-solid fa-xmark';
      } else {
        dropdownMenu.classList.add('hide');
        dropdownMenu.classList.remove('show');
        toggleBtnIcon.className = 'fa-solid fa-bars';
      }
      isOpen = !isOpen;
    });
  }
  

  // Delete all tasks
  if (DeleteAllTaskBtn) {
  DeleteAllTaskBtn.addEventListener('click', () => {
    const items = tasksDiv.querySelectorAll('.task');
    if (items.length === 0) return;

    let remaining = items.length;

    items.forEach((el, i) => {
      // set delay for each item
      el.style.transitionDelay = `${i * 0.3}s`;

      el.classList.add('erasing');
      el.addEventListener('transitionend', () => {
        remaining--;
        if (remaining === 0) {
          tasks.length = 0;
          renderTasks();
          saveTasks();
        }
      }, { once: true }); // the transition listener will only run once (the css have two transitions so it would double the iteration number)
    });
  });
  
}

  // Add task event
  addTaskButton.addEventListener('click', addTask);

});

//helper for saved lists
function getSavedListsMap() {
    try {
        return JSON.parse(localStorage.getItem(SAVED_LISTS_KEY)) || {};
    } catch {
        return {};
    }

}


function renderSavedListsDropdown() {
    const SavedListsDropdown = document.querySelector('.saved-lists-dropdown');
    const map = getSavedListsMap();
    SavedListsDropdown.innerHTML = ''; //clears the template buttons 
    Object.keys(map).forEach(name => {
        const btn = document.createElement('button');
        btn.className = 'saved-list-button';
        btn.textContent = name;
        btn.dataset.name = name;
        SavedListsDropdown.appendChild(btn);
    })
}

//tasks persistence
function loadTasks() {
    const oldTasks = localStorage.getItem(TASKS_KEY);
    if (oldTasks) {
        tasks = JSON.parse(oldTasks);
        renderTasks();
    }
}

function saveTasks() {
    localStorage.setItem(TASKS_KEY, JSON.stringify(tasks));
}

// tasks allingment and style
function renderTasks() {
    tasksDiv.innerHTML = "";
    tasks.forEach((task, idx) => {
        const div = document.createElement('div');
        div.classList.add('task');
        div.style.marginBottom = '10px';

        const text = document.createElement('p');
        text.textContent = task;
        Object.assign(text.style, {
            display: 'inline',
            marginRight: '10px',
            fontWeight: 'bold',
            fontSize: '1.3rem'
        });

        const button = document.createElement('button');
        button.innerHTML = '<ion-icon name="trash-outline" style="font-size: 1rem; color: white;"></ion-icon>';
        Object.assign(button.style, {
            backgroundColor: '#2F1E2E',
            color: '#ffffff',
            border: 'none',
            fontSize: '1.5rem',
            cursor: 'pointer',
            padding: '6px 8px',
            borderRadius: '8px',
            display: 'inline-flex',
            alignItems: 'center',
            justifyContent: 'center',
            height: '1.9rem'
        });

        button.addEventListener('mouseenter', () => button.style.backgroundColor = '#3C2E3B');
        button.addEventListener('mouseleave', () => button.style.backgroundColor = '#2F1E2E');
        
        // Trigger CSS animation and remove the task after the transition end
        button.onclick = () => {
            div.classList.add('erasing');
            div.addEventListener('transitionend', () => {
            removeTask(idx);
      }, { once: true }); // same case as for the delete all tasks button
    };

        div.appendChild(text);
        div.appendChild(button);
        tasksDiv.appendChild(div);
    });
}

function addTask() {
    const value = input.value.trim();
    const OriginalPlaceholder = input.placeholder;

    // Helper: show placeholder error messages briefly
    const ShowPlaceholderWarning = (msg) => {
        input.value = "";
        input.placeholder = msg;

        // clear previous timer
        if (input._phTimer) clearTimeout(input._phTimer);

        // Restore original placeholder when user is typing
        const onType = () => {
            input.placeholder = OriginalPlaceholder;
            input.removeEventListener('input', onType);
            if (input._phTimer) {
            clearTimeout(input._phTimer);
            input._phTimer = null;
            }
        };

        input.addEventListener('input', onType, { once: true });

        //restore after 2s
        input._phTimer = setTimeout(() => {
            input.placeholder = OriginalPlaceholder;
            input.removeEventListener('input', onType);
            input._phTimer = null;
        }, 2000);
        };

    // validations
    if (!/^[a-zA-Z0-9 ]*$/.test(value)) return ShowPlaceholderWarning("Task contains invalid characters!");
    if (!value) return ShowPlaceholderWarning("Please enter a task!");
    if (value.length > 45) return ShowPlaceholderWarning("Task exceeds 45 characters!");
    if (tasks.includes(value)) return ShowPlaceholderWarning("Task already exists!");
    if (tasks.length >= 9) return ShowPlaceholderWarning("Maximum number of tasks reached");

    tasks.push(value);
    renderTasks();
    input.value = "";
    localStorage.removeItem(TASK_INPUT_KEY);
    saveTasks();
}

function removeTask(idx) {
    tasks.splice(idx, 1);
    renderTasks();
    saveTasks();

}


// input events
input.addEventListener('keyup', (event) => {
    if (event.key === 'Enter') addTask();
});

What are the biggest obstacles companies face when adopting AI Software Development, and how can they overcome them successfully? [closed]

Many companies are eager to adopt AI Software Development Services because of the potential to improve efficiency, decision-making, and automation. But in practice, adoption is not straightforward. Businesses often struggle with issues such as poor-quality data, unclear objectives, integration with legacy systems, limited in-house expertise, and fears about cost or complexity. These obstacles can delay or even derail AI projects.

What I tried:
We started exploring AI Software Development Services to automate processes and improve efficiency. The plan included testing predictive models with existing business data and integrating them into our legacy systems.
**
What I expected:**
I expected the models to provide clean insights, integrate smoothly, and improve decision-making with minimal setup.

What actually happened:
We ran into poor data quality, integration issues with older systems, and a lack of in-house expertise to fine-tune the models. Instead of smoother operations, we got delays and inconsistent results.

Tabulator Spreadsheet Paste Multiple Rows

The attached example allows for copying multiple rows but only pastes a single row. I would like to copy multiple rows and paste multiple rows.
jsfiddle : https://jsfiddle.net/8Lof1m3g/

Steps to reproduce:

  1. select multiple rows in the spreadsheet and press ctrl+c
  2. select an empty row and press ctrl+v

The result will be only one of the rows getting pasted.

Tabulator documentation: https://tabulator.info/examples/6.3#spreadsheet-clipboard

//define an array of sheet definitions
var sheets = [
  {
    title: "First Sheet",
    key: "first",
    rows: 20,
    columns: 20,
    data: [
      [9937, "", "", 7749, 9816, 4355, 8279, "", ""],
      [2380, "", 6977, 8896, 4012, 3803, 5408, 3415, 3056],
      [9180, "", 39, 9445, 3917, "", 18, 5239, 2516],
      [1924, 8734, 1819, 1838, 2330, 7921, 9219, "", 3537],
    ],
  },
  {
    title: "Second Sheet",
    key: "second",
    data: [
      [2380, "", 6977, 8896, 4012, 3803, 5408, 3415, 3056],
      [9180, "", 39, 9445, 3917, "", 18, 5239, 2516],
      [1924, 8734, 1819, 1838, 2330, 7921, 9219, "", 3537],
      ["", 8665, 5875, 9732, 1926, "", 9743, 8388, ""],
      [7040, 4861, 2988, 5584, 2344, 9749, 8872, 9177, 6246],
      [6334, 1674, 2967, "", 9353, 396, 6006, 8572, ""],
      [6359, "", 2580, 5723, 9801, 554, 1044, 5266, 8532],
    ],
  },
  {
    title: "Third Sheet",
    key: "third",
    rows: 5,
    columns: 5,
    data: [
      [1924, 8734, 1819, 1838, 2330, 7921, 9219, "", 3537],
      ["", 8665, 5875, 9732, 1926, "", 9743, 8388, ""],
      [7040, 4861, 2988, 5584, 2344, 9749, 8872, 9177, 6246],
      [6334, 1674, 2967, "", 9353, 396, 6006, 8572, ""],
      [6359, "", 2580, 5723, 9801, 554, 1044, 5266, 8532],
      [7278, 6971, 2232, 5720, 5665, 7231, 1165, "", 168],
    ],
  },
]

//Build Tabulator
var table = new Tabulator("#example-table", {
  height: "311px",

  spreadsheet: true,
  spreadsheetRows: 50,
  spreadsheetColumns: 50,
  spreadsheetColumnDefinition: { editor: "input", resizable: "header" },
  spreadsheetSheets: sheets,
  spreadsheetSheetTabs: true,

  rowHeader: {
    field: "_id",
    hozAlign: "center",
    headerSort: false,
    frozen: true,
  },

  editTriggerEvent: "dblclick", //change edit trigger mode to make cell navigation smoother
  editorEmptyValue: undefined, //ensure empty values are set to undefined so they arent included in spreadsheet output data

  //enable range selection
  selectableRange: 1,
  selectableRangeColumns: true,
  selectableRangeRows: true,
  selectableRangeClearCells: true,

  //configure clipboard to allow copy and paste of range format data
  clipboard: true,
  clipboardCopyStyled: false,
  clipboardCopyConfig: {
    rowHeaders: false,
    columnHeaders: false,
  },
  clipboardCopyRowRange: "range",
  clipboardPasteParser: "range",
  clipboardPasteAction: "range",
})

jQuery not grabbing form setup in chart.js loadCallback function

I have a form appearing in a popup, this loads in the content section of chart.js new Popup function. I’m utilizing the loadCallback as described in their documentation to set up actions based on input in the content.

When the button is clicked, the event is registering and hitting my code, however when I go to serialize the form to acquire its data, it reports blank. If I console.log the variable I’ve saved the form too, I do get the elements of the form.

So it appears to grab the elements, but my serializeObject function isn’t getting any data or references. I was curious if this is an issue with how I’m utilizing jQuery, or perhaps an issue with something else all together.

Edit: upon further playing around with this, I found that its jQuery’s serializeArray() function which isn’t returning any data on the form which my serializeObject() requires. Not sure why, I use it this way in every other script with forms.

const handleUserForm = function(document) {
    console.log(document);

    myPopup = new Popup({
        id: "popup",
        title: "Download Form",
        content: '<div class="row">' +
            '<form id="user-registration-form">' +
            '<div class="row">' +
            '<div class="col"><label for="fname" hidden>First Name</label><input type="text" placeholder="First Name" id="fname"></div>' +
            '<div class="col"><label for="lname" hidden>Last Name</label><input type="text" placeholder="Last Name" id="lname"></div> ' +
            '</div>' +
            '<div class="row">' +
            '<div class="col"><label for="email" hidden>Email</label><input type="email" placeholder="[email protected]"></div>' +
            '<div class="col"><label for="organization" hidden>Organization</label><input type="text" placeholder="Organization Name"></div>' +
            '</div>' +
            '<div class="row">' +
            '<div class="col"><label for="state" hidden>State</label><select id="state"></select></div>' +
            '<div class="col"><label for="zip" hidden>Zip Code</label><input id="zip" type="text"></div> ' +
            '</div>' +
            '<div class="row">' +
            '<a class="btn btn-secondary" type="submit" id="registrationFormSubmit" style="color: white;">Submit</a>' +
            '</div>' +
            '</form> ' +
            '</div>',
        loadCallback: () => {
            $('#registrationFormSubmit').on('click', function (e) {
                e.preventDefault();

                let $reg = $('#user-registration-form');

                console.log($reg);
                console.log($reg.serializeObject());
            })
        },
    });

    myPopup.show();
}

jQuery.fn.serializeObject = function () {
    let arrayData, objectData;
    arrayData = this.serializeArray();
    objectData = {};

    console.log('serializeObject');
    console.log(arrayData);

    $.each(arrayData, function () {
        let value;

        console.log(value);

        if (this.value != null) {
            value = this.value;
        } else {
            value = '';
        }

        if (objectData[this.name] != null) {
            if (!objectData[this.name].push) {
                objectData[this.name] = [objectData[this.name]];
            }

            objectData[this.name].push(value);
        } else {
            objectData[this.name] = value;
        }
    });

    return objectData;
};

Even though there are no errors in the frontend or backend, something in my Angular app is still preventing the pages from rendering

I am working on an Angular application, but currently all the pages are showing up as blank. There are no errors reported in the frontend console or in the backend, and the API calls are working correctly. I suspect that something in the app’s structure or routing configuration is blocking the rendering of the components. I have checked the modules and components, but the issue persists

I have tried checking all my Angular modules, components, and routing configuration. I also verified that there are no errors in the console and that all backend APIs are working correctly. I expected the pages to render normally, with each route displaying its corresponding component, but instead the application shows only a blank page.

How can I run JavaScript code in VS Code?

I’m learning JavaScript and I’m using Visual Studio Code as my editor.

I wrote a simple file, script.js:

console.log("Hello, world!");

But when I try to run it inside VS Code, nothing happens.

  • Do I need to install something extra?

  • Should I run it in the terminal, or is there a built-in way in VS Code to execute JavaScript files?

  • What’s the simplest way to run and see the output of my JS code in VS Code?

I’m on Windows 11.

How do services like Otter.ai programmatically join Google Meet without browser automation?

Context & Current Situation

We’re building an educational analytics platform and need to access individual participant video streams from Google Meet sessions. After hitting walls with official APIs (Meet API, Add-ons SDK), we’re exploring bot-based approaches.

The Documentation & Visibility Problem

The core issue: There’s zero official documentation on how to build Google Meet bots, yet companies like Otter.ai, Read.ai, and numerous others have seamless implementations.

What We’re Struggling With:
Complete lack of official guidance – No Google documentation on bot development for Meet

Technical implementation mysteries – How are these companies actually joining meetings programmatically?

Reliability vs. hackiness – Our Puppeteer attempts are fragile and break frequently

Detection avoidance – What techniques prevent Google from blocking bot access?

Core Questions:

How do established companies achieve rock-solid reliability? Their bots join seamlessly every time

What’s the actual technical architecture? Are they using undocumented APIs, special browser automation, or something else entirely?

I would appreciate real technical insights from developers who’ve solved this. Anyone with actual implementation experience or insights into how this ecosystem really works?