Why doesn’t my JavaScript function add a new to-do item to the list? [closed]

I’m creating a simple to-do list using HTML, CSS, and JavaScript.
When I click the “Add” button, I expect the new task to appear in the list, but nothing happens.
Here’s my code:

<input type="text" id="todo-input" placeholder="Add a task" />
<button onclick="addTodo()">Add</button>
<ul id="todo-list"></ul>

<script>
  function addTodo() {
    const input = document.getElementById("todo-input");
    const list = document.getElementById("todo-list");

    const item = document.createElement("li");
    item.textContent = input.value;

    list.appendChild(item);
  }
</script>

I don’t see any errors in the console, but the list stays empty.
What am I doing wrong?

How to find same property value in an object [duplicate]

I am trying to group objects by property, I mean same property value, using if and else condition not ternary operator. I do not know how to match the property value from the object.

let ars = [
{name:"raj", age:21},
{name:"mraj", age:26},
{name:"kraj", age:21},
{name:"draj", age:26},
{name:"wraj", age:21},
{name:"sraj", age:29},
];

var result = ars.reduce(function(a,c) {
   let key = c.age;
     if (a[key]) {

     } else {
     a[key]=c;
   }
   return a;
 }, {});

console.log(result);

Now I am getting like this:

 {
   '21': [ { name: 'raj', age: 21 } ],
   '26': [ { name: 'mraj', age: 26 } ],
   '29': [ { name: 'sraj', age: 29 } ]
 }

Output should be like:

{
  '21': [ { name: 'raj', age: 21 }, { name: 'kraj', age: 21 }, { name: 'wraj', age: 21 } ],
  '26': [ { name: 'draj', age: 26 }, { name: 'mraj', age: 26 } ],
  '29': [ { name: 'sraj', age: 29 } ]
}

How can I extract session slot IDs from HTML or fetch responses in a dashboard with no public API?

How can I extract session slot IDs from HTML or fetch responses in a dashboard with no public API?

I’m working on a private automation script for syncing availability across platforms. One of the platforms I use has a dashboard that shows class sessions (dates, available spots), but does not have a public API.

I’ve already figured out how to send updates to the backend using a PATCH request that modifies session spots — but to do that, I need to know the session slot IDs in advance.

I’ve tried:

Watching DevTools > Network for any XHR/fetch response that returns a list of sessions with IDs. Nothing obvious so far.

Searching the HTML DOM for data-session-id, input name=”session_id”, or inline JSON in tags. Haven’t found the ID array yet.

Question:

Is there a consistent or recommended method to extract internal IDs from a site like this, without using a headless browser?

Any direction on how to identify fetch/XHR responses or embedded data would help — especially if I can parse it with Python or JavaScript.

Not pulling in the supervisor name, it just says your supervisor twice

In the below script, I’m having an issue with the script removing Miguel or Linnea if they are the receipient of this email and where it says “Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.” it’s not pulling in the supervisor name it just says your supervisor twice.

/**
 * sendNotifications
 * -----------------
 * Sends one email per staffer with Status = "Incomplete".
 * • Reads Staff List (columns A=Staff Name, E=Supervisor, F=Email).
 * • Builds an in-memory map keyed by lowercased staff name.
 * • Looks up each person’s email and supervisor name & email from that map.
 * • CCs: supervisor, Miguel, Linnea (filtered by normalized local-part).
 * • Inserts the exact supervisor name (as spelled in Staff List) into the body.
 */
