fullCalendar is throwing undefined error on successCallback after correctly parsing the response from the backend

I am using fullCalendar 5.5.1 to display some events on screen. I fetch the data from the database and it is working as expected. The only issue I have is that in some situations I receive an error:

Uncaught (in promise) TypeError: successCallback(…) is undefined

It happens if the response from the database is empty but it also happens after fullCalendar parses all the data returned from the database (like it is not stopping after managing all the records).

To avoid the first to happen I put a check on the response length so that if it is 0 it stops parsing and it works fine but I don’t know how to avoid the other situation.

A sample of my data is (printed from console)

0: Object { title: "Evento di test 1 - 7 hours", start: "2024-06-01T22:00:00.000Z", duration: 7 }​
1: Object { title: "Evento di test 2 - 3 hours", start: "2024-06-01T22:00:00.000Z", duration: 3 }
2: Object { title: "Evento di test 3 - 3 hours", start: "2024-06-06T22:00:00.000Z", duration: 3 }
3: Object { title: "Evento di test 4 - 7 hours", start: "2024-06-09T22:00:00.000Z", duration: 7 }
4: Object { title: "Evento di test 5 - 4 hours", start: "2024-06-20T22:00:00.000Z", duration: 4 }
5: Object { title: "Evento di test 6 - 6 hours", start: "2024-06-22T22:00:00.000Z", duration: 6 }
6: Object { title: "Evento di test 7 - 3 hours", start: "2024-06-28T22:00:00.000Z", duration: 3 }

While the code I am using is:

        var calendar = new Calendar(calendarEl, {
            timeZone: 'local',
            customButtons: {
                newEvent: {
                    text: 'New record',
                    click: function () {
                        alert('clicked the custom button!');
                    }
                }
            },
            headerToolbar: {
                right: 'prev,next today',
                left: 'title',
                center: 'newEvent',
                //right: 'dayGridMonth,dayGridWeek,dayGridDay'
            },
            themeSystem: 'bootstrap',
            defaultAllDay: true,
            events: function (info, successCallback, failureCallback) {
                let user = sessione.profilo.id;
                let project = sessione.progettoAttivo.id;
                //let start = info.start.valueOf();
                //let end = info.end.valueOf();
                let start = info.startStr;
                let end = info.endStr;
                smartAxios.get("/timesheet?user=" + user + "&project=" + project + "&start=" + start + "&end=" + end)
                .then((response) => {
                    console.log(response.data);
                    let prevDate = '';
                    let totDuration = 0;
                    if(response.data.length==0){
                        console.log('no data for this month');
                    }else{
                        successCallback(
                            response.data.map(function (eventEl) {
                                console.log(eventEl);
                                return {
                                    title: eventEl.title,
                                    start: eventEl.start,
                                    color: '#007bff',
                                    textColor: 'white',
                                    allDay: true
                                }
                            }),
                            response.data.forEach(function (element) {
                                let date = new Date(element.start);
                            
                                let year = date.getFullYear();
                                let month = ((date.getMonth()+1).toString().length < 2) ? "0"+(date.getMonth()+1) : (date.getMonth()+1);
                                //let month = date.getMonth()+1;
                                let day = ((date.getDate()).toString().length < 2) ? "0"+(date.getDate()) : (date.getDate());
                                //let day = date.getDate();
                                date= year+'-'+month+'-'+day;
                                if (date == prevDate) {
                                    totDuration = totDuration + element.duration;
                                } else {
                                    prevDate = date;
                                    totDuration = element.duration;
                                }
                                if (totDuration > 8) {
                                    $('#calendar').find('.fc-day[data-date="' + date + '"]').css('background-color', '#FAA732');
                                }
                                console.log(prevDate, totDuration);
                            })
                        )
                        .catch(function(err){
                            console.log(err)
                            $(document).Toasts('create', { autohide: true, delay: 750, title: 'Timesheet',class: 'bg-danger', body:'Error trying to retrieve data'})
                            
                        });
                    }

                });
            }
        });

webscraping – request with dynamically generated parameter

One thing I’ve alawys wanted was to write an auto checkout bot/monitoring bot for more complex websites. The problem I encountered is as follows:

There is some ‘hidden’ data on the website I’m trying to scrape, which contains stuff such as product stock etc.

It’s all in a response of a request, which looks like this:
https://site-api.site_name.com/shop/v1/shop/productDetails?spuId={spuId}&s={sValue}&t={tValue}

I know that t is just a timestamp, but value s, is dynamically generated (I assume so, because it changes everytime I refresh the website).

I also noticed that in this api headers is a “X-sign” header, which contains some value and a timestamp. (I don’t know if it could be anyway useful)
enter image description here

How do I find out how is “s” generated? I’m sure it’s possible.

Trying to embed a leafletJS map in a responsive website

I am trying to generate a responsive website where a map and an info div would be displayed laterally on large screens and stack on phones.

My main code is:

<body>
    <div id="global_container">
        <div id="maCarte">
            <script>
... scripts to generate maps ...
            </script>
        </div>
            
        <div id="left_panel">
            <div id="info_block">
                <p id="detailed_info">
                </p>
            </div>
        </div>
    </div>
</body>

And the CSS contains:

body{
    font-family: "Ubuntu", "Open Sans", sans-serif; /* Optima, Calibri, "Gill Sans", Verdana, "Trebuchet MS", Geneva, */
    margin:0;
    background: #F1F3F9;
}

#global_container {
    display: flex;
    flex-wrap: wrap; /* Allows wrapping for smaller screens */
}

#maCarte{
    position: relative; /* pb avec INSEE */
    width: 65%;
    float: left;
    height: 100vh; 
}

#left_panel {
    color: #333;
    width: 35%;
    float: right;
}
    
#info_block {
  width: auto;
  height: auto;
  margin: 0 auto;
  padding: 0 10%;
  position: relative;
}


/* Keep after the definition of #maCarte and #left_panel */
@media all and (max-width:800px) {
    #maCarte, #left_panel {
        display: block; 
        float: none; 
        width: 100%;
    }
}

However, instead of stacking normally, the two blocks superimpose on small screens. I assume this is due to using height: 100vh; for #maCarte, but if I do not use it, then the maps is of zero height or does not fill in the page in computer screens.

What should I do?

How to broadcast a video stream without reloading the page?

I created a node js server to 1) receive images in udp and transform them into video and
2) display it on a website

  1. I tried but I don’t understand how to broadcast the video live without having to reload the page

node js server code :

const express = require('express');
const dgram = require('dgram');
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const path = require('path');
const WebSocket = require('ws');

const app = express();
const httpPort = 3000;

const imageDir = path.join(__dirname, 'images');
if (!fs.existsSync(imageDir)) {
    fs.mkdirSync(imageDir);
}

let imageCount = 0;

const udpPort = 15002;
const udpHost = '127.0.0.1';
const server = dgram.createSocket('udp4');

const wss = new WebSocket.Server({ noServer: true });


