Get grid cells to expand to grid-item when the grid item resizes dynamically

I am having an auto-fill grid container. Initially when I add items, the grid cells automatically adjust to the grid-items width and height, however, if I try to dynamically change its size, the grid cells don’t expand to fit the content.

Here’s a demo:

.grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, auto));
    grid-template-rows: repeat(auto-fill, minmax(100px, auto));
    gap: 10px;
    border: 2px solid black;
    padding: 10px;
    width: fit-content;
}

  .grid-item {
      background-color: lightblue;
      display: flex;
      align-items: center;
      justify-content: center;
      border: 1px solid blue;
      padding: 10px;
      min-width: 100px;
      min-height: 100px;
      transition: width 0.3s ease, height 0.3s ease;
  }

.large {
    width: 200px !important;
    height: 200px !important;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic Grid Resizing</title>
    <style>
       
    </style>
</head>
<body>

    <button onclick="resizeItem()">Resize Item</button>

    <div class="grid-container">
        <div class="grid-item" id="resizable-item">Resize Me</div>
        <div class="grid-item">Item 2</div>
        <div class="grid-item">Item 3</div>
    </div>

    <script>
        function resizeItem() {
            const item = document.getElementById("resizable-item");
            item.classList.toggle("large");
        }
    </script>

</body>
</html>

As you can see when you press resize, it collapses onto each other.

I’ll be having more items, but above is the MRE. How can I get the grid cells to fit to grid items, even when resized dynamically?

Should I use defer or DOMContentLoaded for modifying image loading attributes?

I’m optimizing image loading for a grid layout (similar to YouTube thumbnails) by setting loading=”eager” for some images and loading=”lazy” for others based on screen size. I have placed the script tag in the head tag not the body to add loading attributes before images are in the DOM.

My goal is to:

  1. Run the script after the DOM is ready but before images load.

  2. Ensure optimal performance and avoid blocking rendering.

document.addEventListener("DOMContentLoaded", function(){
    let image = document.querySelectorAll(".image-container img");
    let eagerLoadLimit = 0

    if(window.innerWidth > 1024){
        eagerLoadLimit = 8 // desktop pc
    }
    else if(window.innerWidth >= 768 && window.innerWidth < 1024){
        eagerLoadLimit = 6 // tablets
    }
    else{
        eagerLoadLimit = 3; // mobile
    }
    image.forEach((img, index) =>{
        img.loading = index < eagerLoadLimit ? "eager" : "lazy";
    })
})

I was expecting better performance but I got worse performance in lighthouse

Stock Quantity Not Updating on Size Selection in Django Template with JavaScript

Problem Description:
I’m working on a Django project where a product can have multiple size variants, and each size has its own stock quantity. I want to display the stock information dynamically when a user selects a size using JavaScript.

However, the stock information is not updating as expected. It always shows undefined in stock or Only undefined left, even though I can see the correct stock data in the browser console.


Models:

class Size(models.Model):
    name = models.CharField(max_length=50)

class Product(models.Model):
    title = models.CharField(max_length=255)

class ProductStock(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="stocks")
    size = models.ForeignKey(Size, on_delete=models.CASCADE, blank=True, null=True)
    uploded_stock_quantity = models.PositiveIntegerField(default=0)
    stock_quantity = models.PositiveIntegerField(default=0)
    reserved_stock = models.PositiveIntegerField(default=0)

    def available_stock(self):
        return self.stock_quantity - self.reserved_stock

Views:

from django.shortcuts import render, get_object_or_404

def product_detail_view(request, pid):
    product = get_object_or_404(Product, pid=pid)
    sizes = product.size.filter(product=product)
    product_stocks = ProductStock.objects.filter(product=product)
    
    size_stock_data = {
        str(stock.size.id): {
            'stock_quantity': stock.stock_quantity,
            'uploaded_stock_quantity': stock.uploded_stock_quantity
        }
        for stock in product_stocks
    }

    return render(request, 'core/product_detail.html', {
        'product': product,
        'sizes': sizes,
        'size_stock_data': size_stock_data
    })

Template:

{{ size_stock_data|safe|json_script:"size-stock-data" }}

<div class="u-s-m-b-15">
  <div class="pd-detail__inline">
    <span class="pd-detail__stock" id="uploaded-stock">-</span>
    <span class="pd-detail__left" id="remaining-stock">-</span>
  </div>
</div>

{% if sizes %}
  <div class="u-s-m-b-15">
    <span class="pd-detail__label u-s-m-b-8">Size:</span>
    <div class="pd-detail__size">
      {% for s in sizes %}
      <div class="size__radio">
        <input type="radio" id="size_{{ s.id }}" name="size" value="{{ s.id }}" onclick="updateStock(this)" {% if forloop.first %}checked{% endif %}>
        <label class="size__radio-label" for="size_{{ s.id }}">{{ s.name }}</label>
      </div>
      {% endfor %}
    </div>
  </div>
{% endif %}

JavaScript:

function updateStock(element) {
  const sizeId = element.value;
  const stockDataElement = document.getElementById('size-stock-data');

  if (!stockDataElement) {
    console.error("Stock data not found!");
    return;
  }

  try {
    const stockData = JSON.parse(stockDataElement.textContent);
    console.log("Parsed Stock Data:", stockData);
    console.log("Selected Size ID:", sizeId);

    if (stockData[sizeId]) {
      const uploadedStock = stockData[sizeId].uploaded_stock_quantity;
      const stockQuantity = stockData[sizeId].stock_quantity;
      document.getElementById('uploaded-stock').innerText = `${uploadedStock} in stock`;
      document.getElementById('remaining-stock').innerText = `Only ${stockQuantity} left`;
    } else {
      console.error("No stock data available for size:", sizeId);
    }
  } catch (error) {
    console.error("Error parsing stock data:", error);
  }
}

// Trigger for initially selected size
document.addEventListener('DOMContentLoaded', function() {
  const checkedSize = document.querySelector('input[name="size"]:checked');
  if (checkedSize) {
    updateStock(checkedSize);
  }
});

Issue Faced:

  • undefined in stock or Only undefined left
  • The stock data is visible in the console using console.log, but the values are not reflected in the HTML.
  • No JavaScript errors in the console.

What I Tried:

  1. Confirmed size_stock_data is correctly passed to the template.
  2. Verified json_script using console.log(document.getElementById('size-stock-data').textContent).
  3. Confirmed HTML IDs are correct and not duplicated.
  4. Ensured the size IDs are properly rendered.

Expected Result:

  • When a size is selected, it should update the stock details with the correct values like 100 in stock and Only 98 left.

How can I fix this issue? Any suggestions are appreciated!

Add multiple select options to url paramter with Javascript | remove undefined

I want to create a url where I send select option values to the url.

I already saw that article, which helps a lot. Add multiple select options to url paramter with Javascript

The only thing with this code is, if I choose the second option and leave the first blank, I get a name=undefined in the url for the first value. But only for the first option value, the others are just not in the url if blank.

Can you please help to adjust the code, thank you. if there is no value selected, it should be not added to the url.

Another point is, if the option is preselected with html, it gets ignored and therefor an undefined.

<option value="2" selected>2</option>

thank you for your help.

Here is the code/answer from the other article:

<form action="" method="GET" id="myForm">
    <select name="channel" id="0" onChange="changeURL(0)">
            <option value="" selected disabled>Choose Channel</option>
            <option value="facebook-ads">Facebook ads</option>
            <option value="instagram-ads">Instagram ads</option>
    </select>
        <select name="brand" id="1" onChange="changeURL(1)">
            <option value="" selected disabled>Choose Brand</option>
            <option value="brand-1">brand 1</option>
            <option value="brand-2">brand 2</option>
            <option value="brand-3">brand 3</option>
        </select>
</form>
<p id="test"></p>
<script>

var filters = [,]; // create an array with empty values (only 2 in this case)

function changeURL(a) {
    var yourUrl = "https://yourdomain.com"; // your url
    filters[a] = document.getElementById(a).value; // set the value of the selected filter inside the array
    var preFilter = "?"; // blank url will need a "?" to start with your filters
    for(var i=0; i<filters.length; i++) {
        aName = document.getElementById(i).name; // get the name of the filter
        yourUrl += preFilter + aName + "=" + filters[i];
        preFilter = "&";  
    }
    document.getElementById("test").innerHTML = yourUrl; // test output of the new url
}
</script>

Is it possible to record current playing audio using web audio and play in different context?

I want to record current playing audio using Audio Worklet processer and web audio api and play in real time with possible lag of 100ms current audio sources, but the audio is distorted and not playing correctly so what is correct way to fix the following issues?

In following code a test.mp3 file selected, then played, after that the start processing button clicked to make current playing audio volume to 0.01 and and play the new processed audio in new context. The audio taken from Audio Worklet Processor.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Real-Time Audio Processing</title>
</head>
<body>
    <h1>Real-Time Audio Processing</h1>
    <audio id="audio" controls>
        <source src="test.mp3" type="audio/mpeg">
        Your browser does not support the audio tag.
    </audio>
    <button id="start">Start Processing</button>
    <button id="stop" disabled>Stop Processing</button>

    <script>
        let originalAudio, audioContext, newAudioContext, workletNode, mediaStreamSource;
        let bufferQueue = [];
        let isPlaying = false;
        let processorNode;
        let startTime = 0;
        let lastAudioTime = 0;

        document.getElementById('start').addEventListener('click', async () => {
            originalAudio = document.getElementById('audio');
            originalAudio.volume = 0.01; // Mute original audio to 0.01 but still play

            const stream = originalAudio.captureStream();

            audioContext = new AudioContext();
            newAudioContext = new AudioContext();

            // Register WorkletProcessor
            await audioContext.audioWorklet.addModule(URL.createObjectURL(new Blob([`
                class RecorderProcessor extends AudioWorkletProcessor {
                    constructor() {
                        super();
                        this.port.start();
                    }
                    process(inputs) {
                        const input = inputs[0];
                        if (input.length > 0) {
                            const outputBuffer = input[0]; // First channel data
                            this.port.postMessage(outputBuffer); // Send to main thread
                        }
                        return true;
                    }
                }
                registerProcessor("recorder-processor", RecorderProcessor);
            `], { type: "application/javascript" })));

            workletNode = new AudioWorkletNode(audioContext, "recorder-processor");

            workletNode.port.onmessage = (event) => {
                const data = event.data;
                bufferQueue.push(data);
                if (!isPlaying) {
                    playBufferedAudio();
                }
            };

            mediaStreamSource = audioContext.createMediaStreamSource(stream);
            mediaStreamSource.connect(workletNode);
            workletNode.connect(audioContext.destination);

            document.getElementById('start').disabled = true;
            document.getElementById('stop').disabled = false;
        });

        function playBufferedAudio() {
            if (bufferQueue.length === 0) {
                isPlaying = false;
                return;
            }

            isPlaying = true;

            const data = bufferQueue.shift();
            const buffer = newAudioContext.createBuffer(1, data.length, newAudioContext.sampleRate);
            buffer.copyToChannel(new Float32Array(data), 0);

            const source = newAudioContext.createBufferSource();
            source.buffer = buffer;
            source.connect(newAudioContext.destination);

            if (startTime === 0) {
                startTime = newAudioContext.currentTime + 0.02; // Add slight delay to sync
            } else {
                startTime = Math.max(newAudioContext.currentTime, lastAudioTime);
            }

            lastAudioTime = startTime + buffer.duration;
            source.start(startTime);

            source.onended = playBufferedAudio;
        }

        document.getElementById('stop').addEventListener('click', () => {
            audioContext.close();
            newAudioContext.close();
            bufferQueue = [];
            isPlaying = false;
            console.log("Stopped processing audio");
        });
    </script>
</body>
</html>

Is there a way to link this program? [closed]

I am going to need a lot of help with linking this program.

C:UsersuserDesktop>link /subsystem:console /entry:main malware.obj /RapeKernel32.lib
Microsoft (R) Incremental Linker Version 14.29.30159.0
Copyright (C) Microsoft Corporation.  All rights reserved.

LINK : warning LNK4044: unrecognized option '/RapeKernel32.lib'; ignored
malware.obj : error LNK2001: unresolved external symbol _GetStdHandle@4
malware.obj : error LNK2001: unresolved external symbol _WriteFile@20
malware.obj : error LNK2001: unresolved external symbol _ExitProcess@4

malware.exe : fatal error LNK1120: 3 unresolved externals

How to make the hover text in desktop to appear below the image?

I am building a website related to a branding agency and I am making its Our Team Section where I need to put a hover animation on the team members images to show their names, roles and linkedin profile button link as an overlay text. While I have successfully done that for the desktop view, I cannot seem to find a solution to do that in mobile view, I want to make the mobile view such that the description of the team member (name, role and linkedin) is fixed below each image in the smaller screens while keeping the layout similar to what the desktop is showing. Below is the code for the same

/* team container CSS start */
.team-container-outer {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100dvw;
    height: 150vh;
}

.team-container {
    display: flex;
    width: 80%;
    height: 90%;
    flex-direction: column;
    align-items: center;
}

@media (min-width:1450px) {
    .team-container-outer {
        width: 100dvw;
        height: 180vh;
    }

    .team-container {
        display: flex;
        width: 60%;
        height: 90%;

    }
}

.first-column,
.second-column,
.third-column {
    width: 100%;
    display: flex;
}

.first-column {
    flex: 2.5 1;
    flex-direction: row;
    justify-content: space-between;
    gap: 25px;
}

.second-column {
    flex: 1 1;
    flex-direction: column;
    justify-content: center;
    text-align: center;
}

.third-column {
    flex: 3 1;
    justify-content: space-between;
    gap: 25px;
}

/* Base styles for all boxes */
.box {
    width: 30%;
    border-radius: 40px;
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

/* Remove hover from parent box6 */
.box6 {
    width: 30%;
    display: flex;
    flex-direction: column;
    height: 98%;
    gap: 3%;
    transform: none !important;
    transition: none !important;
}

/* Individual box styles */
.box1, .box2, .box3, .box4, .box5 {
    transition: transform 0.3s ease;
}

.box6-1, .box6-2 {
    width: 100%;
    flex: 1;
    border-radius: 40px;
    position: relative;
    overflow: hidden;
    background-size: cover;
    background-position: center;
    transition: transform 0.3s ease;
}

/* Hover effects for individual boxes */
.box1:hover, .box2:hover, .box3:hover, .box4:hover, .box5:hover,
.box6-1:hover, .box6-2:hover {
    transform: scale(1.05);
}

/* Team member overlay styles */
.team-member-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.85);
    padding: 20px;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 15px;
}