function sendNotifications() {
  const ss         = SpreadsheetApp.getActive();
  const ui         = SpreadsheetApp.getUi();
  const dbSheet    = ss.getSheetByName('Centralized Database');
  const staffSheet = ss.getSheetByName('Staff List');
  const mandSheet  = ss.getSheetByName('Mandatory Trainings');
  if (!dbSheet || !staffSheet || !mandSheet) {
    ui.alert('Error: Missing one or more required sheets.');
    return;
  }

  // Build header maps
  const dbMap  = getHeaderMap(dbSheet);
  const stMap  = getHeaderMap(staffSheet);
  const mdMap  = getHeaderMap(mandSheet);

  // 1) Build staffInfo map: 
  //    key = lowercased staffName, 
  //    value = { email, supervisorName (raw from column E) }
  const staffInfo = {};
  const staffData = staffSheet
    .getRange(2, 1, staffSheet.getLastRow() - 1, staffSheet.getLastColumn())
    .getValues();
  staffData.forEach(row => {
    const rawName  = (row[stMap['Staff Name']]   || '').toString().trim();
    const rawSup   = (row[stMap['Supervsior']]   || '').toString().trim(); // exact header spelling
    const rawEmail = (row[stMap['Email']]        || '').toString().trim();
    if (rawName && rawEmail) {
      const key = rawName.toLowerCase();
      staffInfo[key] = {
        email:      rawEmail.trim().toLowerCase(),
        supervisor: rawSup  // store exactly what’s in column E
      };
    }
  });

  // 2) Build a Set of mandatory titles (for labeling)
  const mandatoryList = mandSheet
    .getRange(2, mdMap['Mandatory Trainings'] + 1, mandSheet.getLastRow() - 1, 1)
    .getValues()
    .flat()
    .filter(String);

  // 3) Group all "Incomplete" trainings by lowercased staff name
  const incompleteMap = {}; // { "alice smith": ["Course A (Mandatory)", "Course B", ...], ... }
  const dbRows = dbSheet
    .getRange(2, 1, dbSheet.getLastRow() - 1, dbSheet.getLastColumn())
    .getValues();
  dbRows.forEach(r => {
    const status = (r[dbMap['Status']] || '').toString().trim();
    if (status !== 'Incomplete') return;

    const rawName  = (r[dbMap['Staff Name']]    || '').toString().trim();
    const title    = (r[dbMap['Training Title']]|| '').toString().trim();
    if (!rawName) return;

    const key       = rawName.toLowerCase();
    const label     = mandatoryList.includes(title)
      ? `${title} (Mandatory)`
      : title;

    if (!incompleteMap[key]) {
      incompleteMap[key] = [];
    }
    incompleteMap[key].push(label);
  });

  // 4) CC constants & helper to get local-part
  const MIGUEL = '[email protected]';
  const LINNEA = '[email protected]';
  function localPart(email) {
    return (email || '').toString().split('@')[0].toLowerCase().trim();
  }

  // 5) Send one email per staffName key
  Object.entries(incompleteMap).forEach(([staffKey, trainings]) => {
    // a) Lookup this staff’s info
    const info = staffInfo[staffKey];
    if (!info || !info.email) {
      console.warn(`Skipping "${staffKey}"—no email found in Staff List.`);
      return;
    }
    const toEmailNorm = info.email;            // already lowercased + trimmed
    const supNameRaw  = info.supervisor || '';  // exact text from column E
    const supKey      = supNameRaw.toLowerCase();
    const supEmailNorm = staffInfo[supKey]
      ? staffInfo[supKey].email
      : '';

    // b) Build CC list, dropping any whose local-part matches the recipient’s
    const ccList = [supEmailNorm, MIGUEL, LINNEA]
      .filter(addr => addr)                                // drop blanks
      .filter(addr => localPart(addr) !== localPart(toEmailNorm))  // drop if same local-part
      .filter((addr, i, arr) => arr.indexOf(addr) === i);  // dedupe

    // c) Build HTML bullet list
    const listHtml = trainings.map(t => `<li>${t}</li>`).join('n');

    // d) Supervisor display fallback
    const supDisplay = supNameRaw || 'your supervisor';

    // e) Compose the HTML body
    const htmlBody = `
<p>Hello ${staffKey.charAt(0).toUpperCase() + staffKey.slice(1)},</p>

<p>Our records show you have not completed the following trainings:</p>
<ul>
${listHtml}
</ul>

<p>We encourage you to complete these trainings at your earliest convenience, as they are pre-requisites for registering for future trainings and will ensure you stay aligned with professional development goals.</p>

<p>These trainings can be found on <a href="https://testing.litmos.com/account/Login">Litmos</a> —
please reach out to <a href="mailto:[email protected]">[email protected]</a>
if you have any issues accessing Litmos.</p>

<p>Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.</p>

<p>Warmly,<br>
<strong>BJI Training Liaisons</strong></p>
`;

    // f) Send the email
    GmailApp.sendEmail(toEmailNorm, 'Incomplete Trainings Reminder', '', {
      htmlBody,
      cc: ccList.join(', ')
    });
  });

  ui.alert('sendNotifications: All incomplete reminders have been sent.');
}

Google Apps Script Having 2 mapping issues

In the below script, I’m having an issue with the script removing Miguel or Linnea if they are the receipient of this email and where it says “Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.” it’s not pulling in the supervisor name it just says your supervisor twice. Help please!

/**
 * sendNotifications
 * -----------------
 * Sends one email per staffer with Status = "Incomplete".
 * • Reads Staff List (columns A=Staff Name, E=Supervisor, F=Email).
 * • Builds an in-memory map keyed by lowercased staff name.
 * • Looks up each person’s email and supervisor name & email from that map.
 * • CCs: supervisor, Miguel, Linnea (filtered by normalized local-part).
 * • Inserts the exact supervisor name (as spelled in Staff List) into the body.
 */