const createVideo = () => {
    const outputVideo = path.join(__dirname, 'output_video.mp4');

    ffmpeg()
        .input(path.join(imageDir, '%d.jpg'))
        .inputOptions('-framerate 30')
        .output(outputVideo)
        .outputOptions('-c:v libx264')
        .on('end', () => {
            console.log('Vidéo créée avec succès !');

            wss.clients.forEach(client => {
                if (client.readyState === WebSocket.OPEN) {
                    client.send('new-video');
                }
            });
        })
        .on('error', (err) => {
            console.log('Erreur lors de la création de la vidéo:', err);
        })
        .run();
};


app.get('/feed-video', (req, res) => {
    const videoPath = path.join(__dirname, 'output_video.mp4');
    res.sendFile(videoPath);
});

server.on('message', (msg, rinfo) => {
    console.log(`Reçu message de ${rinfo.address}:${rinfo.port}`);

    const imageFilePath = path.join(imageDir, `${imageCount}.jpg`);
    fs.writeFileSync(imageFilePath, msg);

    console.log(`Image ${imageCount}.jpg reçue et sauvegardée`);


    imageCount++;


    if (imageCount > 100) {
        createVideo();
        imageCount = 0;
    }
});


server.on('listening', () => {
    const address = server.address();
    console.log(`Serveur UDP en écoute sur ${address.address}:${address.port}`);
});


app.server = app.listen(httpPort, () => {
    console.log(`Serveur HTTP et WebSocket démarré sur http://localhost:${httpPort}`);
});

app.server.on('upgrade', (request, socket, head) => {
    wss.handleUpgrade(request, socket, head, (ws) => {
        wss.emit('connection', ws, request);
    });
});


server.bind(udpPort, udpHost);

the html page :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Drone Video Feed</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #1a1a1a;
            color: #ffffff;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }

        h1 {
            margin-bottom: 20px;
            font-size: 2rem;
            text-shadow: 1px 1px 5px #00bcd4;
        }

        video {
            width: 80%;
            max-width: 600px;
            border: 2px solid #00bcd4;
            border-radius: 8px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
        }
    </style>
</head>
<body>
<h1>Drone Video Feed</h1>
<video id="video" controls autoplay></video>

<script>
    const video = document.getElementById('video');
    const ws = new WebSocket('ws://localhost:3000');

    ws.onmessage = (event) => {
        const blob = new Blob([event.data], { type: 'video/mp4' });
        video.src = URL.createObjectURL(blob);
        video.play();
    };
</script>
</body>
</html>

please can you help me to resolve this problem?

I tried with websocket but I didn’t succeed.
the video is correctly created and when I reload the page the new video is played by the player

however I would have been able to see the live stream without having to reload my page all the time

multipart/form-data request to Google Drive API in React Native

I’m trying to send a multipart/form-data request to the Google Drive API from my React Native app.
When I use Postman, the request works perfectly, but when I try to implement the same request in React Native using fetch or axios, I keep getting a “Malformed multipart body” error.

I’m constructing the request using FormData, adding metadata (metadata) and the file (file).
This setup works fine in Postman, so I suspect there’s something different in how React Native handles FormData or the Content-Type header for multipart requests.

Has anyone experienced this issue in React Native?
Is there a specific way to configure FormData to behave the same way as it does in Postman?
Or, if you have any recommendations for alternative approaches to send multipart/form-data requests from React Native, I’d really appreciate the guidance.

Thanks in advance for any help!

enter image description here

export const uploadToGoogleDrive = async (data) => {
  try {
    const accessToken = await signInWithGoogle();
    const fileName = data.title;
    const fileDescription = data.description;
    const file = data.file;
    const fileMimeType = file.assets[0].mimeType;

    const formData = new FormData();

    formData.append("metadata", JSON.stringify({
      name: fileName,
      mimeType: fileMimeType,
      description: fileDescription,
      parents: [GOOGLE_DRIVE_FOLDER_ID]
    }), { type: 'application/json' });

    formData.append('file', {
      uri: file.assets[0].uri,
      type: fileMimeType,
      name: fileName,
    });

    const response = await fetch(`${GOOGLE_DRIVE_ENDPOINT}/files?uploadType=multipart`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
      },
      body: formData,
    });

    if (!response.ok) {
      const errorText = await response.json();
      console.log("Detailed Error:", errorText);
      throw new Error(`Error uploading file: ${response.statusText}, details: ${errorText}`);
    }

    return response;

  } catch (error) {
    console.error("Upload error:", error);
    if (error.response) {
      console.error("Response data:", error.response.data);
    } else if (error.request) {
      console.error("Request details:", error.request);
    } else {
      console.error("Error:", error.message);
    }
  }
};

Allowing characters in eg variable names in Monaco editor

Is there a Monaco option to treat non-ascii characters as valid in variable names in the Monaco editor? In VSCode the below code would have been formatted as a valid variable name, but when using MonacoEditor it stumbles on valid characters like ö.

I have tried toggling the unicodeHighlight: nonBasicASCII option, but that seems to be something else, and neither does unicodeHighlight: allowedLocales do any good here. The red color has the classname .mtk11, but I haven’t been able to find a list of what those classnames actually mean.

enter image description here

I’m using [email protected] (in a Nuxt4 project through [email protected], but options are forwardes as-is, so that probably doesn’t matter.)

How can I prefill DatePicker and TimePicker components with data retrieved from the backend?

I’m working on React app using Ant-Design UI library. I am trying to prefill the date and time pickers with data received from backend so users can change the dates/time and make an API call to update. I used the form.setFieldsValue inside useEffect to set the date and time picker values with form passed as dependency into the useEffect. I noticed that the date picker were blinking as a result it was difficult to select date/time. On the other hand, I removed the dependency array and the form fields were not prefilled with data.