/* Show overlay only on hover of individual boxes */
.box1:hover .team-member-overlay,
.box2:hover .team-member-overlay,
.box3:hover .team-member-overlay,
.box4:hover .team-member-overlay,
.box5:hover .team-member-overlay,
.box6-1:hover .team-member-overlay,
.box6-2:hover .team-member-overlay {
    opacity: 1;
    visibility: visible;
}

.team-member-name {
    color: white;
    font-size: 1.4rem;
    font-weight: 600;
    margin: 0;
}

.team-member-role {
    color: #4dd6f5;
    font-size: 1rem;
    margin: 0;
    font-weight: 500;
}

.linkedin-btn {
    background: #0077b5;
    color: white;
    padding: 10px 20px;
    border-radius: 25px;
    text-decoration: none;
    font-size: 0.95rem;
    transition: all 0.3s ease;
    border: none;
    margin-top: 5px;
}

.linkedin-btn:hover {
    background: #005885;
    transform: translateY(-2px);
}

/* Box background images */
.box1 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
    height: 70%;
}

.box2 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
    height: 70%;
    align-self: end;
}

.box3 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
    height: 70%;
}

.box4 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
    height: 95%;
    align-self: center;
}

.box5 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
    height: 80%;
    align-self: center;
}

.box6-1 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
}