function sendNotifications() {
  const ss         = SpreadsheetApp.getActive();
  const ui         = SpreadsheetApp.getUi();
  const dbSheet    = ss.getSheetByName('Centralized Database');
  const staffSheet = ss.getSheetByName('Staff List');
  const mandSheet  = ss.getSheetByName('Mandatory Trainings');
  if (!dbSheet || !staffSheet || !mandSheet) {
    ui.alert('Error: Missing one or more required sheets.');
    return;
  }

  // Build header maps
  const dbMap  = getHeaderMap(dbSheet);
  const stMap  = getHeaderMap(staffSheet);
  const mdMap  = getHeaderMap(mandSheet);

  // 1) Build staffInfo map: 
  //    key = lowercased staffName, 
  //    value = { email, supervisorName (raw from column E) }
  const staffInfo = {};
  const staffData = staffSheet
    .getRange(2, 1, staffSheet.getLastRow() - 1, staffSheet.getLastColumn())
    .getValues();
  staffData.forEach(row => {
    const rawName  = (row[stMap['Staff Name']]   || '').toString().trim();
    const rawSup   = (row[stMap['Supervsior']]   || '').toString().trim(); // exact header spelling
    const rawEmail = (row[stMap['Email']]        || '').toString().trim();
    if (rawName && rawEmail) {
      const key = rawName.toLowerCase();
      staffInfo[key] = {
        email:      rawEmail.trim().toLowerCase(),
        supervisor: rawSup  // store exactly what’s in column E
      };
    }
  });

  // 2) Build a Set of mandatory titles (for labeling)
  const mandatoryList = mandSheet
    .getRange(2, mdMap['Mandatory Trainings'] + 1, mandSheet.getLastRow() - 1, 1)
    .getValues()
    .flat()
    .filter(String);

  // 3) Group all "Incomplete" trainings by lowercased staff name
  const incompleteMap = {}; // { "alice smith": ["Course A (Mandatory)", "Course B", ...], ... }
  const dbRows = dbSheet
    .getRange(2, 1, dbSheet.getLastRow() - 1, dbSheet.getLastColumn())
    .getValues();
  dbRows.forEach(r => {
    const status = (r[dbMap['Status']] || '').toString().trim();
    if (status !== 'Incomplete') return;

    const rawName  = (r[dbMap['Staff Name']]    || '').toString().trim();
    const title    = (r[dbMap['Training Title']]|| '').toString().trim();
    if (!rawName) return;

    const key       = rawName.toLowerCase();
    const label     = mandatoryList.includes(title)
      ? `${title} (Mandatory)`
      : title;

    if (!incompleteMap[key]) {
      incompleteMap[key] = [];
    }
    incompleteMap[key].push(label);
  });

  // 4) CC constants & helper to get local-part
  const MIGUEL = '[email protected]';
  const LINNEA = '[email protected]';
  function localPart(email) {
    return (email || '').toString().split('@')[0].toLowerCase().trim();
  }

  // 5) Send one email per staffName key
  Object.entries(incompleteMap).forEach(([staffKey, trainings]) => {
    // a) Lookup this staff’s info
    const info = staffInfo[staffKey];
    if (!info || !info.email) {
      console.warn(`Skipping "${staffKey}"—no email found in Staff List.`);
      return;
    }
    const toEmailNorm = info.email;            // already lowercased + trimmed
    const supNameRaw  = info.supervisor || '';  // exact text from column E
    const supKey      = supNameRaw.toLowerCase();
    const supEmailNorm = staffInfo[supKey]
      ? staffInfo[supKey].email
      : '';

    // b) Build CC list, dropping any whose local-part matches the recipient’s
    const ccList = [supEmailNorm, MIGUEL, LINNEA]
      .filter(addr => addr)                                // drop blanks
      .filter(addr => localPart(addr) !== localPart(toEmailNorm))  // drop if same local-part
      .filter((addr, i, arr) => arr.indexOf(addr) === i);  // dedupe

    // c) Build HTML bullet list
    const listHtml = trainings.map(t => `<li>${t}</li>`).join('n');

    // d) Supervisor display fallback
    const supDisplay = supNameRaw || 'your supervisor';

    // e) Compose the HTML body
    const htmlBody = `
<p>Hello ${staffKey.charAt(0).toUpperCase() + staffKey.slice(1)},</p>

<p>Our records show you have not completed the following trainings:</p>
<ul>
${listHtml}
</ul>

<p>We encourage you to complete these trainings at your earliest convenience, as they are pre-requisites for registering for future trainings and will ensure you stay aligned with professional development goals.</p>

<p>These trainings can be found on <a href="https://testing.litmos.com/account/Login">Litmos</a> —
please reach out to <a href="mailto:[email protected]">[email protected]</a>
if you have any issues accessing Litmos.</p>

<p>Contact your supervisor ${supDisplay}, Miguel, or Linnea for assistance.</p>

<p>Warmly,<br>
<strong>BJI Training Liaisons</strong></p>
`;

    // f) Send the email
    GmailApp.sendEmail(toEmailNorm, 'Incomplete Trainings Reminder', '', {
      htmlBody,
      cc: ccList.join(', ')
    });
  });

  ui.alert('sendNotifications: All incomplete reminders have been sent.');
}

Javascript JSON related TypeError

Workflow: Basically I want to update number of Pomodoro using this code:

backButton.addEventListener("click", async () => {
    remainingPomodoro = Math.max(0, noPomodoros - (pomoCount - 1)); // Result clamped to 0

    try {
        const response = await fetch("/updatetask", {
            method: "POST",
            headers: {
                "Content-type": "application/json"
            },
            body: JSON.stringify({
                taskId,
                updatedpomoCount: remainingPomodoro
            })
        });

        const rawText = await response.text();
        try {  // Read the response once
            result = JSON.parse(rawText);
            if (result.success) {
                window.location.href = "/task-tracker";
            }
            else {
                alert("Failed to update task.");
            }

        } catch (e) {
            const text = await response.text();
            console.error("Failed to parse JSON. Raw response:", text);
            alert("Server error. Check console for details.");
            return;
        }
    }

    catch (error) {
        console.error("Error updating task:", error);
        alert("Error contacting server.");
    }

This code will be transferred to flask backend to be processed:

@app.route("/updatetask", methods=["POST"])
def updatetask():
    if request.method == "POST":
        data = request.get_json()
        updated_pomocount = data.get("updatedpomoCount")
        id = data.get("taskId")

        db = get_db_connection()
        cursor = db.cursor()
        updated_task = cursor.execute("UPDATE tasks SET pomocount = ? WHERE id = ?", (updated_pomocount, id))
        db.commit()
        cursor.close()
        db.close()

        if updated_pomocount is None or id is None:
            return jsonify({"success": False, "error": "Missing data"}), 400
        return jsonify({"success": True})

However, I got this error:

Error updating task: TypeError: Failed to execute ‘text’ on ‘Response’: body stream already read
at HTMLButtonElement. (pomodoro.js:451:41)
(anonymous) @ pomodoro.js:459

Could somebody please help me to identify the root cause of the problem, why did I trigger the problem in the first place and the steps needed to fix this code.

The values are initialized in the following blocks of code

function addTask(taskName, noPomodoros, selectedDayIndex, taskId) {
  console.log(taskName, noPomodoros, selectedDayIndex, taskId)
  // Create a new task div
  const taskDiv = document.createElement("div");
  taskDiv.className = "task-div";
  taskDiv.innerHTML = 
  `<span>${taskName}</span>
  <p> Pomodoros: ${noPomodoros}</p>
  <button class="deleteTaskButton">delete</button>`;

  const deleteTaskButton = taskDiv.querySelector(".deleteTaskButton");

  // Initially hide the button via CSS (not with inline style)
  deleteTaskButton.style.opacity = "0";
  deleteTaskButton.style.visibility = "hidden";
  deleteTaskButton.style.transition = "all 0.3s ease;";

  // Show button on hover (only for this taskDiv)
  taskDiv.addEventListener("mouseenter", () => {
    deleteTaskButton.style.opacity = "1";
    deleteTaskButton.style.visibility = "visible";
  });
  taskDiv.addEventListener("mouseleave", () => {
    deleteTaskButton.style.opacity = "0";
    deleteTaskButton.style.visibility = "hidden";
  });

  // Add event listener to delete button
  deleteTaskButton.addEventListener("click", async (e) => {
    e.stopPropagation();
    new Audio('/static/button-click.mp3').play()
    try {
    const response = await fetch ('/deletetask', {
      method: 'DELETE',
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        task_id : taskId,
      }),
    });

    const result = await response.json();
    if (result.success) {
      taskDiv.remove();  
      alert("Task deleted successfully.");
    } else {
      alert("Failed to delete task.");
    }}
      catch (error) {
    console.error("Error deleting task:", error);
    alert("An error occurred.");
      }
  })
  // Insert the task div into the correct column above the add task button
  const targetColumn = document.querySelector(`.day-column[data-index="${selectedDayIndex}"]`)
  const addButton = targetColumn.querySelector(".add-task");
  targetColumn.insertBefore(taskDiv, addButton);

  taskDiv.addEventListener("click", async () => {
    const form = document.createElement("form");
    form.method = "POST";
    form.action = "/view-task";

    const data = {
      task_name: taskName,
      no_pomodoros: noPomodoros,
      day_idx: selectedDayIndex + 1,
    };

    for (const key in data) {
      const input = document.createElement("input");
      input.type = "hidden";
      input.name = key;
      input.value = data[key];
      form.appendChild(input);
    }

    localStorage.setItem("currentTask", JSON.stringify({
      taskName,
      noPomodoros,
      taskId,
      day_idx: selectedDayIndex
    }));

    document.body.appendChild(form);
    form.submit();
  })

  // Clear inputs and close popup
  document.getElementById('taskNameInput').value = '';
  document.getElementById('pomoCountInput').value = 1;
  closeTaskPopup();
}