useEffect(() => {
  const data = openHours?.data?.data;
  form.setFieldsValue({
    firsTermFrom:
      openHours?.data?.data?.firstTerm?.from &&
      moment(openHours?.data?.data?.firstTerm?.from, dateFormat).isValid()
        ? moment(openHours?.data?.data?.firstTerm?.from, dateFormat)
        : "",
    firstTermTo:
      openHours?.data?.data?.firstTerm?.to &&
      moment(data?.firstTerm?.to, dateFormat).isValid()
        ? moment(openHours?.data?.data?.firstTerm?.to, dateFormat)
        : "",
    secondTermFrom:
      openHours?.data?.data?.secondTerm?.from &&
      moment(data?.secondTerm?.from, dateFormat).isValid()
        ? moment(openHours?.data?.data?.secondTerm?.from, dateFormat)
        : "",
    secondTermTo:
      openHours?.data?.data?.secondTerm?.to &&
      moment(data?.secondTerm?.to, dateFormat).isValid()
        ? moment(openHours?.data?.data?.secondTerm?.to, dateFormat)
        : "",
    thirdTermFrom:
      openHours?.data?.data?.thirdTerm?.from &&
      moment(data?.thirdTerm?.from, dateFormat).isValid()
        ? moment(openHours?.data?.data?.thirdTerm?.from, dateFormat)
        : "",
    thirdTermTo:
      openHours?.data?.data?.thirdTerm?.to &&
      moment(data?.thirdTerm?.to, dateFormat).isValid()
        ? moment(openHours?.data?.data?.thirdTerm?.to, dateFormat)
        : "",
    studentStart:
      openHours?.data?.data?.studentsNewResumptionTime !== "Invalid date" &&
      openHours?.data?.data?.studentsNewResumptionTime !== null &&
      moment(data?.studentsNewResumptionTime, "h:mm:ss a").isValid()
        ? moment(
          openHours?.data?.data?.studentsNewResumptionTime,
          "h:mm:ss a"
        ) : "",
    studentEnd:
      openHours?.data?.data?.studentNewClosingTime !== "Invalid date" &&
      openHours?.data?.data?.studentNewClosingTime !== null &&
      moment(data?.studentNewClosingTime, "h:mm:ss a").isValid()
        ? moment(openHours?.data?.data?.studentNewClosingTime, "h:mm:ss a")
        : "",
    superStart:
      openHours?.data?.data?.supervisorNewResumptionTime !== "Invalid date" &&
      openHours?.data?.data?.supervisorNewResumptionTime !== null &&
      moment(data?.supervisorNewResumptionTime, "h:mm:ss a").isValid()
        ? moment(
          openHours?.data?.data?.supervisorNewResumptionTime,
          "h:mm:ss a"
        ) : "",
    superEnd:
      openHours?.data?.data?.supervisorNewClosingTime &&
      openHours?.data?.data?.supervisorNewClosingTime !== "Invalid date" &&
      openHours?.data?.data?.supervisorNewClosingTime !== null &&
      moment(data?.supervisorNewClosingTime, "h:mm:ss a").isValid()
        ? moment(openHours?.data?.data?.supervisorNewClosingTime, "h:mm:ss a")
        : "",
  });
}, []);

<Form
  className="openHrs w-2/3"
  form={form}
  title="open-hours"
  onFinish={onFinish}
  onFinishFailed={onFinishFailed}
  autoComplete="off"
>
  <div className="">
    <span
      className="text-lg font-extrabold"
      title="openhrs"
      data-testid="openhrs-title"
    >
      Open hours
    </span>
  </div>

  {/* SESSION */}
  <div className="mt-7 mb-3 flex flex-col items-baseline">
    <div className="mb-7 w-60">
      <span className="student font-InterMedium text-base font-medium tracking-widest text-arshGrey opacity-100">
        SESSION
      </span>
    </div>
  </div>

  {/* TERMS */}
  <div className="flex flex-col space-y-3">
    {/* 1ST TERM*/}
    <div className="mt-2 mb-1 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="font-InterMedium text-base font-medium">
          First term
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <div className="flex w-3/4 flex-row items-center space-x-2">
        <Form.Item
          name={"firsTermFrom"}
          rules={[
            {
              required: true,
              message: "Please input first term start date",
            },
          ]}
        >
          <DatePicker
            picker="date"
            className="openInput outline-0 w-52 rounded border-0 bg-inputBg px-10 py-3 font-InterMedium opacity-100 shadow-none"
            placeholder="Start date"
            format={dateFormat}
            size={"large"}
            data-testid="first-term-from"
          />
        </Form.Item>

        <Form.Item
          name={"firstTermTo"}
          rules={[
            {
              required: true,
              message: "Please input second term start date",
            },
          ]}
        >
          <DatePicker
            picker="date"
            className="openInput outline-0 w-52 rounded border-0 bg-inputBg px-10 py-3 font-InterMedium opacity-100 shadow-none"
            placeholder="End date"
            format={dateFormat}
            size={"large"}
          />
        </Form.Item>
      </div>
    </div>

    {/* 2ND TERM */}
    <div className="mb-3 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="schName font-InterMedium text-base font-medium">
          Second term
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <div className="flex w-3/4 flex-row items-baseline space-x-2">
        <Form.Item
          name={"secondTermFrom"}
          rules={[
            {
              required: true,
              message: "Please input second term start date",
            },
          ]}
        >
          <DatePicker
            picker="date"
            className="openInput outline-0 w-52 rounded border-0 bg-inputBg px-10 py-3 font-InterMedium opacity-100 shadow-none"
            placeholder="Start date"
            format={dateFormat}
            size={"large"}
          />
        </Form.Item>

        <Form.Item
          name={"secondTermTo"}
          rules={[
            {
              required: true,
              message: "Please input second term end date",
            },
          ]}
        >
          <DatePicker
            picker="date"
            className="openInput outline-0 w-52 rounded border-0 bg-inputBg px-10 py-3 font-InterMedium opacity-100 shadow-none"
            placeholder="End date"
            format={dateFormat}
            size={"large"}
          />
        </Form.Item>
      </div>
    </div>

    {/* 3RD TERM */}
    <div className="mb-3 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="schName font-InterMedium text-base font-medium">
          Third term
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <div className="flex w-3/4 flex-row items-center space-x-2">
        <Form.Item
          name={"thirdTermFrom"}
          rules={[
            {
              required: true,
              message: "Please input third term start date",
            },
          ]}
        >
          <DatePicker
            picker="date"
            className="openInput outline-0 w-52 rounded border-0 bg-inputBg px-10 py-3 font-InterMedium opacity-100 shadow-none"
            placeholder="Start date"
            format={dateFormat}
            size={"large"}
          />
        </Form.Item>

        <Form.Item
          name={"thirdTermTo"}
          rules={[
            {
              required: true,
              message: "Please input third term end date",
            },
          ]}
        >
          <DatePicker
            picker="date"
            className="openInput outline-0 w-52 rounded border-0 bg-inputBg px-10 py-3 font-InterMedium opacity-100 shadow-none"
            placeholder="Start date"
            format={dateFormat}
            size={"large"}
          />
        </Form.Item>
      </div>
    </div>
  </div>

  {/* HORIZONTAL RULE */}
  <hr className="mt-7 w-5/6 p-1" />

  {/* STUDENT */}
  <div className="mt-7 mb-3 flex flex-col items-baseline">
    <div className="mb-7 w-60">
      <span className="student font-InterMedium text-base font-medium tracking-widest text-arshGrey opacity-100">
        STUDENT
      </span>
    </div>
  </div>

  {/* STUDENT TIMES */}
  <div className="flex flex-col">
    {/* RESUMPTION */}
    <div className="mt-2 mb-1 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="font-InterMedium text-base font-medium">
          Resumption time
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <Form.Item
        className="w-3/4"
        name={"studentStart"}
        rules={[
          {
            required: true,
            message: "Please input student resumption time",
          },
        ]}
      >
        <TimePicker
          use12Hours
          format="h:mm:ss a"
          className="openInput outline-0 focus:outline-none h-12 w-2/3 rounded border-0 bg-inputBg px-10 py-5 font-InterMedium opacity-100 shadow-none placeholder:font-InterMedium"
          placeholder="Resumption time"
          size={"large"}
        />
      </Form.Item>
    </div>

    {/* CLOSING */}
    <div className="mb-3 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="schName font-InterMedium text-base font-medium">
          Closing time
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <Form.Item
        className="w-3/4"
        name={"studentEnd"}
        rules={[
          {
            required: true,
            message: "Please input student closing time",
          },
        ]}
      >
        <TimePicker
          use12Hours
          format="h:mm:ss a"
          className="openInput outline-0 focus:outline-none h-12 w-2/3 rounded border-0 bg-inputBg px-10 py-5 font-InterMedium opacity-100 shadow-none placeholder:font-InterMedium"
          placeholder="Closing time"
          size={"large"}
        />
      </Form.Item>
    </div>
  </div>

  {/* HORIZONTAL RULE */}
  <hr className="w-5/6 p-1" />

  {/* TEACHERS */}
  <div className="mt-4 mb-3 flex flex-col items-baseline">
    <div className="mb-4 w-60">
      <span className="font-InterMedium text-base font-medium tracking-widest text-arshGrey opacity-100">
        TEACHERS
      </span>
    </div>
  </div>

  {/* TEACHERS RESUMPTION TIME */}
  <div className="flex flex-col">
    {/* RESUMPTION */}
    <div className="mt-2 mb-1 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="schName font-InterMedium text-base font-medium">
          Resumption time
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <Form.Item
        className="w-3/4"
        name={"superStart"}
        rules={[
          {
            required: true,
            message: "Please input teacher resumption time",
          },
        ]}
      >
        <TimePicker
          use12Hours
          format="h:mm:ss a"
          className="openInput outline-0 focus:outline-none h-12 w-2/3 rounded border-0 bg-inputBg px-10 py-5 font-InterMedium opacity-100 shadow-none placeholder:font-InterMedium"
          placeholder="Resumption time"
          size={"large"}
          name="resumptionTime"
        />
      </Form.Item>
    </div>

    {/* CLOSING */}
    <div className="mb-3 flex flex-row items-baseline space-x-12">
      <div className="mb-7 w-1/4">
        <span className="schName font-InterMedium text-base font-medium">
          Closing time
        </span>
      </div>

      {/* RESUMPTION TIME */}
      <Form.Item
        className="w-3/4"
        name={"superEnd"}
        rules={[
          {
            required: true,
            message: "Please input teacher closing time",
          },
        ]}
      >
        <TimePicker
          use12Hours
          format="h:mm:ss a"
          className="openInput outline-0 focus:outline-none h-12 w-2/3 rounded border-0 bg-inputBg px-10 py-5 font-InterMedium opacity-100 shadow-none placeholder:font-InterMedium"
          placeholder="Closing time"
          size={"large"}
        />
      </Form.Item>
    </div>

    <Button
      className="save float-right  h-8 w-auto cursor-pointer place-self-end rounded border border-solid border-regularGreen bg-regularGreen font-InterBold font-medium text-regularWhite opacity-100"
      htmlType="submit"
      size="middle"
      loading={loading}
    >
      {openHrsId === undefined || "" ? "CREATE" : "EDIT"}{" "}
    </Button>
  </div>

  {/* SAVE */}
  <div className="text-end w-full pb-7 text-right"></div>
