שמירת נתונים בטבלה )HTML( על ידי שימוש בlocalstorage [closed]

יש לי טבלה בhtml ויש לי כפתור שמוסיף שורה בכל לחיצה עליו ויש לי כפתור ששמור את כל הנתונים בטבלה בlocalstorage הבעיה שבכל פעם שאני מוסיף שורה הוא לא מצליח לשמור
הנה קוד הjavascript שלי:

וגם אם מישהו יודע איך אפשר לשמור תמונה בlocalstorage אני אשמח

function addRow() {
    var table = document.getElementById("myTable");
    var row = table.insertRow();
    var cell1 = row.insertCell();
    var cell2 = row.insertCell();
    var cell3 = row.insertCell();
    var cell4 = row.insertCell();
    var cell5 = row.insertCell();
  
    var input = document.createElement("input");
    input.type = "file";
    input.accept = "image/*";
    input.onchange = uploadFile;
    cell1.appendChild(input);
    cell2.innerHTML = '<input type="text" placeholder="שם מוצר">';
    cell3.innerHTML = '<input type="text" placeholder="מחיר מוצר" pattern="[0-9]*">';
    cell4.innerHTML = '<input type="text" placeholder="תיאור מוצר">';
    cell5.innerHTML = '<button type="button" onclick="deleteRow(this)">מחק</button>';
  
    saveData();


function deleteRow(button) {
    var row = button.parentNode.parentNode;
    row.parentNode.removeChild(row);
}

function saveData() {
    var table = document.getElementById("myTable");
    var products = [];
    for (var i = 1, row; row = table.rows[i]; i++) {
      var product = {
        image: row.cells[0].getElementsByTagName('img')[0].src,
        name: row.cells[1].getElementsByTagName('input')[0].value,
        price: row.cells[2].getElementsByTagName('input')[0].value,
        description: row.cells[3].getElementsByTagName('input')[0].value
      };
      products.push(product);
    }
    localStorage.setItem('products', JSON.stringify(products));
  }



function uploadFile(event) {
    var file = event.target.files[0];
    var reader = new FileReader();
    reader.onload = function(e) {
        var image = document.createElement("img");
        image.src = e.target.result;
        image.style.maxWidth = "120px";
        image.style.maxHeight = "120px";
        var cell = event.target.parentNode.parentNode;
        cell.innerHTML = "";
        cell.appendChild(image);
    };
    reader.readAsDataURL(file);
}

function loadData() {
    var table = document.getElementById("myTable");
    var data = localStorage.getItem("products");

    // ניקוי הטבלה מכל השורות הקיימות לפני טעינת הנתונים
    while (table.rows.length > 1) {
        table.deleteRow(1);
    }

    if (data) {
        data = JSON.parse(data);
        for (var i = 0; i < data.length; i++) {
            var row = table.insertRow();
            var cell1 = row.insertCell();
            var cell2 = row.insertCell();
            var cell3 = row.insertCell();
            var cell4 = row.insertCell();
            var cell5 = row.insertCell();

            cell1.innerHTML = '<img src="' + data[i].image + '" alt="Product Image" style="max-width: 120px; max-height: 120px;">';
            cell2.innerHTML = '<input type="text" placeholder="שם מוצר" value="' + data[i].name + '">';
            cell3.innerHTML = '<input type="text" placeholder="מחיר מוצר" pattern="[0-9]*" value="' + data[i].price + '">';
            cell4.innerHTML = '<input type="text" placeholder="תיאור מוצר" value="' + data[i].description + '">';
            cell5.innerHTML = '<button type="button" onclick="deleteRow(this)">מחק</button>';
        }
    }
}

loadData();

ניסיתי להחליף בין הסדר ההפעלה של הפונקציות וזה לא עזר אגב את רוב הקוד בניתי בעזרת chat gpt אבל את החלק הזה הוא לא הצליח לתקן לי ניסיתי גם בgoogle bard וגם בedge ai

Proper way to import JSLib into k6.io tests

I tried to follow guide of k6.io to import JS modules in the test:

https://jslib.k6.io/

enter image description here

My js tests can’t load:

import { uuidv4 } from “https://jslib.k6.io/k6-utils/1.4.0/index.j”

//@ts-check
import http from "k6/http";
import { check } from "k6";
import { Counter } from "k6/metrics";
import { jsonRequest } from "../data/createNode.js";
import { uuidv4 } from "https://jslib.k6.io/k6-utils/1.4.0/index.j"


//counter for http codes
var http200 = new Counter("HTTP_200_counter")
var error400 = new Counter("HTTP_400_error_counter")
var error500 = new Counter("HTTP_500_error_counter")

enter image description here

Question About JavaScript Global Variables in Functions

I keep getting an error when trying to declare variables outside of the function.

I made a button where text increments +1 on click but why does this work

let count = 0

function increment() {
    const countEl = document.getElementById('incrementBtn')
    countEl.innerText = count
    console.log("The button was clicked")
    count++
}

But this doesn’t? shouldn’t the variable be able to be called because its global?

let count = 0
let countEl

countEl = document.getElementById('incrementBtn')

function increment() {
    countEl.innerText = count
    console.log(countEl)
    console.log("The button was clicked")
    count++
}

Pakistani Escorts in Dubai +971581705103 Dubai escorts Service

Pakistani Escorts in Dubai +971581705103 Dubai escorts Service

| +971562430093 |
If you are in Dubai and looking for Call girls for enjoyment. Don’t book anyone blindly. Check whether they are genuine or not. As compared to other call girls. We have a separate customer review section for every Call girl in Dubai . All reviews are written by their clients. If you book an appointment with us. You will be going to meet the same girl as in the pictures.
Have you been looking for an Call girls agency that will be an answer to all your carnal urges? Are you tired of looking for the best agency in Dubai ? If yes, your search must end here.
Hi guys, I am the naughty 22-year-old independent call girl of your dreams. My body is an open invitation to paradise, I have an exquisitely curvy body and smooth skin that you will love when you touch.
I love to play and fill each client with pleasure, we will enjoy a delicious and intense meeting. It will be an unforgettable experience and what I like most on a date is to make you enjoy to the fullest.
As a lover, I offer a very pleasant time, my services are very complete, with me you can enjoy to the fullest. I’ll give myself up completely and leave you with a taste of wanting more after our hot sex session.
Dubai call girls, Call Girls in Dubai , indian Call Girls in Dubai , pakistani Call Girls in Dubai , Dubai escorts, Dubai Call Girls number, indian Call Girls numbers, pakistani Call Girls numbers, paid sex in Dubai , girls for Sex is also an art form, it is delightful and tasty with passion for another person, with me you will experience it. I leave you super relaxed, come and experience and delight completely.I am a lover who is very involved and who will do everything in my hands so that you have the most intense orgasm of your life. I will provide you with all the pleasure you need. We’ll have true sex and passion to the maximum,

does cancelAnimationFrame clear any existing requestAnimationFrame queues?

does cancelanimationframe completely removes all the queued up animation logic? for example, lets say the logic was complicated and my screen was doing 60fps. the time it took to complete the entire logic per frame, lets say is 50ms. That is much more than 16.66667ms which is the minimum to maintain 60fps.
if each frame takes 50ms in a total of 60 frames, there would be a build up of the animation logic queue. right?
normally, at 60fps, with 60 frames, the entire animation should take 1 second. right?
but with my animation logic, it will take 3 seconds total to complete the animation.

lets assume , after I start the animation at t0, and I wait until t1.5 while animation is ongoing, and I run the cancelAnimationFrame function, will it stop the animation right then and there? or will it complete the entire animation until 3 seconds has passed?

what about if i run the cancelAnimationFrame function at t0.5? will it stop the animation right then and there? or will it complete halfway of the animation until 1.5 seconds has passed?

Why is node-firebird giving a password error only when running many queries in succession?

I am trying to run multiple queries in a row using node-firebird, using Firebird 4.0 on Windows. In isql, I make a simple test database:

SQL> create database 'temp.fdb' page_size 8192 user SYSDBA password 'masterkey';
SQL> create table stuff( id int not null primary key, val int);
SQL> insert into stuff values(0, 0);

To simulate running multiple queries, I use a the following loop, based on an example from the node-firebird docs:

var Firebird = require('node-firebird');

for (let i = 0; i < 3; ++i) {
    console.log('running ' + i)
    var options = {};

    options.host = '127.0.0.1';
    options.port = 3050;
    options.database = <path to the database i just made>
    options.user = 'SYSDBA';
    options.password = 'masterkey';
    options.retryConnectionInterval = 1000; // reconnect interval in case of connection drop
    options.blobAsText = false; // set to true to get blob as text, only affects blob subtype 1

    Firebird.attach(options, function(err, db) {
        if (err)
            throw err;

        // db = DATABASE
        db.query('SELECT * FROM stuff', function(err, result) {
            if (err) {
                throw err;
            }
            // IMPORTANT: close the connection
            db.detach();
            console.log('connection closed: ' + i);
        });

    });
}

This runs as expected:

running 0
running 1
running 2
connection closed: 0
connection closed: 2
connection closed: 1

However, when I increase the number of iterations in the loop, it tells me the username and password are not defined:

running 0
running 1
running 2
running 3
running 4
running 5
running 6
running 7
running 8
running 9
C:<...>node-firebirdlibindex.js:3454
        throw err;
        ^

Error: Your user name and password are not defined. Ask your database
administrator to set up a Firebird login

    at doCallback (C:<...>node_modulesnode-firebirdlibindex.js:1360:21)
    at C:<...>node_modulesnode-firebirdlibindex.js:3138:21
    at loop (C:<...>node_modulesnode-firebirdlibindex.js:3198:29)
    at parseOpResponse (C:<...>node_modulesnode-firebirdlibindex.js:3481:29)
    at decodeResponse (C:<...>node_modulesnode-firebirdlibindex.js:3203:24)
    at Socket.<anonymous> (C:<...>node_modulesnode-firebirdlibindex.js:3115:13)
    at Socket.emit (node:events:512:28)
    at addChunk (node:internal/streams/readable:343:12)
    at readableAddChunk (node:internal/streams/readable:316:9)
    at Readable.push (node:internal/streams/readable:253:10) {
  gdscode: 335544472,
  gdsparams: undefined
}

Node.js v20.4.0

This error confuses me, since the username and password works when I’m only running as few queries. How can I fix this so that I can run many queries in a row?

I need a random number generator that picks a file and then uses that file name in my code

I have an html site and I part of what I want it to do is select a file at random from a large folder of files on my PC. What I’ve decided I want to do is have all the files simply named 1, 2, 3, 4 etc. and then have a random number generator to pick a number and that can put that filename into my code somehow? Except I don’t really know how to do that and I need some help.

I can make a random number generator but I do not know how to get it to pull the file so I haven’t tried anything yet.

How do i deal with the error “Uncaught ReferenceError: require is not defined”?

I have been struggling with publishing my website to github pages.After publishing, the page just shows a blank page with a dark color which is my websites background color.In the console there is the following error “Uncaught ReferenceError: require is not defined”. When in development on localhost everything works as expected.Link to the website
Link to the repository

I read a question here and it encouraged not using commonjs ie “import React, {useState, useEffect} from ‘react'” which i did but this did not change anything the question

Issue with animation not starting from the correct point

I am making a feature on an app which allows the user to perform breathing exercises to do this I am using CSS animations. My issue is that I want to display exhale and inhale when an animation of a circle is shrinking and enlarging but my animation does start from the same point each time so this causes issues with the word that is displayed.

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <title>Asthma App Breathing Exercise page</title>
    <link rel="stylesheet" href="CSS/normalize.css">
    <link rel="stylesheet" href="CSS/breathingExercises.css">
</head>
<body>
<div class="container">
    <h1>Breathing Exercises</h1>

    <div class="dropdown">
        <button class="button" onclick="toggleDropdown()">Select Exercise</button>
        <div id="dropdown-content" class="dropdown-content">
            <a href="#" onclick="selectExercise('exercise1')">Exercise 1</a>
            <a href="#" onclick="selectExercise('exercise2')">Exercise 2</a>
            <a href="#" onclick="selectExercise('exercise3')">Exercise 3</a>
            <a href="#" onclick="selectExercise('exercise4')">Exercise 4</a>
        </div>
    </div>

    <div id="exercise1" class="exercise">
        <h2>Exercise 1</h2>
        <p>This is the description for Exercise 1.</p>
        <div class="circle-wrapper">
            <div id="circle1" class="circle"></div>
        </div>
        <div id="timer1" class="timer"></div>
        <button class="start-button" onclick="startAnimation('circle1', 10000, 5, 'timer1')">Start</button>
    </div>

    <div id="exercise2" class="exercise" style="display: none;">
        <h2>Exercise 2</h2>
        <p>This is the description for Exercise 2.</p>
        <div class="circle-wrapper">
            <div id="circle2" class="circle"></div>
        </div>
        <div id="timer2" class="timer"></div>
        <button class="start-button" onclick="startAnimation('circle2', 6000, 3, 'timer2')">Start</button>
    </div>

    <div id="exercise3" class="exercise" style="display: none;">
        <h2>Exercise 3</h2>
        <p>This is the description for Exercise 3.</p>
        <div class="circle-wrapper">
            <div id="circle3" class="circle"></div>
        </div>
        <div id="timer3" class="timer"></div>
        <button class="start-button" onclick="startAnimation('circle3', 8000, 2, 'timer3')">Start</button>
    </div>

    <div id="exercise4" class="exercise" style="display: none;">
        <h2>Exercise 4</h2>
        <p>This is the description for Exercise 4.</p>
        <div class="circle-wrapper">
            <div id="circle4" class="circle"></div>
        </div>
        <div id="timer4" class="timer"></div>
        <button class="start-button" onclick="startAnimation('circle4', 4000, 10, 'timer4')">Start</button>
    </div>
</div>

<script>
    function toggleDropdown() {
        var dropdownContent = document.getElementById("dropdown-content");
        dropdownContent.classList.toggle("show");
    }

    var timer;

    function selectExercise(exerciseId) {
        // Hide all exercises
        var exercises = document.getElementsByClassName("exercise");
        for (var i = 0; i < exercises.length; i++) {
            exercises[i].style.display = "none";
        }

        // Reset animation for all circles
        var circles = document.getElementsByClassName("circle");
        for (var i = 0; i < circles.length; i++) {
            circles[i].style.animationDuration = "0ms";
            circles[i].innerHTML = "Inhale";
            circles[i].classList.remove("reset-animation");
            void circles[i].offsetWidth; // Trigger reflow to apply the class immediately
            circles[i].classList.add("reset-animation");
        }


        // Show selected exercise
        var selectedExercise = document.getElementById(exerciseId);
        selectedExercise.style.display = "block";

        var dropdownContent = document.getElementById("dropdown-content");
        dropdownContent.classList.remove("show");

        clearInterval(timer);

        var timerElement = document.getElementById("timer" + exerciseId.slice(-1));
        timerElement.innerHTML = "";
    }

    function startAnimation(circleId, duration, totalCycles, timerId) {
        var circle = document.getElementById(circleId);
        var cycles = 0;
        var remainingTime = duration * totalCycles;
        var inhaleTime = duration / 2;
        var exhaleTime = duration / 2;

        clearInterval(timer);

        animate();

        function animate() {
            circle.innerHTML = "Inhale";
            setTimeout(function() {
                circle.innerHTML = "Exhale";
                setTimeout(function() {
                    circle.innerHTML = "Inhale";
                    cycles++;
                    if (cycles < totalCycles) {
                        animate(); // Start the next cycle
                    } else {
                        circle.style.animationDuration = "0ms"; // Stop the animation
                    }
                }, inhaleTime);
            }, exhaleTime);
        }

        circle.style.animationDuration = duration + "ms";

        var timerElement = document.getElementById(timerId);
        timerElement.innerHTML = "Time left: " + (remainingTime / 1000) + " seconds";

        timer = setInterval(function() {
            remainingTime -= 1000;
            if (remainingTime <= 0) {
                clearInterval(timer);
                timerElement.innerHTML = "Time left: 0 seconds";
            } else {
                timerElement.innerHTML = "Time left: " + (remainingTime / 1000) + " seconds";
            }
        }, 1000);
    }

    selectExercise('exercise1', 4000);
</script>
</body>
</html>
body {
    background: #005eb8;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    font-family: "Helvetica Neue", Arial, sans-serif;
}

.container {
    max-width: 350px;
    margin: 0 auto;
    border-radius: 5px;
    overflow: hidden;
    background: #ffffff;
    padding: 20px;
}

h1 {
    margin-bottom: 20px;
    text-align: center;
    color: #003087;
}

.dropdown {
    position: relative;
}

.button {
    width: 100%;
    padding: 10px;
    margin-bottom: 1px;
    color: #ffffff;
    background: #0072ce;
    border: none;
    cursor: pointer;
    border-radius: 5px;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #ffffff;
    width: 100%;
    border-radius: 5px;
    box-shadow: 0 0 15px rgba(0, 0, 0, 0.15);
    z-index: 1;
}

.dropdown-content a {
    display: block;
    padding: 10px;
    color: #003087;
    text-decoration: none;
}

.dropdown:hover .dropdown-content {
    display: block;
}

.exercise {
    display: none;
    padding: 2px;
    background-color: #ffffff;
    border-radius: 5px;
    margin-top: 0px;
    text-align: center;
    color: #003087;
}

.exercise h2 {
    margin-top: 10px;
    margin-bottom: 10px;
}

.exercise p {
    margin-top: 10px;
    margin-bottom: 20px;
}

.circle-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    margin-bottom: 20px;
}

.circle {
    width: 200px;
    height: 200px;
    background-color: #4BC0C0;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #fff;
    font-size: 24px;
    font-weight: bold;
    animation-name: breathe;
    animation-timing-function: ease-in-out;
    animation-iteration-count: infinite;
    animation-fill-mode: forwards;
    margin-bottom: 5px;
}

@keyframes breathe {
    0% { transform: scale(1); }
    50% { transform: scale(1.2); }
    100% { transform: scale(1); }
}

.start-button {
    padding: 10px;
    color: #ffffff;
    background: #0072ce;
    width: 100%;
    border: none;
    cursor: pointer;
    border-radius: 5px;
    font-weight: bold;
    margin-top: 5px;
}

.start-button:hover {
    background: #003087;
}



I have tried different methods for resetting the animation each time a new exercise is selected however I’ve been unsuccessful.

Selector in PEG.js grammar accepting what is shouldn’t

I’ve recently been working on a custom programming language using PEG.js.
I made a system that recognises variable names and evaluates variable values, supporting access to object/array properties.

Global variables (glob):

{
  "null":null,
  "undefined":undefined,
  test:{
    foobar:'it worked'
  }
}

When I type test, it evaluates to {foobar:"it worked"} as expected.
But when I type test["foobar"] it should return "it worked" but instead I get this error:

Error: Variable 'test[' does not exist.

My PEG.js grammar:

Getvar
= name:Varname path:('[' _ exp:(String/Integer) _ ']' {return exp;})* {
  let rt=glob[name];
    if(rt===undefined&&name!='undefined'&&name!='null')
    error(`Variable '${name}' does not exist.`);

  for(let p of path)rt=rt[p];
  return rt;
}

Varname "variable name"
= [A-z0-9]+{
  if(!/[A-z]+/.test(text()))
    error(`Variable name must contain at least one letter. (reading '${text()}')`);
  return text();
}

String "string"
  = '"' chars:DoubleStringCharacter* '"' { return chars.join(''); }
  / "'" chars:SingleStringCharacter* "'" { return chars.join(''); }

DoubleStringCharacter
  = !('"' / "\") char:. { return char; }
  / "\" sequence:EscapeSequence { return sequence; }

SingleStringCharacter
  = !("'" / "\") char:. { return char; }
  / "\" sequence:EscapeSequence { return sequence; }

EscapeSequence
  = "'"
  / '"'
  / "\"
  / "b"  { return "b";   }
  / "f"  { return "f";   }
  / "n"  { return "n";   }
  / "r"  { return "r";   }
  / "t"  { return "t";   }
  / "v"  { return "x0B"; }

Integer "integer"
  = _ [0-9]+ { return parseInt(text(), 10); }

_ "whitespace"
  = [ tnr]*

Since the variable name has the pattern [A-z0-9]+, I have no idea why [ passes as a variable name. As I was playing around trying to figure out what’s going on,
I discovered that the pattern somehow matches A-z (letters), 0-9 (numbers), but also [ and ].

Does anyone know why this is happening?

How to do something when entering a div using the keyboard tab key

How can I ‘do something’ with jQuery when entering a div using the keyboard tab key? For example, when a user navigates using the keyboard tab button, and they enter the ‘Inside’ div in the example below, the console log doesn’t fire until the tab button is pressed a second time:

<div class="container">
<div class="outside text-center">
  <a href="">Outside Link 1</a>
  <a href="">Outside Link 2</a>
  <a href="">Outside Link 3</a>
  <a href="">Outside Link 4</a>
</div>
<div class="inside text-center">
  <a href="">Inside Link 1</a>
  <a href="">Inside Link 2</a>
  <a href="">Inside Link 3</a>
  <a href="">Inside Link 4</a>
</div>
</div>

$('.inside').on('keydown', function(e) {
  if (e.keyCode === 9) {
    console.log('Inside');
  }
});

Here’s a Codepen:
https://codepen.io/Codewalker/pen/mdQxZRr

Next.js consuming context from dynamic page

I am creating a context in Next.js

'use client';
import { createContext, useContext } from 'react';
import useSWR from 'swr';

const AppContext = createContext();
const fetcher = (url) => fetch(url).then((res) => res.json());

export function AppWrapper({ children }) {
    const { data } = useSWR('/api/images', fetcher);

    return (
        <AppContext.Provider value={ data }>
        { children && children }
        </AppContext.Provider>
    );
}

export function useAppContext() {
    return useContext(AppContext);
}

It wraps my whole layout

export default function RootLayout({ children }) {
return (
    <AppWrapper>
        <html lang="en">
            <body className={ inter.className } suppressHydrationWarning={true}>
                <header>
                    <h1>{ metadata.title }</h1>
                </header>
                { children }
            </body>
        </html>
    </AppWrapper>
    )
}

I can consume it from the main page

const imageList = useAppContext();
const imageGrid = imageList && imageList.sort(() => (Math.random() > 0.5) ? 1 : -1).slice(0, 20);

But from a dynamic route it’s called once but never returns

const imageList = useAppContext();
console.log("imageList", imageList); // undefined

How should I be accessing this data on a dynamic route?

As above on mainpage it calls 2 times undefined then ajax response.
On dynamic route its called once and undefined.

All pages should behave the same and retrieve context data

Download YouTube video using Python, youtube-dlp and video/audio formats

I am writing a backend server in Flask that on demand uses youtube-dlp to provide users with the direct download link to audio and video formats (including audio).

The code I wrote succeeds in generating and displaying all the links on screen, the problem is that once the client clicks on links, they are redirected to a page where the audio or video can be played and downloaded.

I would like the video/audio download to occur once the client clicks on the link, without being redirected to a further page.

Below is the code:

app.py

from flask import Flask, jsonify, request, render_template
import yt_dlp

app = Flask(__name__)

def get_download_links(video_url):
    ydl_opts = {
        'format': 'best',
    }

    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        info = ydl.extract_info(video_url, download=False)

        video_formats = []
        audio_formats = []
        for format in info['formats']:
            if 'url' in format:
                if 'acodec' in format and format['acodec'] != 'none':
                    audio_formats.append({
                        'format_id': format['format_id'],
                        'url': format['url'],
                    })
                else:
                    video_formats.append({
                        'format_id': format['format_id'],
                        'url': format['url'],
                    })

    return video_formats, audio_formats, info['title']

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/get_download_links', methods=['GET'])
def get_download_links_api():
    video_url = request.args.get('video_url')

    if not video_url:
        return jsonify({"error": "Il parametro 'video_url' è richiesto."}), 400

    video_formats, audio_formats, video_title = get_download_links(video_url)
    return jsonify({
        'video_formats': video_formats,
        'audio_formats': audio_formats,
        'video_title': video_title
    })

if __name__ == '__main__':
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Download Links</title>
</head>
<body>
    <h1>Download Links</h1>
    <form id="video-form">
        <label for="video-url">Inserisci il link del video di YouTube:</label>
        <input type="text" id="video-url" required>
        <button type="submit">Genera link di download</button>
    </form>
    <div id="video-links"></div>
    <div id="audio-links"></div>

    <script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>

main.js

document.addEventListener('DOMContentLoaded', function() {
    function createDownloadLink(url, filename) {
        var link = document.createElement('a');
        link.href = url;
        link.download = filename;
        link.textContent = 'Download';
        link.style.display = 'block'; // Nasconde i link di download precedenti
        link.style.marginTop = '10px'; // Aggiunge uno spazio tra i link

        return link;
    }

    function displayVideoLinks(videoFormats) {
        var videoLinksDiv = document.getElementById('video-links');
        videoLinksDiv.innerHTML = '<h2>Video Download Links</h2>';

        videoFormats.forEach(function(format) {
            var link = createDownloadLink(format.url, format.format_id + '.mp4');
            videoLinksDiv.appendChild(link);
        });
    }

    function displayAudioLinks(audioFormats) {
        var audioLinksDiv = document.getElementById('audio-links');
        audioLinksDiv.innerHTML = '<h2>Audio Download Links</h2>';

        audioFormats.forEach(function(format) {
            var link = createDownloadLink(format.url, format.format_id + '.mp3');
            audioLinksDiv.appendChild(link);
        });
    }[enter image description here](https://i.stack.imgur.com/bWveQ.png)

    function getDownloadLinks(videoUrl) {
        fetch('/get_download_links?video_url=' + encodeURIComponent(videoUrl))
            .then(response => response.json())
            .then(data => {
                displayVideoLinks(data.video_formats);
                displayAudioLinks(data.audio_formats);
            })
            .catch(error => console.error('Error:', error));
    }

    var form = document.getElementById('video-form');
    form.addEventListener('submit', function(event) {
        event.preventDefault();
        var videoUrlInput = document.getElementById('video-url');
        var videoUrl = videoUrlInput.value.trim();
        if (videoUrl !== '') {
            getDownloadLinks(videoUrl);
        }
    });
});

Some screens [[Flow](https://i.stack.imgur.com/rGbiN.png)](https://i.stack.imgur.com/8Jqwp.png)

I expect that once the link/button is clicked instead of being redirected to a page with the video/audio playback downloadable from the client, the video/audio is downloaded once the linl/button is clicked.

Animated border CSS not working on Firefox: CSS is a combination of tailwind and custom CSS

The animated border is working perfectly on Chrome, but on Firefox the border is not even showing, let alone the animation working. Need help with this

CSS file:

@import "keyframes.css";

@layer components {
  .animated-chevron {
    @apply relative;
    &:before {
      @apply content-[''] absolute w-0 h-[0.18rem] top-[41%] right-[-0.05rem] mr-[0.5rem] bg-current rounded group-hover:w-[0.55rem] group-hover:md:w-[0.7rem] transition-all duration-medium;
    }
  }
}

@layer utilities {
  .splash {
    @apply relative overflow-hidden;
    &:after {
      @apply content-[''] absolute block bg-white w-0 h-0 hover:w-[100%] hover:h-[100%] top-1/2 left-1/2 opacity-[0.15] rounded-full -translate-x-1/2 -translate-y-1/2 transition-all duration-long;
    }
  }
  .animated-border {
    @apply relative;
    &:before,
    &:after {
      -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
      -webkit-mask-composite: xor;
      mask-composite: exclude;
      @apply content-[''] absolute inset-0 rounded-primary border-[1.5px] border-transparent filter contrast-[6] bg-current pointer-events-none transition-all duration-1000;
    }
    &:after {
      background: linear-gradient(var(--angle), var(--tw-gradient-stops)) border-box;
      @apply animate-[rotate_4s_linear_infinite] opacity-0 hover:opacity-100;
    }
  }
  .animated-border-static {
    @apply animated-border from-primary-light via-black via-[70%] to-gray-light after:opacity-100;
    &:before {
      all: unset;
    }
  }
}

JSX file:

import { twMerge } from "tailwind-merge";

const StatusCard = ({ className, title, subtitle, icon: Icon }) => {
  return (
    <div
      className={twMerge(
        "group w-full flex flex-col place-items-center relative py-5 px-3 md:py-7 md:px-7 gap-1 animated-border-static revert",
        className
      )}
    >
      <div className="opacity-80 mb-3 transform scale-75 md:scale-100 rounded-2xl p-5 flex aspect-square rotate-45 md:mt-2 bg-gray-200">
        <Icon className="w-8 h-8 -rotate-45 fill-black" />
      </div>
      <span className="font-semibold text-sm md:text-base -mt-3 md:mt-2">{title}</span>
      <span className="font-medium text-sm md:text-base">{subtitle}</span>
    </div>
  );
};

export default StatusCard;

Keyframes.css

@property --angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@keyframes rotate {
  to {
    --angle: 360deg;
  }
}

When I comment the :

:before {
all: unset;
} 

the border starts showing up on Firefox, ofcourse but the animation still not working, but maybe Firefox has issue with suedo selectors