taskFormPopup.addEventListener("submit", async function (e) {
  e.preventDefault(); // Prevent the form from submitting normally

  const taskName = document.getElementById("taskNameInput").value.trim(); 
  const noPomodoros = document.getElementById("pomoCountInput").value;
  const taskDayIdx = parseInt(document.getElementById("dayIndexInput").value);

  // Create a json object to send to flask serverside
  const response = await fetch('/addtask', {
    method: 'POST',
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      task_name: taskName,
      pomodoro_count: noPomodoros,
      day_index: taskDayIdx,
    }),
  });

  const data = await response.json();
  console.log(data);
  if (data.success) {
    taskId = data.task_id;
    addTask(taskName, noPomodoros, taskDayIdx, taskId);
    alert("Task added successfully!");
  }
  else {
    alert("Failed to add task. Please try again.")
  }
})

The other javascript file then receives the information here

const currentTask = JSON.parse(localStorage.getItem("currentTask"));
if (currentTask) {
    taskId = currentTask.taskId;
    noPomodoros = parseInt(currentTask.noPomodoros);
    taskName = currentTask.taskName;
    day_idx = currentTask.day_idx;
}

Any sort of guide and help is appreciated! Let me know if you still need any more information.

Dropdown buttons do not function correctly when NVDA screen reader is active

The dropdown buttons in the main menu are expected to open submenus when activated via the Enter or Space key. While this behavior works correctly during standard keyboard-only testing, it fails when NVDA is active: Instead of expanding the dropdown, pressing Enter or Space while focused on a dropdown item navigates to the linked product page. How can I fix this issue?

<button class="class1" tabindex="0" type="button" aria-controls="categoryList" aria-expanded="false"** aria-label="" aria-haspopup="true">

<span class="MuiBox-root css-0">Find Your Fit</span>

<span class="MuiTouchRipple-root css-w0pj6f"></span>
</button>

Users always get ERR_CONNECTION_CLOSED / ERR_CONNECTION_REFUSED error when using my website

I use php, javascript (for ajax), html and css to build my website on a web hosting.
However, when my users and I use the function of the website, we will get ERR_CONNECTION_CLOSED / ERR_CONNECTION_REFUSED error and got blocked for about 5 mins.
I asked the hosting provider and they say the server files are fine.

BTW, I have subdomains on the domain too.
When I got blocked, I change to use mobile network and the website comes back, but it will block me again if i use the website for a while.
the users have done clearing cache

upload image to firebase storage not working [closed]

I’m trying to upload image to firebase storage with this code

 const upLoadProfilePhoto = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
  mediaTypes: ImagePicker.MediaTypeOptions.Images,
  allowsEditing: true,
  aspect: [1, 1],
  quality: 1,
});

console.log(result.assets[0].uri);

if (!result.cancelled) {
  setImage(result.assets[0].uri);
 await uploadData(result.assets[0].uri, 'image')
}
};

async function uploadData (uri, fileType) {
// just to confirm the uri got to the upload function
 console.log('uploading....'+ uri)

const response = await fetch(uri)
const blob = await response.blob()
const storag = ref(storage, 'data/' + new Date().getTime())
const uploadTask = uploadBytesResumable(storag, blob)

uploadTask.on('state_changed', (snapshot) => {
     const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
     console.log('upload progress: ' + progress + '%')
},
(error) => {
 console.log(error)
},
() => {
  getDownloadURL(uploadTask.snapshot.ref).then(async (downloadUrl) => {

   setImageUrl(downloadUrl)
   console.log('file available at: ' + downloadUrl)

  }).then(() => {
   // saveToFireStore()
   
  })
})
}

somehow the image does not get uploaded and nothing is being logged in the console. I have all the necessary imports and still yet nothing happens when I try to upload an image.

c# dotnet SSE Server do answer, but the Browser do not display the messages. Why?

I have an SSE Server that has the following settings/requirements:

  • C# dotnet 8
  • Non Blocking Communication
  • No ASP
  • No Extention
  • Allow CORS

On the other side (client) I have an Browser with JavaScript

The Problem:

I can see the communication from the client to the server.
The Server accepts the request and send packets back to the client.
I can see the received packets with wireshark, but the javascript do not responds to the received packets.

If I try to use curl, then I receive the header. Then after a short period of time the cached packets (many packets). But I think the cache is full and I see the cache.

Here is the c# SSE Server code:

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

class Program
{
    private static readonly List<HttpListenerContext> clients = new List<HttpListenerContext>();
    private static readonly object lockObject = new object();
    private static System.Timers.Timer? messageTimer;

    static async Task Main(string[] args)
    {
        string url = "http://+:5000/";
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add(url);
        listener.Start();
        Console.WriteLine($"Server runs on {url}");

        // Timer
        messageTimer = new System.Timers.Timer(1000);
        messageTimer.Elapsed += SendPeriodicMessages;
        messageTimer.AutoReset = true;
        messageTimer.Enabled = true;

        while (true)
        {
            HttpListenerContext context = await listener.GetContextAsync();
            HandleClient(context);
        }
    }