</Form>

Store result from ajax API call into Var | jQuery

I am able to get result from ajax API Call and want to store result into var, but the result does’t store into var. Please help me to achieve this. Below is the code for ajax response:-

var Name = '';

function webservice_returnResult(apiURL, id) {
    return $.ajax({
        type: 'GET',
        url: baseurl + '/' + apiURL,
        data: { "Id": id },
        dataType: 'JSON',
        //async: true,  //NOT NEEDED
        success: function (response) {
            //Data = response;
        }
    });
}
 
    webservice_returnResult('api/sample/GetById', Id).done(function (result) {
        Name = result.Name;
    });
  
    console.log(Name);

result.Name does’t save into var Name.

empty object returned with a bundled js library with webpack

Attempting to use graphology-layout-forceatlas2 on web.
Couldn’t find a working build online.

Used webpack to create a bundle, however when included it returned an empty object even though there was 10kb of code.

package.json

  "name": "udm",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.96.1",
    "webpack-cli": "^5.1.4"
  }
}

webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js', 
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        library: 'ForceAtlas2',
        libraryTarget: 'umd',
    },
    mode: 'production'
};

src/index.js

const forceAtlas2 = require('graphology-layout-forceatlas2');
window.ForceAtlas2 = forceAtlas2;

bundle.js