.box6-2 {
    background: url(https://www.istockphoto.com/photos/full-length-person);
    background-size: cover;
}

/* Media queries */
@media (max-width: 768px) {
    .team-container-outer {
        height: 90vh;
    }

    .team-member-overlay {
        padding: 15px;
    }

    .team-member-name {
        font-size: 1.2rem;
    }

    .team-member-role {
        font-size: 0.9rem;
    }

    .linkedin-btn {
        padding: 8px 16px;
        font-size: 0.85rem;
    }
}

@media (max-width: 480px) {
    .team-container-outer {
        height: 45vh;
    }

    .box, .box6-1, .box6-2 {
        border-radius: 25px;
    }

    .team-member-overlay {
        padding: 10px;
        opacity: 1;
        visibility: visible;
        background: rgba(0, 0, 0, 0.75);
    }

    .team-member-name {
        font-size: 1rem;
    }

    .team-member-role {
        font-size: 0.8rem;
    }

    .linkedin-btn {
        padding: 6px 12px;
        font-size: 0.8rem;
    }
}

@media screen and (max-width: 360px) {
    .team-member-name {
        font-size: 0.9rem;
    }

    .team-member-role {
        font-size: 0.75rem;
    }

    .linkedin-btn {
        padding: 5px 10px;
        font-size: 0.75rem;
    }
}
<section id="our-team" class="page6 hidden animate-on-scroll">
    <div class="team-container-outer">
      <div class="team-container">
        <div class="first-column">
          <div class="box box1">
            <div class="team-member-overlay">
              <h3 class="team-member-name">Aayush</h3>
              <p class="team-member-role">Frontend Developer</p>
              <a href="https://www.linkedin.com/in/aayush" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
            </div>
          </div>
          <div class="box box2">
            <div class="team-member-overlay">
              <h3 class="team-member-name">Lakshya</h3>
              <p class="team-member-role">Founder and UI/UX Designer</p>
              <a href="https://www.linkedin.com/in/lakshya" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
            </div>
          </div>
          <div class="box box3">
            <div class="team-member-overlay">
              <h3 class="team-member-name">Abhijeet</h3>
              <p class="team-member-role">Graphic Designer and Video Editor</p>
              <a href="https://www.linkedin.com/in/abhijeet" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
            </div>
          </div>
        </div>
        <div class="second-column">
          <h1>MEET OUR TEAM</h1>
          <p>We Explore, Create, Design, Develop only for your Growth</p>
        </div>
        <div class="third-column">
          <div class="box box4">
            <div class="team-member-overlay">
              <h3 class="team-member-name">Sumit</h3>
              <p class="team-member-role">Full Stack Developer</p>
              <a href="https://www.linkedin.com/in/sumit" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
            </div>
          </div>
          <div class="box box5">
            <div class="team-member-overlay">
              <h3 class="team-member-name">Aman</h3>
              <p class="team-member-role">LinkedIn Manager</p>
              <a href="https://www.linkedin.com/in/aman" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
            </div>
          </div>
          <div class="box box6">
            <div class="box box6-1">
              <div class="team-member-overlay">
                <h3 class="team-member-name">Avneesh</h3>
                <p class="team-member-role">Web Developer</p>
                <a href="https://www.linkedin.com/in/avneesh" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
              </div>
            </div>
            <div class="box box6-2">
              <div class="team-member-overlay">
                <h3 class="team-member-name">Divyanshu</h3>
                <p class="team-member-role">Web Developer</p>
                <a href="https://www.linkedin.com/in/divyanshu" target="_blank" rel="noopener" class="linkedin-btn">LinkedIn Profile</a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>

Why does Promise.resolve().then() execute before process.nextTick() in my Node.js script?

I’m trying to understand the async operations of node.js, specifically process.nextTick() and Promise().

The process.nextTick() has the highest priority in async operations compared to all other operations.

process.nextTick(() => console.log("tick"));

Promise.resolve().then(() => console.log("promise"));

For above code the expected output should be:

tick
promise

But instead I got below output:

promise
tick

I could not able to understand why this strange behaviour happens, please give me proper reason and solution for this. Thanks for support.

How to maintain the selected state of radio button in slick slides as you navigate between slides

Steps to do.

  1. Select the radio button item 1.
  2. Click the slick next arrow until you reach again the item 1 and it is not selected. I want it selected because you select it previously.

I want to maintain the selected state of radio button in slick slides once it shown in the slick/viewport.

I tried using the slick Methods and Events like slickGoTo, afterChange ect.. but no to avail.

Here are my codes.

$('.my-slick-carousel').each(function() {
        let slider = $(this);
        slider.slick({
            slidesToShow: 2,
            slidesToScroll: 1,
            autoplay: false,
            dots: true,
            infinite: true,
            arrows: true,
            centerPadding: '0px',
            variableWidth: false,
            centerMode: false,
            touchThreshold: 100,
            rows: 0,
        });
    });
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick-theme.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.9.0/slick.min.js"></script>
<style>
.items {
  background-color: gray;
  border-radius:2rem;
  text-align:center;
}
.slick-prev,
.slick-next {
  z-index:9;
}
.slick-next:before, .slick-prev:before {
  color: red;
}
.slick-prev {
  left: 0;
}
.slick-next {
  right: 0;
}
</style>

<div class="container">
  <h4 class="text-center">Maintain the selected radio button on slick slide and maintain the selected state as you navigate between slides.</h4>
  <div class="my-slick-carousel py-5 px-3">
    <div class="items mx-2 p-4"><input type="radio" name="addOnsRadio" value="item 1" id=""> item 1</div>
    <div class="items mx-2 p-4"><input type="radio" name="addOnsRadio" value="item 2" id=""> item 2</div>
    <div class="items mx-2 p-4"><input type="radio" name="addOnsRadio" value="item 3" id=""> item 3</div>
  </div>
</div>

Memory game code works but only if tiles are clicked slowly, if tiles are clicked too fast game breaks

HTML CODE

 <!DOCTYPE html>
<html>
    
    <body style="justify-self:center;">
        <h1 style="justify-self:center">Memory Game</h1>
        <div id="cont" style="width:px">
            <p class="stats" style="justify-self:center ;"></p>
            <div class='cardContainer' style="justify-self:center ;">
                <div class='card' id="1"></div>
                <div class='card' id="1"></div>
                <div class='card' id="2"></div>
                <div class='card' id="2"></div>
                <div class='card' id="3"></div>
                <div class='card' id="3"></div>
                <div class='card' id="4"></div>
                <div class='card' id="4"></div>
                <div class='card' id="5"></div>
                <div class='card' id="5"></div>
                <div class='card' id="6"></div>
                <div class='card' id="6"></div>
                <div class='card' id="7"></div>
                <div class='card' id="7"></div>
                <div class='card' id="8"></div>
                <div class='card' id="8"></div>
            </div>
        
            <div style="justify-self:center ;"><button id="reset" style="margin-top: 20px; ">Reset Game</button></div>
            <script src="mg.js"></script>
        </div>   
    </body>
    

</html> 

JS CODE

const cards = document.querySelectorAll('.card')
let clickCount = 0
let id = []
let matched = 0

function shuffle(){
    cards.forEach(card => {                                                  
        let pos = Math.floor(Math.random() * 12);
        card.style.order = pos
    })
}

shuffle()

function checkMatch(){
    if (id[0] == id[1]){
        return true
    }else{return false}
}


cards.forEach(card=>{
    card.addEventListener('click', ()=>{
        card.innerHTML = card.id
        id.push(card.id)
        card.setAttribute('open', 'true')
        clickCount += 1
        console.log(clickCount)
        if (clickCount == 2){
            let result = checkMatch()
            clickCount = 0
            if (result == false){
                id = []
                setTimeout(()=>{document.querySelectorAll('[open="true"]').forEach((card)=>{card.innerHTML='';card.removeAttribute('open', 'true')})},100)
            }else{
                console.log('matched')
                id = []
                document.querySelectorAll('[open="true"]').forEach((card)=>{card.removeAttribute('open', 'true');card.replaceWith(card.cloneNode(true))})
                matched += 2
            }
        }
        if (matched == 16){
            console.log('You win')
        }
    })
})

If i click the tiles slowly and play the game the game works properly. However if i were to try and randomly click tiles super fast, one of the clicked tiles declare itself as matched and stays open even thought it hasn’t matched. How do I fix this.
[1]: https://i.sstatic.net/65H9nyzB.png

Searching child elements of HTML DOM element?

const parent = document.getElementById('parent');
const paragraphs = parent.getElementsByTagName('p'); // Get all <p> tags
console.log(paragraphs); // HTMLCollection of <p> elements
<div id="parent">
    <p class="child">First Child</p>
    <p class="child">Second Child</p>
    <span class="child">A Span Child</span>
</div>

Code like this works, but I can’t find any documentation for using .getElementsByTagName – or any other JavaScript DOM search methods – as a method with HTMLelement, only with document, why is this?

See:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
https://developer.mozilla.org/en-US/docs/Web/API/Document

React: Images not rendering when using rich text from Contentful

I’m using React, Astro and Contenful. I need to render rich text with images. I tried to use documentToReactComponents function from Contentful’s @Contentful/rich-text-react-renderer package to render rich text content in my React application. While my text and headings are rendering correctly, any images within the content do not appear.

Here’s a simplified version of my component:

import React, { useState } from "react";
import { documentToReactComponents } from "@Contentful/rich-text-react-renderer";
import type { QuestionAndAnswerItem } from "../types/contentful";
interface TrendingArticlesProps {
  faqData: QuestionAndAnswerItem[];
  heading: string;
}
export const TrendingArticles: React.FC<TrendingArticlesProps> = ({ faqData, heading }) => {
  const [openIndex, setOpenIndex] = useState<number | null>(null);
  const handleToggle = (index: number) => {
    setOpenIndex((prevIndex) => (prevIndex === index ? null : index));
  };
  return (
    <section style={{ margin: "2rem 0" }}>
      <h2>{heading}</h2>
      <div>
        {faqData.map((item, index) => (
          <div
            key={index}
            style={{
              border: "1px solid #ccc",
              borderRadius: "4px",
              marginBottom: "0.5rem",
            }}
          >
            <button
              onClick={() => handleToggle(index)}
              style={{
                width: "100%",
                textAlign: "left",
                padding: "1rem",
                background: "F9F9F9_1",
                border: "none",
                cursor: "pointer",
              }}
            >
              {documentToReactComponents(item.question)}
            </button>
            {openIndex === index && (
              <div style={{ padding: "1rem", background: "#fff" }}>
                {documentToReactComponents(item.answer)}
              </div>
            )}
          </div>
        ))}
      </div>
    </section>
  );
};

Contenful content
output

documentToReactComponents function from Contentful’s @Contentful/rich-text-react-renderer package to render rich text content in my React application. While my text and headings are rendering correctly, any images within the content do not appear.
contentful content
output

Clipboard API: Leading spaces lost on first HTML paragraph when pasting into PowerPoint

I’m using the Clipboard API to copy styled HTML content with leading spaces into Microsoft PowerPoint, and I found that using a combination of &nbsp; and mso-spacerun:yes works well — except for the first line (based on this question). For some reason, the indentation of the first paragraph gets collapsed down into at most one space when pasted into PowerPoint.

Here’s the full source code of what I’m doing:

const htmlText =
  // Indented with non-breaking spaces and mso-spacerun
  '<p><span style="mso-spacerun:yes">&nbsp;&nbsp;&nbsp;Three</span></p>' +
  '<p><span style="mso-spacerun:yes">&nbsp;&nbsp;Two</span></p>' +
  '<p><span style="mso-spacerun:yes">&nbsp;One</span></p>' +
  '<p><span style="mso-spacerun:yes">&nbsp;&nbsp;Two</span></p>'+
  '<p><span style="mso-spacerun:yes">&nbsp;&nbsp;&nbsp;Three</span></p>';

async function copyToClipboard() {
  try {
    const data = [
      new ClipboardItem({
        'text/html': new Blob([htmlText], { type: 'text/html' })
      })
    ];
    await navigator.clipboard.write(data);
    console.log('HTML copied to clipboard');
  } catch (err) {
    console.error('Failed to copy HTML:', err);
  }
}

When I paste this into PowerPoint:

  • The second, third, and fourth lines all keep their leading spaces as expected.
  • But the first line loses its indentation and appears left-aligned.

The following shows the result in powerpoint:

Example of the wrong indentation for the first line

Has anyone else run into this?
Is there a workaround or specific formatting tweak that forces PowerPoint to respect the leading spaces on the first paragraph as well?

Thanks in advance!

Getting the XML declaration from a document

I’ve hit a conundrum whilst writing a custom serialize XMLDocument function. I can’t find the opening XML declaration anywhere. I know it’s there because new XMLSerializer().serializeToString(xml) can access it, and I’m fairly certain it doesn’t just generate a new one because it even includes the standalone=”no” of the original document.

However, the MDN documentation specifies:

XML – declaration is not a tag

and indeed I’ve looked through the DOM properties and the declaration is nowhere to be found. The processing instruction appears to be absent from the document structure. Is there a property I’m missing somewhere? Maybe one that contains the un-parsed document as a string? And failing that I would love to know how serializeToString() does it.

Here is my function as it stands:

const serialize = function(xml) {
    let string = "";
    const recursive = function(node,indent = 0) {
        if (node.nodeType === Node.ELEMENT_NODE) {
            string += "t".repeat(indent) + "<" + node.tagName;
            for (const attribute of node.attributes) {
                recursive(attribute,indent + 1);
            }
            if (node.childNodes.length) {
                string += ">";
                if (Array.from(node.childNodes).some(child => child.nodeType === Node.TEXT_NODE && child.data.match(/[^s]/))) {
                    for (const child of node.childNodes) {
                        recursive(child,0);
                    }
                } else {
                    string += "n";
                    for (const child of Array.from(node.childNodes).filter(child => child.nodeType === Node.ELEMENT_NODE)) {
                        recursive(child,indent + 1);
                    }
                    string += "t".repeat(indent);
                }
                string += "</" + node.tagName + ">";
            } else {
                string += "/>";
            }
            string += (indent ? "n" : "");
        }
        if (node.nodeType === Node.ATTRIBUTE_NODE) {
            string += (indent ? "n" : " ") + "t".repeat(indent) + `${node.name}="${node.value}"`;
        }
        if (node.nodeType === Node.TEXT_NODE) {
            string += node.data;
        }
        if (node.nodeType === Node.CDATA_SECTION_NODE) {
            string += "<!CDATA[[" + node.data + "]]>" + "n";
        }
        if (node.nodeType === Node.PROCESSING_INSTRUCTION_NODE) {
            string += "<?" + node.target + " " + node.data + "?>" + "n";
        }
        if (node.nodeType === Node.COMMENT_NODE) {
            string += "<!-- " + node.data + " -->" + "n";
        }
        if (node.nodeType === Node.DOCUMENT_NODE) {
            for (const child of node.childNodes) {
                recursive(child);
            }
        }
    }
    recursive(xml);
    return string;
}

AG Grid Value Setter Not Updating Underlying Data

I’m trying to apply a basic formula that multiplies the “quantity” by “cost” to get a “total cost”. The user can change the “quantity” or “cost” which will update the “total cost”. I then want to retrieve that updated “total cost” from the underlying data in the grid. From my understanding of the documentation, I should be using “valueSetter”, but it does not work. Meaning, after the user changes the “cost” or “quanity”, I can see the data changed in the display of the grid. However, the underlying data does not change.

I’ve already tried the only other source found here under a similar thread, but it does not work.

Code example: This uses methods shown under the documentations examples.

let gridApi;

const gridOptions = {
    rowData: [ { item: "Shirt", quantity: 10, cost: 2.00 , total: 20.00 } ],
    columnDefs: [
        { field: "item", },
        { field: "quantity", headerName: 'Qty', editable: true, },
        { field: "cost", headerName: 'Cost', editable: true, },
        {
            field: "total",
            headerName: 'Total Cost',
            editable: false,
            valueGetter: params => params.data.quantity * params.data.cost,
            valueSetter: params => {
                params.data.total = params.newValue;
                return true;
            },
        },
    ],
};

document.addEventListener("DOMContentLoaded", function () {
    const gridDiv = document.querySelector("#myGrid");
    gridApi = agGrid.createGrid(gridDiv, gridOptions);
});

$("#ButtonDisplayData").click(function () {
    const allRowData = [];
    gridApi.forEachNode(node => allRowData.push(node.data));

    //Display data using node and directly. Nothing changes
    console.log(allRowData);
    console.log(gridOptions.rowData);
});

As I said above, I tried the suggestion from the similar thread found on this site and it didn’t work.

const colId = params.colDef.colId;
const paramsCopy = { ...params.data };
const paramsCopy = params.data ;
paramsCopy[colId] = params.newValue;
params.data = paramsCopy;
params.node.setData(paramsCopy);
return true;