    private static void HandleClient(HttpListenerContext context)
    {
        HttpListenerRequest request = context.Request;
        HttpListenerResponse response = context.Response;

        response.Headers.Add("Access-Control-Allow-Origin", "*");
        response.Headers.Add("Access-Control-Allow-Methods", "GET, OPTIONS");
        response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");

        if (request.HttpMethod == "OPTIONS")
        {
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, OPTIONS");
            response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
            response.StatusCode = (int)HttpStatusCode.OK;
            response.OutputStream.Close();
            return;
        }

        response.Headers.Add("Content-Type", "text/event-stream");
        response.Headers.Add("Cache-Control", "no-cache");
        response.Headers.Add("Connection", "keep-alive");

        AddClient(context);
    }

    private static void AddClient(HttpListenerContext context)
    {
        lock (lockObject)
        {
            clients.Add(context);

            var clientIp = context.Request.RemoteEndPoint.Address.ToString();
            var clientPort = context.Request.RemoteEndPoint.Port;
            Console.WriteLine($"Client connected: IP = {clientIp}, Port = {clientPort}");
        }
    }

    static int TimerCounter = 0;
    private static void SendPeriodicMessages(object? sender, ElapsedEventArgs e)
    {
        Console.WriteLine("TimerTick " + TimerCounter);
        SendMessagesToClients("data: " + TimerCounter++ + "\n\n");
    }

    private static void SendMessagesToClients(string message)
    {
        Task.Run(async () =>
        {
            byte[] buffer = Encoding.UTF8.GetBytes(message);

            List<Task> sendTasks = new List<Task>();
            List<HttpListenerContext> removeList = new ();

            lock (lockObject)
            {
                Console.WriteLine("Number of Clients: " + clients.Count);
                foreach (var client in clients)
                {
                    sendTasks.Add(Task.Run(() =>
                    {
                        try
                        {
                            HttpListenerRequest request = client.Request;
                            HttpListenerResponse response = client.Response;

                            var clientIp = client.Request.RemoteEndPoint.Address.ToString();
                            var clientPort = client.Request.RemoteEndPoint.Port;
                            Console.WriteLine($"Sending Data ({buffer.Length}) to {clientIp}:{clientPort}");

                            response.OutputStream.Write(buffer, 0, buffer.Length);
                            response.OutputStream.Flush();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"Error - Cant send data to Client: {ex.Message}");
                            removeList.Add(client);
                        }
                    }));
                }
            }

            await Task.WhenAll(sendTasks);

            lock (lockObject)
            {
                while (removeList.Count > 0)
                {
                    clients.Remove(removeList.First());
                    removeList.RemoveAt(0);   
                }
            }
        });
    }
}

And the JavaCode:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TEST</title>
</head>
<body>
    <h1>
        Server Send Event
    </h1>
    <div id="messages"></div>
    <script>
        const eventSource = new EventSource('http://192.168.56.245:5000/');

        eventSource.onmessage = function(event) {
            const messagesDiv = document.getElementById('messages');
            messagesDiv.innerHTML += `<p>${event.data}</p>`;
            console.log(event.data);
        };

        eventSource.onerror = function(event) {
            console.error("Error receiving messages from SSE:", event);
            eventSource.close();
        };
    </script>
</body>
</html>

how do I pass a URL with multiple parameters in javascript code? [duplicate]

I want to run jasper report from oracle APEX and I used javascript code to run the report URL

I need to run the URL and pass 3 parameters

This is the code I used :

var company_id = $v('P53_COMPANY');
var sample_id = $v('P53_SAMPLE');
var program_id = $v('P53_PROGRAM');

if (company_id && sample_id && program_id) {
    var url = 'http://maxapex:8090/JasperReportsIntegration/report?_repName=785/Companyrep&_repFormat=pdf&standAlone=true&_dataSource=2064&company_id=' + company_id;
    window.open(url, '_blank'); // Opens the URL in a new tab
} else {
    alert('Select company and sample and program before print');
}

the code with one parameter its working but I need to pass also sample_id and program_id
at the end of var url ,

I don’t know the correct syntax ?
Thank you in advance

Change CSS property after transition

I have a button to toggle opening and closing of a dropdown menu with CSS transition. Suppose I have this HTML for a dropdown menu and a toggle button:

<button type="button" id="main-nav-collapse-button" aria-label="Click to expand or collapse the main navigation menu" >☰</button>
...
<nav role="navigation" id="main-nav"><ul>
  <li>...</li>
  <li>...</li>
  <li>...</li>
</ul></nav>

Instead of opening/closing the nav dropdown with JS, I have minimal JS to just add/remove a class .expanded to/from the <ul>.

I have transition in the CSS so that the opening/closing is animated:

#main-nav>ul {
  display:none;
  max-height:0;
  overflow:hidden;
  transition: height 0.5s linear;
}
#main-nav>ul.expanded {
  display:block;
  max-height: 100vh;
}

The problem with the above code is that the opening/closing do not transition/animate because I have display CSS property specified in both states. display cannot be transition/animated and it is toggled straight away when the class is added/removed.