!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ForceAtlas2=e():t.ForceAtlas2=e()}(self,(()=>(()=>{var t={435:t=>{t.exports={linLogMode:!1,outboundAttractionDistribution:!1,adjustSizes:!1,edgeWeightInfluence:1,scalingRatio:1,strongGravityMode:!1,gravity:1,slowDown:1,barnesHutOptimize:!1,barnesHutTheta:.5}},924:(t,e)=>{e.assign=function(t){t=t||{};var e,o,n,r=Array.prototype.slice.call(arguments).slice(1);for(e=0,n=r.length;e<n;e++)if(r[e])for(o in r[e])t[o]=r[e][o];return t},e.validateSettings=function(t){return"linLogMode"in t&&"boolean"!=typeof t.linLogMode?{message:"the `linLogMode` setting should be a boolean."}:"outboundAttractionDistribution"in t&&"boolean"!=typeof t.outboundAttractionDistribution?{message:"the `outboundAttractionDistribution` setting should be a boolean."}:"adjustSizes"in t&&"boolean"!=typeof t.adjustSizes?{message:"the `adjustSizes` setting should be a boolean."}:"edgeWeightInfluence"in t&&"number"!=typeof t.edgeWeightInfluence?{message:"the `edgeWeightInfluence` setting should be a number."}:!("scalingRatio"in t)||"number"==typeof t.scalingRatio&&t.scalingRatio>=0?"strongGravityMode"in t&&"boolean"!=typeof t.strongGravityMode?{message:"the `strongGravityMode` setting should be a boolean."}:!("gravity"in t)||"number"==typeof t.gravity&&t.gravity>=0?"slowDown"in t&&!("number"==typeof t.slowDown||t.slowDown>=0)?{message:"the `slowDown` setting should be a number >= 0."}:"barnesHutOptimize"in t&&"boolean"!=typeof t.barnesHutOptimize?{message:"the `barnesHutOptimize` setting should be a boolean."}:!("barnesHutTheta"in t)||"number"==typeof t.barnesHutTheta&&t.barnesHutTheta>=0?null:{message:"the `barnesHutTheta` setting should be a number >= 0."}:{message:"the `gravity` setting should be a number >= 0."}:{message:"the `scalingRatio` setting should be a number >= 0."}},e.graphToByteArrays=function(t,e){var o,n=t.order,r=t.size,i={},a=new Float32Array(10*n),s=new Float32Array(3*r);return o=0,t.forEachNode((function(t,e){i[t]=o,a[o]=e.x,a[o+1]=e.y,a[o+2]=0,a[o+3]=0,a[o+4]=0,a[o+5]=0,a[o+6]=1,a[o+7]=1,a[o+8]=e.size||1,a[o+9]=e.fixed?1:0,o+=10})),o=0,t.forEachEdge((function(t,n,r,u,f,g,l){var h=i[r],c=i[u],d=e(t,n,r,u,f,g,l);a[h+6]+=d,a[c+6]+=d,s[o]=h,s[o+1]=c,s[o+2]=d,o+=3})),{nodes:a,edges:s}},e.assignLayoutChanges=function(t,e,o){var n=0;t.updateEachNodeAttributes((function(t,r){return r.x=e[n],r.y=e[n+1],n+=10,o?o(t,r):r}))},e.readGraphPositions=function(t,e){var o=0;t.forEachNode((function(t,n){e[o]=n.x,e[o+1]=n.y,o+=10}))},e.collectLayoutChanges=function(t,e,o){for(var n=t.nodes(),r={},i=0,a=0,s=e.length;i<s;i+=10){if(o){var u=Object.assign({},t.getNodeAttributes(n[a]));u.x=e[i],u.y=e[i+1],u=o(n[a],u),r[n[a]]={x:u.x,y:u.y}}else r[n[a]]={x:e[i],y:e[i+1]};a++}return r},e.createWorker=function(t){var e=window.URL||window.webkitURL,o=t.toString(),n=e.createObjectURL(new Blob(["("+o+").call(this);"],{type:"text/javascript"})),r=new Worker(n);return e.revokeObjectURL(n),r}},697:(t,e,o)=>{var n=o(154),r=o(183).Fd,i=o(675),a=o(924),s=o(435);function u(t,e,o){if(!n(e))throw new Error("graphology-layout-forceatlas2: the given graph is not a valid graphology instance.");"number"==typeof o&&(o={iterations:o});var u=o.iterations;if("number"!=typeof u)throw new Error("graphology-layout-forceatlas2: invalid number of iterations.");if(u<=0)throw new Error("graphology-layout-forceatlas2: you should provide a positive number of iterations.");var f=r("getEdgeWeight"in o?o.getEdgeWeight:"weight").fromEntry,g="function"==typeof o.outputReducer?o.outputReducer:null,l=a.assign({},s,o.settings),h=a.validateSettings(l);if(h)throw new Error("graphology-layout-forceatlas2: "+h.message);var c,d=a.graphToByteArrays(e,f);for(c=0;c<u;c++)i(l,d.nodes,d.edges);if(!t)return a.collectLayoutChanges(e,d.nodes);a.assignLayoutChanges(e,d.nodes,g)}var f=u.bind(null,!1);f.assign=u.bind(null,!0),f.inferSettings=function(t){var e="number"==typeof t?t:t.order;return{barnesHutOptimize:e>2e3,strongGravityMode:!0,gravity:.05,scalingRatio:10,slowDown:1+Math.log(e)}},t.exports=f},675:t=>{var e=10;t.exports=function(t,o,n){var r,i,a,s,u,f,g,l,h,c,d,b,y,p,m,M,w,v,A,E,x,D,q,L=o.length,R=n.length,z=t.adjustSizes,H=t.barnesHutTheta*t.barnesHutTheta,j=[];for(a=0;a<L;a+=e)o[a+4]=o[a+2],o[a+5]=o[a+3],o[a+2]=0,o[a+3]=0;if(t.outboundAttractionDistribution){for(d=0,a=0;a<L;a+=e)d+=o[a+6];d/=L/e}if(t.barnesHutOptimize){var S,G,T,O=1/0,W=-1/0,k=1/0,F=-1/0;for(a=0;a<L;a+=e)O=Math.min(O,o[a+0]),W=Math.max(W,o[a+0]),k=Math.min(k,o[a+1]),F=Math.max(F,o[a+1]);var N=W-O,U=F-k;for(N>U?F=(k-=(N-U)/2)+N:W=(O-=(U-N)/2)+U,j[0]=-1,j[1]=(O+W)/2,j[2]=(k+F)/2,j[3]=Math.max(W-O,F-k),j[4]=-1,j[5]=-1,j[6]=0,j[7]=0,j[8]=0,r=1,a=0;a<L;a+=e)for(i=0,T=3;;){if(!(j[i+5]>=0)){if(j[i+0]<0){j[i+0]=a;break}if(j[i+5]=9*r,l=j[i+3]/2,j[(h=j[i+5])+0]=-1,j[h+1]=j[i+1]-l,j[h+2]=j[i+2]-l,j[h+3]=l,j[h+4]=h+9,j[h+5]=-1,j[h+6]=0,j[h+7]=0,j[h+8]=0,j[(h+=9)+0]=-1,j[h+1]=j[i+1]-l,j[h+2]=j[i+2]+l,j[h+3]=l,j[h+4]=h+9,j[h+5]=-1,j[h+6]=0,j[h+7]=0,j[h+8]=0,j[(h+=9)+0]=-1,j[h+1]=j[i+1]+l,j[h+2]=j[i+2]-l,j[h+3]=l,j[h+4]=h+9,j[h+5]=-1,j[h+6]=0,j[h+7]=0,j[h+8]=0,j[(h+=9)+0]=-1,j[h+1]=j[i+1]+l,j[h+2]=j[i+2]+l,j[h+3]=l,j[h+4]=j[i+4],j[h+5]=-1,j[h+6]=0,j[h+7]=0,j[h+8]=0,r+=4,S=o[j[i+0]+0]<j[i+1]?o[j[i+0]+1]<j[i+2]?j[i+5]:j[i+5]+9:o[j[i+0]+1]<j[i+2]?j[i+5]+18:j[i+5]+27,j[i+6]=o[j[i+0]+6],j[i+7]=o[j[i+0]+0],j[i+8]=o[j[i+0]+1],j[S+0]=j[i+0],j[i+0]=-1,S===(G=o[a+0]<j[i+1]?o[a+1]<j[i+2]?j[i+5]:j[i+5]+9:o[a+1]<j[i+2]?j[i+5]+18:j[i+5]+27)){if(T--){i=S;continue}T=3;break}j[G+0]=a;break}S=o[a+0]<j[i+1]?o[a+1]<j[i+2]?j[i+5]:j[i+5]+9:o[a+1]<j[i+2]?j[i+5]+18:j[i+5]+27,j[i+7]=(j[i+7]*j[i+6]+o[a+0]*o[a+6])/(j[i+6]+o[a+6]),j[i+8]=(j[i+8]*j[i+6]+o[a+1]*o[a+6])/(j[i+6]+o[a+6]),j[i+6]+=o[a+6],i=S}}if(t.barnesHutOptimize){for(b=t.scalingRatio,a=0;a<L;a+=e)for(i=0;;)if(j[i+5]>=0){if(M=Math.pow(o[a+0]-j[i+7],2)+Math.pow(o[a+1]-j[i+8],2),4*(c=j[i+3])*c/M<H){if(y=o[a+0]-j[i+7],p=o[a+1]-j[i+8],!0===z?M>0?(w=b*o[a+6]*j[i+6]/M,o[a+2]+=y*w,o[a+3]+=p*w):M<0&&(w=-b*o[a+6]*j[i+6]/Math.sqrt(M),o[a+2]+=y*w,o[a+3]+=p*w):M>0&&(w=b*o[a+6]*j[i+6]/M,o[a+2]+=y*w,o[a+3]+=p*w),(i=j[i+4])<0)break;continue}i=j[i+5]}else if((f=j[i+0])>=0&&f!==a&&(M=(y=o[a+0]-o[f+0])*y+(p=o[a+1]-o[f+1])*p,!0===z?M>0?(w=b*o[a+6]*o[f+6]/M,o[a+2]+=y*w,o[a+3]+=p*w):M<0&&(w=-b*o[a+6]*o[f+6]/Math.sqrt(M),o[a+2]+=y*w,o[a+3]+=p*w):M>0&&(w=b*o[a+6]*o[f+6]/M,o[a+2]+=y*w,o[a+3]+=p*w)),(i=j[i+4])<0)break}else for(b=t.scalingRatio,s=0;s<L;s+=e)for(u=0;u<s;u+=e)y=o[s+0]-o[u+0],p=o[s+1]-o[u+1],!0===z?(M=Math.sqrt(y*y+p*p)-o[s+8]-o[u+8])>0?(w=b*o[s+6]*o[u+6]/M/M,o[s+2]+=y*w,o[s+3]+=p*w,o[u+2]-=y*w,o[u+3]-=p*w):M<0&&(w=100*b*o[s+6]*o[u+6],o[s+2]+=y*w,o[s+3]+=p*w,o[u+2]-=y*w,o[u+3]-=p*w):(M=Math.sqrt(y*y+p*p))>0&&(w=b*o[s+6]*o[u+6]/M/M,o[s+2]+=y*w,o[s+3]+=p*w,o[u+2]-=y*w,o[u+3]-=p*w);for(h=t.gravity/t.scalingRatio,b=t.scalingRatio,a=0;a<L;a+=e)w=0,y=o[a+0],p=o[a+1],M=Math.sqrt(Math.pow(y,2)+Math.pow(p,2)),t.strongGravityMode?M>0&&(w=b*o[a+6]*h):M>0&&(w=b*o[a+6]*h/M),o[a+2]-=y*w,o[a+3]-=p*w;for(b=1*(t.outboundAttractionDistribution?d:1),g=0;g<R;g+=3)s=n[g+0],u=n[g+1],l=n[g+2],m=Math.pow(l,t.edgeWeightInfluence),y=o[s+0]-o[u+0],p=o[s+1]-o[u+1],!0===z?(M=Math.sqrt(y*y+p*p)-o[s+8]-o[u+8],t.linLogMode?t.outboundAttractionDistribution?M>0&&(w=-b*m*Math.log(1+M)/M/o[s+6]):M>0&&(w=-b*m*Math.log(1+M)/M):t.outboundAttractionDistribution?M>0&&(w=-b*m/o[s+6]):M>0&&(w=-b*m)):(M=Math.sqrt(Math.pow(y,2)+Math.pow(p,2)),t.linLogMode?t.outboundAttractionDistribution?M>0&&(w=-b*m*Math.log(1+M)/M/o[s+6]):M>0&&(w=-b*m*Math.log(1+M)/M):t.outboundAttractionDistribution?(M=1,w=-b*m/o[s+6]):(M=1,w=-b*m)),M>0&&(o[s+2]+=y*w,o[s+3]+=p*w,o[u+2]-=y*w,o[u+3]-=p*w);if(!0===z)for(a=0;a<L;a+=e)1!==o[a+9]&&((v=Math.sqrt(Math.pow(o[a+2],2)+Math.pow(o[a+3],2)))>10&&(o[a+2]=10*o[a+2]/v,o[a+3]=10*o[a+3]/v),A=o[a+6]*Math.sqrt((o[a+4]-o[a+2])*(o[a+4]-o[a+2])+(o[a+5]-o[a+3])*(o[a+5]-o[a+3])),E=Math.sqrt((o[a+4]+o[a+2])*(o[a+4]+o[a+2])+(o[a+5]+o[a+3])*(o[a+5]+o[a+3]))/2,x=.1*Math.log(1+E)/(1+Math.sqrt(A)),D=o[a+0]+o[a+2]*(x/t.slowDown),o[a+0]=D,q=o[a+1]+o[a+3]*(x/t.slowDown),o[a+1]=q);else for(a=0;a<L;a+=e)1!==o[a+9]&&(A=o[a+6]*Math.sqrt((o[a+4]-o[a+2])*(o[a+4]-o[a+2])+(o[a+5]-o[a+3])*(o[a+5]-o[a+3])),E=Math.sqrt((o[a+4]+o[a+2])*(o[a+4]+o[a+2])+(o[a+5]+o[a+3])*(o[a+5]+o[a+3]))/2,x=o[a+7]*Math.log(1+E)/(1+Math.sqrt(A)),o[a+7]=Math.min(1,Math.sqrt(x*(Math.pow(o[a+2],2)+Math.pow(o[a+3],2))/(1+Math.sqrt(A)))),D=o[a+0]+o[a+2]*(x/t.slowDown),o[a+0]=D,q=o[a+1]+o[a+3]*(x/t.slowDown),o[a+1]=q);return{}}},183:(t,e)=>{function o(t){return"number"!=typeof t||isNaN(t)?1:t}e.Fd=function(t){return function(t,e){var o={},n=function(t){return void 0===t?e:t};"function"==typeof e&&(n=e);var r=function(e){return n(e[t])},i=function(){return n(void 0)};return"string"==typeof t?(o.fromAttributes=r,o.fromGraph=function(t,e){return r(t.getEdgeAttributes(e))},o.fromEntry=function(t,e){return r(e)},o.fromPartialEntry=o.fromEntry,o.fromMinimalEntry=o.fromEntry):"function"==typeof t?(o.fromAttributes=function(){throw new Error("graphology-utils/getters/createEdgeValueGetter: irrelevant usage.")},o.fromGraph=function(e,o){var r=e.extremities(o);return n(t(o,e.getEdgeAttributes(o),r[0],r[1],e.getNodeAttributes(r[0]),e.getNodeAttributes(r[1]),e.isUndirected(o)))},o.fromEntry=function(e,o,r,i,a,s,u){return n(t(e,o,r,i,a,s,u))},o.fromPartialEntry=function(e,o,r,i){return n(t(e,o,r,i))},o.fromMinimalEntry=function(e,o){return n(t(e,o))}):(o.fromAttributes=i,o.fromGraph=i,o.fromEntry=i,o.fromMinimalEntry=i),o}(t,o)}},154:t=>{t.exports=function(t){return null!==t&&"object"==typeof t&&"function"==typeof t.addUndirectedEdgeWithKey&&"function"==typeof t.dropNode&&"boolean"==typeof t.multi}}},e={};const o=function o(n){var r=e[n];if(void 0!==r)return r.exports;var i=e[n]={exports:{}};return t[n](i,i.exports,o),i.exports}(697);return window.ForceAtlas2={assign:o.assign,inferSettings:o.inferSettings,DEFAULTS:o.DEFAULTS},{}})()));```

Safari extension – context menu item renders TWICE

I render three new context menu items through a Safari extension like this:

browser.contextMenus.create({
  id: 'copy-this',
  title: 'Copy this',
  contexts: ['selection', 'link']
});

browser.contextMenus.create({
  id: 'copy-that',
  title: 'Copy that',
  contexts: ['selection', 'link']
});

browser.contextMenus.create({
  id: 'do-this',
  title: 'Do this',
  contexts: ['selection', 'link']
});

When right clicking on regular text, these menu items render fine. Just once per.

I don’t even specify editable contexts, and yet when the user right clicks on text in a textarea, say, the above menu items render twice.

Ideally, they shouldn’t render at all in editable contexts. How do I do that?

How would I import a spine image, .json file, and a .atlas file into an HTML Document to display an animated model?

I’m wondering how I would be able to import something from Gimkit into a site I’m creating without having to download the actual file itself, and I’m trying to use a singular HTML Document to make my site. The animated previews use a spritesheet-like thing made in Spine, a .json file, and a .atlas file. I am hoping to eventually make this usable for all filenames, but for this example, I need to use the filename “dayOne”. The spritesheet can be found at https://www.gimkit.com/assets/map/characters/spine/dayOne-v2.32.png, the .json file can be found at https://www.gimkit.com/assets/map/characters/spine/dayOne.json?cb=410516585127, and the .atlas file can be found at
https://www.gimkit.com/assets/map/characters/spine/dayOne.atlas?cb=410516585127. If anyone could do this for me, I would be forever thankful! Thanks!

I have tried several things, but I honestly have no clue on what to do with this. I tried this, based on some information I previously found online, but is doesn’t work. If you could help me, that’d be great!

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sprite Test I Guess</title>
<style>     
.sprite-container {       
width: 64px;       
height: 64px;       
background-image: none;       
background-position: 0 0;       
animation: playAnimation 1s steps(16) infinite;       
border: 1px solid black;     
}     
@keyframes playAnimation {       
100% {         
background-position: -1024px 0;       
}     
}   
</style> 
</head> 
<body>   
<div class="sprite-container"></div>   
<script>     
const proxyUrl = 'https://api.allorigins.win/raw?url=';     
const spriteSheetUrl = 'https://www.gimkit.com/assets/map/characters/spine/dayOne-v2.32.png';     
const jsonUrl = 'https://www.gimkit.com/assets/map/characters/spine/dayOne.json?cb=410516585127';     
const atlasUrl = 'https://www.gimkit.com/assets/map/characters/spine/dayOne.atlas?cb=410516585127';     
fetch(proxyUrl + encodeURIComponent(spriteSheetUrl))       
.then(response => {         
if (!response.ok) {           
throw new Error('Network response was not ok for spritesheet');         
}         
return response.blob();       
})       
.then(blob => {         
const imgUrl = URL.createObjectURL(blob);         
const spriteContainer = document.querySelector('.sprite-container');         
spriteContainer.style.backgroundImage = `url(${imgUrl})`;       
})       
.catch(error => {         
console.error('There was a problem fetching the spritesheet:', error);       
});     
fetch(proxyUrl + encodeURIComponent(jsonUrl))       
.then(response => response.json())       
.then(jsonData => {         
console.log('JSON data loaded:', jsonData);       
})       
.catch(error => {         
console.error('Error loading the JSON data:', error);       
});     
fetch(proxyUrl + encodeURIComponent(atlasUrl))       
.then(response => response.text())       
.then(atlasData => {         
console.log('Atlas data loaded:', atlasData);       
})       .catch(error => {         
console.error('Error loading the .atlas data:', error);       
});   
</script>
</body>
</html>

ie8 click on button trigger select’s ondbclick, could do it?

ie8 click on button then trigger select’s ondbclick, could do it? actually,that is a ie8 watermark mask penetrate problem

button.attachEvent('onclick',function(e){
    var currentDom = e.srcElement;
    var point = document.elementsFromPoint(e.clientX, e.clientY);
    if(point.tagName.toLowerCase() == 'select') {
        point.focus()
        // trigger select's dbclick function
        .....
    }
})
<select ondbclick="changeSelct(this);">
  <option>a</option>
  <option>b</option>
</select>

so anyone give me some suggestions

JS WebWorker – How to transfer ArrayBuffer from worker to main

Transfer ArrayBuffer from main.js to worker.js work as expected:
after sending ArrayBuffer is no longer usable in main.js.

// main.js

const array = new Uint32Array(1_000_000).map((v, i) => i);
console.log(array.byteLength); // 4000000

const worker = new Worker(new URL('worker.js', import.meta.url), { type: 'module' });
worker.postMessage(array, [array.buffer]);

console.log(array.byteLength); // 0 <= GOOD, as expected

But transferring ArrayBuffer from worker.js to main.js doesn’t work as expected:
after sending ArrayBuffer is still usable in worker.js.

// worker.js

onmessage = function handleMessageFromMain(msg) {
    const array = new Uint32Array(1_000_000).map((v, i) => i);
    console.log(array.byteLength); // 4000000

    postMessage(array, null, [array.buffer]);

    console.log(array.byteLength); // 4000000 <= BAD, must be 0
};

How to transfer ArrayBuffer from worker to main?

how to draw polygons on image with vue/javascripts

I have an image with boxes and codes on each pox. I send it to Google Vision and get a response.
Then I display the list of buttons for each “product code”. On click, it should use “product code” to find its coordinates from the response list and draw a polygon on the image to highlight the box with that “product code”.
I follow mdn documentation on how to draw polygons but it does not work. Please help.

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.5.4/vue.global.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <title>Scan</title>
    <style>
        .form-group {
            margin-bottom: 1rem;
        }

        .code-button {
            margin: 5px;
        }
    </style>
</head>
<body>
    <div id="scan" class="container">
        <div class="row">
            <div class="col-md-12">
                <h1>Scan</h1>
                <div class="form-group">
                    <label for="image">Image</label>
                    <input type="file" accept="image/*" class="form-control" id="image" name="image" @change="handleFileUpload">
                </div>
                <div class="form-group">
                    <button v-if="isImageSelected" class="btn btn-warning" @click="restartImage">Restart Image</button>
                    <button class="btn btn-success" @click="sendImage">Submit</button>
                </div>
                <div style="position: relative; width: 640px; height: 480px;">
                    <canvas id="canvas" width="640" height="480" style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
                    <img id="preview" src="" alt="Preview" class="img-fluid" style="position: absolute; top: 0; left: 0; z-index: 0;">
                </div>
                <div id="results"></div>
                <div id="code-buttons">
                    <button v-for="code in codeList" :key="code" class="code-button" @click="highlightBox(code)">
                        [[ code ]]
                    </button>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>

    <script>
        const response = {
            "product_codes": [
                {
                    "code": "697902",
                    "bounding_poly": [
                        [574, 1250],
                        [766, 1256],
                        [765, 1282],
                        [573, 1276]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [762, 1390],
                        [960, 1384],
                        [961, 1413],
                        [763, 1419]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [673, 1570],
                        [880, 1579],
                        [878, 1612],
                        [672, 1603]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [364, 1792],
                        [573, 1796],
                        [572, 1825],
                        [364, 1821]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [640, 1796],
                        [848, 1779],
                        [851, 1811],
                        [643, 1828]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [1066, 1390],
                        [1248, 1388],
                        [1248, 1412],
                        [1066, 1414]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [942, 1784],
                        [1150, 1770],
                        [1152, 1800],
                        [944, 1814]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [631, 2039],
                        [848, 2024],
                        [850, 2053],
                        [633, 2068]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [1231, 1807],
                        [1445, 1809],
                        [1445, 1840],
                        [1231, 1838]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [1221, 2047],
                        [1439, 2032],
                        [1442, 2069],
                        [1224, 2084]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [591, 2295],
                        [811, 2275],
                        [814, 2309],
                        [594, 2329]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [904, 2296],
                        [1126, 2294],
                        [1126, 2327],
                        [904, 2329]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [216, 2572],
                        [444, 2543],
                        [449, 2581],
                        [221, 2611]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [561, 2558],
                        [788, 2546],
                        [790, 2582],
                        [563, 2594]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [897, 2559],
                        [1119, 2547],
                        [1121, 2586],
                        [899, 2598]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [2159, 2223],
                        [2384, 2237],
                        [2381, 2271],
                        [2157, 2257]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [3293, 2021],
                        [3513, 2024],
                        [3513, 2056],
                        [3293, 2053]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [3411, 2289],
                        [3641, 2289],
                        [3641, 2321],
                        [3411, 2321]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [2133, 2490],
                        [2361, 2509],
                        [2358, 2543],
                        [2130, 2525]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [3801, 2508],
                        [4030, 2503],
                        [4031, 2537],
                        [3802, 2542]
                    ]
                },
                {
                    "code": "697902",
                    "bounding_poly": [
                        [3464, 2534],
                        [3698, 2541],
                        [3697, 2577],
                        [3463, 2570]
                    ]
                }
            ]
        };

        const { createApp } = Vue;

        createApp({
            delimiters: ['[[', ']]'],
            data() {
                return {
                    canvas: null,
                    context: null,
                    isImageSelected: false,
                    capturedImage: null,
                    response: response,
                    codeList: [...new Set(response.product_codes.map(item => item.code))]
                }
            },
            methods: {
                handleFileUpload(event) {
                    const file = event.target.files[0];
                    const reader = new FileReader();
                    reader.onload = (e) => {
                        this.capturedImage = e.target.result;
                        document.getElementById('preview').src = this.capturedImage;
                        document.getElementById('preview').style.display = 'block';
                        this.isImageSelected = true;
                    };
                    reader.readAsDataURL(file);
                },
                sendImage() {
                    this.drawPolygons();
                },
                restartImage() {
                    // Clear states
                    this.isImageSelected = false;
                    document.getElementById('preview').src = '';
                    document.getElementById('preview').style.display = 'none';
                    document.getElementById('results').innerHTML = '';
                    this.capturedImage = null;
                },
                drawPolygons() {
                    const canvas = document.getElementById('canvas');
                    const ctx = canvas.getContext('2d');
                    if (!ctx) {
                        console.error('Failed to get canvas context');
                        return;
                    }
                    const preview = document.getElementById('preview');
                    canvas.width = preview.width;
                    canvas.height = preview.height;
                    canvas.style.display = 'block'; // Ensure canvas is visible

                    this.response.product_codes.forEach(item => {
                        this.drawPolygon(item.bounding_poly, 'rgba(0, 255, 0, 0.5)');
                    });
                },
                drawPolygon(points, color) {
                    const canvas = document.getElementById('canvas');
                    const ctx = canvas.getContext('2d');
                    if (!ctx) {
                        console.error('Failed to get canvas context');
                        return;
                    }
                    ctx.fillStyle = color;
                    ctx.beginPath();
                    ctx.moveTo(points[0][0], points[0][1]);
                    points.slice(1).forEach(point => {
                        ctx.lineTo(point[0], point[1]);
                    });
                    ctx.closePath();
                    ctx.fill();
                },
                highlightBox(code) {
                    console.log('Highlighting box for code:', code);
                    const canvas = document.getElementById('canvas');
                    const ctx = canvas.getContext('2d');
                    if (!ctx) {
                        console.error('Failed to get canvas context');
                        return;
                    }
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    this.drawPolygons();

                    const pointsArray = this.response.product_codes
                        .filter(item => item.code === code)
                        .map(item => item.bounding_poly);
                    console.log('Points array:', pointsArray);
                    pointsArray.forEach(points => {
                        this.drawPolygon(points, 'rgba(255, 0, 0, 0.5)');
                    });
                }
            }
        }).mount('#scan');
    </script>
</body>
</html>

Drag and drop items from different groups

I am using PrimeNG table and group reorder.

Currently, it is possible to drag and drop items within the same group, but dragging and dropping items from one group to another is not accurate yet. How can I identify which group I am dropping into?

MY CODE

Data

this.data = [
      {
        id: 1,
        groupOrder: 1,
        group_by: { name: 'Manager', id: 1 },
        name: 'Manager 1',
        title: '1.1 Manager 1',
      },
      {
        id: 2,
        code: 1.2,
        groupOrder: 1,
        group_by: { name: 'Manager', id: 1 },
        name: 'Manager 2 ',
        title: '1.2 Manager 2',
      },
      {
        id: 3,
        groupOrder: 2,
        group_by: { name: 'Support', id: 2 },
        name: 'Support tel',
        title: '2.1 Support',
      },
      {
        id: 4,
        groupOrder: 2,
        group_by: { name: 'Support', id: 2 },
        name: 'Support app',
        title: '2.2 Support',
      },
    ];

TS:

function array_move(arr, old_index, new_index) {
  if (new_index >= arr.length) {
    var k = new_index - arr.length + 1;
    while (k--) {
      arr.push(undefined);
    }
  }
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
  return arr; // for testing
}

rowTrackBy(_, item: any) {
    return item.id;
  }

  onRowReorder(data: any) {
    array_move(this.data, data.dragIndex, data.dropIndex);
  }

HTML:

<div class="card">
  <p-table
    [value]="data"
    sortMode="single"
    [scrollable]="true"
    [rowTrackBy]="rowTrackBy"
    rowGroupMode="subheader"
    groupRowsBy="group_by.id"
    (onRowReorder)="onRowReorder($event)"
  >
    <ng-template pTemplate="header">
      <tr>
        <th>#</th>
        <th>item</th>
      </tr>
    </ng-template>

    <ng-template pTemplate="groupheader" let-item>
      <tr pRowGroupHeader>
        <td colspan="100" class="font-weight-bold">{{ item.group_by.name }}</td>
      </tr>
    </ng-template>

    <ng-template pTemplate="body" let-item let-rowIndex="rowIndex">
      <tr pDraggable="item" [pReorderableRow]="rowIndex">
        <td>
          <span class="pi pi-bars" pReorderableRowHandle></span>
        </td>
        <td>{{ item.code }} {{ item.name }}</td>
      </tr>
    </ng-template>
  </p-table>
</div>
<pre>{{data | json}}</pre>

and this full code

https://stackblitz.com/edit/2s4ltq-pfulh5?file=src%2Fapp%2Ftable-subheader-grouping-demo.html,src%2Fapp%2Ftable-subheader-grouping-demo.ts