In contrast, if I remove the display properties in the CSS, it does animate. The only problem is that the menu is only hidden from users (height=0) but not preventing the menu from being accessed. When users use keyboard-navigation by tapping , the menu items in the menu are still focusable even they are visibly ‘hidden’. I haven’t found a solution to disable the focus with CSS.

I am hoping there is a way to apply the display property change before/after the CSS transition. I haven’t got a pure CSS approach. My current fallback is to apply the change of display property before/after the class-toggle with a delay using JS, but I just feel that this approach is more like a patch to the problem rather than a proper solution.

It will be great if there is a non-JS solution.

Side note: I could have made the class-toggling part non-JS-dependent too, but unfortunately the button and the nav don’t share the same parent in DOM. Making the dropdown to appear/hide on hover without JS would be extremely difficult.

Flatpickr in Brave / Safari needs two clicks to open

I have tried literally everything I (and chatgpt) could think of but I cannot fix it.
I have a simple form using Flatpickr. It works like a charm but in Safari and Brave (the latter both on Android and iOs) the date picker needs two clicks to open the datepicker.

This is my code:

<!-- Flatpickr CSS & JS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>

<form id="booking-form" style="
  display: flex;
  flex-wrap: nowrap;
  gap: 10px;
  background-color: #2F4D47;
  border-radius: 10px;
  padding: 10px;
">
  <!-- Location select -->
  <select id="location" style="
    flex: 1 1 auto;
    min-width: 150px;
    background-color: #FFFFFF;
    border: none;
    border-radius: 5px;
    padding: 12px 40px 12px 15px;
    font-size: 16px;
    color: #1f1f1f;
    background-image: url('data:image/svg+xml;charset=UTF-8,<svg fill='%231f1f1f' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/></svg>');
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px 16px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
  ">
    <option value="">Alle locaties</option>
    <option value="811720" selected>Kedichem</option>
    <option value="811721">Dorst</option>
  </select>

  <!-- Date range -->
<input type="text" id="date-range" placeholder="Selecteer periode" readonly style="
  flex: 1 1 auto;
  min-width: 200px;
  background-color: #FFFFFF;
  border: none;
  border-radius: 5px;
  padding: 12px 15px; /* GEEN extra padding rechts */
  font-size: 16px;
  color: #1f1f1f;
  text-align: left;
  width: 100%;
">

  <!-- Number of people -->
  <select id="people" style="
    flex: 1 1 auto;
    min-width: 100px;
    background-color: #FFFFFF;
    border: none;
    border-radius: 5px;
    padding: 12px 40px 12px 15px;
    font-size: 16px;
    color: #1f1f1f;
    background-image: url('data:image/svg+xml;charset=UTF-8,<svg fill='%231f1f1f' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/></svg>');
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px 16px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
  ">
    <option value="1">1</option>
    <option value="2" selected>2</option>
    <option value="3">3</option>
  </select>

  <!-- Submit button -->
  <button type="submit" style="
    flex: 1 1 auto;
    min-width: 120px;
    background-color: #dfa16f;
    color: #1f1f1f;
    border: none;
    border-radius: 25px;
    padding: 12px 15px;
    font-size: 16px;
    font-weight: 500;
    cursor: pointer;
                font-weight: 400;
            font-family: 'gitan-latin';
  ">Zoeken</button>
</form>

<script>
    const input = document.getElementById("date-range");

  const fp = flatpickr(input, {
    mode: "range",
    minDate: "today",
    dateFormat: "Y-m-d",
    clickOpens: false,
    allowInput: false,
  });

  function openPicker(e) {
    e.preventDefault();
    setTimeout(() => {
      input.blur(); // force blur to reset state
      input.focus(); // ensure input is active again
      fp.open();
    }, 0);
  }

  ["click", "focus", "touchstart", "mousedown"].forEach(event => {
    input.addEventListener(event, openPicker, { passive: false });
  });
  // Form logic
  document.getElementById("booking-form").addEventListener("submit", function (event) {
    event.preventDefault();

    const location = document.getElementById("location").value;
    const range = document.getElementById("date-range").value;
    const people = document.getElementById("people").value;

    const [startDate, endDate] = range.split(" to ");

    const currentLocale = window.location.href.includes("/en/") ? "en" : "nl";
    const baseUrl = currentLocale === "en"
      ? "https://reserveren.rostig.nl/en/book"
      : "https://reserveren.rostig.nl/reserveren";

    const url = `${baseUrl}?period%5Bstart_date%5D=${startDate}&period%5Bend_date%5D=${endDate}&guest_group%5Badults%5D=${people}&tag_ids%5B%5D=${location}`;

    const newWindow = window.open(url, "_blank");
    if (!newWindow) {
      window.location.href = url;
    }
  });

</script>

<style>
  /* Responsive layout */
  @media (max-width: 768px) {
    #booking-form {
      flex-wrap: wrap !important;
    }
    #booking-form > * {
      flex: 1 1 100% !important;
      max-width: 100% !important;
    }
  }

  input::placeholder {
    color: #999999;
    opacity: 1;
  }
</style>

The code is live on https://rostig.nl/nl/kedichem/ so you can test the behavior there.

It is a WordPress website build with Avada themebuilder. I have added this code with a code block.

Does anyone have any idea how to solve this?

multiple data doesnt deleted from table using Ajax in wordpress

I was define following script for deleting multiple data. Please check the attached image.enter image description here I will select multiple title and click deleted title button data will be deleted. I checked the log there is showing following error. I cant understand how to fix this error.

IDs received for deletion: Array
(
[0] => 10
1 => 8
)

check error: %d,%d
Prepared query for deletion: DELETE FROM wp_slf_schedule_post_title_log WHERE id IN (%d,%d)
IDs received for deletion: 0

PHP script

public function otslf_delete_multiple_blog_title() {

                //check_ajax_referer('ai-seo-content-nonce', 'nonce');
                if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ai-seo-content-nonce' ) ) {
                wp_send_json_error( __( 'Invalid nonce.', 'super-fast-blog-ai' ) );
                }   
                error_log( $_POST['nonce'] ); // Debugging line
            
                global $wpdb;
                $table_name = $wpdb->prefix . 'slf_schedule_post_title_log';
                $ids = isset($_POST['id']) ? array_map('intval', $_POST['id']) : [];


           error_log('IDs received for deletion: ' . print_r($ids, true)); // Debugging line
        
                $placeholders = implode(',', array_fill(0, count($ids), '%d'));
                $query = "DELETE FROM $table_name WHERE id IN ($placeholders)";

                error_log('check error: ' . $placeholders);                  // Debugging line
                error_log('Prepared query for deletion: ' . $query);         // Debugging line
                
                $deleted = $wpdb->query($wpdb->prepare($query, $ids)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery

                error_log('IDs received for deletion: ' . $deleted);

                if ($deleted !== false) {
                    wp_send_json_success(['message' => 'Selected titles deleted successfully.']);
                } else {
                    wp_send_json_error(['message' => 'Failed to delete selected titles.']);
                }
            }

jQuery script

jQuery(document).ready(function($) {
                        jQuery('#select_title').click(function() {
                            let isChecked = jQuery(this).is(':checked');
                            jQuery('input[name="select_title[]"]').prop('checked', isChecked);
                        });          
                        jQuery('#delete-selected').click(function(e) {
                            e.preventDefault();

                            let id = jQuery('input[name="select_title[]"]:checked').map(function() {
                                return jQuery(this).val();
                            }).get();

                            console.log('Selected IDs:', id);

                            if (id.length === 0) {
                                jQuery.toast({ text: "Please select at least one title to delete.", 
                                heading: 'Failed', 
                                icon: 'error',
                                showHideTransition: 'fade',
                                allowToastClose: true, 
                                hideAfter: 3000, 
                                stack: 5, 
                                position: 'top-right', 
                            });                        
                            }
                    
                            jQuery.ajax({
                                url: ajax_ob.ajax_url,
                                type: 'POST',
                                data: {
                                    action: 'otslf_delete_multiple_blog_title',
                                    id: id,
                                    nonce: ajax_ob.nonce
                                },
                                beforeSend: function(xhr) {
                                    jQuery('#delete-selected').append('<span class="loading-spinner"></span>');
                                },
                                success: function(response) {

                                    console.log('Response:', response);
                                    
                                    if (response.success) {
                                        jQuery('input[name="select_title[]"]:checked').closest('tr').remove();
                                        jQuery.toast({
                                            text: "!Selected Title Deleted Successfully",
                                            heading: 'success', 
                                            icon: 'success', 
                                            showHideTransition: 'fade', 
                                            allowToastClose: true, 
                                            hideAfter: 4000, 
                                            stack: 15, 
                                            position: { left : 'auto', right : 100, top : 153, bottom : 'auto' },
                                            textAlign: 'left',
                                            loader: true, 
                                            loaderBg: '#9EC600', 
                                        });
                                        
                                       /*  setTimeout(function() {
                                            location.reload();
                                        }, 2000); */ 

                                    } else {
                                        jQuery.toast({ text: "Please select at least one title to delete.", 
                                            heading: 'Failed', 
                                            icon: 'error',
                                            showHideTransition: 'fade',
                                            allowToastClose: true, 
                                            hideAfter: 3000, 
                                            stack: 5, 
                                            position: 'top-right', 
                                        });
                                    }
                                },
                            
                                complete: function() {
                                    jQuery('#delete-selected').find('.loading-spinner').remove();
                                },

                                error: function(xhr, status, error) {
                                    jQuery.toast({ text: 'An error occurred: ' + error, 
                                        heading: 'NOTE', 
                                        icon: 'error',
                                        showHideTransition: 'fade',
                                        allowToastClose: true, 
                                        hideAfter: 3000, 
                                        stack: 5, 
                                        position: 'top-right', 
                                    });
                                }
                            });
                        });
                    });