offline service worker not working properly in google dev tools

I have been leaning to make PWA and I have notice google dev tools are not properly simulating offline feature of service worker.

enter image description here

I am talking about this feature showed in image.
I am using

package.json

"devDependencies": {
    "http-server": "^0.9.0"
  }

for localhost web server

SW.js file

var CACHE_STATIC_NAME = 'static-v10';
var CACHE_DYNAMIC_NAME = 'dynamic-v2';

self.addEventListener('install', function(event) {
  console.log('[Service Worker] Installing Service Worker ...', event);
  event.waitUntil(
    caches.open(CACHE_STATIC_NAME)
      .then(function(cache) {
        console.log('[Service Worker] Precaching App Shell');
        cache.addAll([
          '/',
          '/index.html',
          '/offline.html',
          '/src/js/app.js',
          '/src/js/feed.js',
          '/src/js/promise.js',
          '/src/js/fetch.js',
          '/src/js/material.min.js',
          '/src/css/app.css',
          '/src/css/feed.css',
          '/src/images/main-image.jpg',
          'https://fonts.googleapis.com/css?family=Roboto:400,700',
          'https://fonts.googleapis.com/icon?family=Material+Icons',
          'https://cdnjs.cloudflare.com/ajax/libs/material-design-lite/1.3.0/material.indigo-pink.min.css'
        ]);
      })
  )
});

self.addEventListener('activate', function(event) {
  console.log('[Service Worker] Activating Service Worker ....', event);
  event.waitUntil(
    caches.keys()
      .then(function(keyList) {
        return Promise.all(keyList.map(function(key) {
          if (key !== CACHE_STATIC_NAME && key !== CACHE_DYNAMIC_NAME) {
            console.log('[Service Worker] Removing old cache.', key);
            return caches.delete(key);
          }
        }));
      })
  );
  return self.clients.claim();
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        if (response) {
          return response;
        } else {
          return fetch(event.request)
            .then(function(res) {
              return caches.open(CACHE_DYNAMIC_NAME)
                .then(function(cache) {
                  cache.put(event.request.url, res.clone());
                  return res;
                })
            })
            .catch(function(err) {
              return caches.open(CACHE_STATIC_NAME)
                .then(function(cache) {
                  return cache.match('/offline.html');
                });
            });
        }
      })
  );
});

this is service worker file. I am trying to show offline.html page if any page

let me know if you need any thing more regarding project I am working with

How to group and find average of object in nested arrays?

I have an array like this where an object is inside nested arrays:

let arr = [
    [
        {date: 1578787200000, displacement: 0},
        {date: 1580860800000, displacement: 1},
        {date: 1593302400000, displacement: 2},
        {date: 1606780800000, displacement: 3}
    ],
    [
        {date: 1578787200000, displacement: 10},
        {date: 1580860800000, displacement: 20},
        {date: 1593302400000, displacement: 30},
        {date: 1606780800000, displacement: 40}
    ]
]

and want to group the objects by ‘date’ whilst also averaging the ‘displacement’ values so the result looks like this:

[
    {date: 1578787200000, displacement: 5},
    {date: 1580860800000, displacement: 10.5},
    {date: 1593302400000, displacement: 16.5},
    {date: 1606780800000, displacement: 21.5}
]

I have tried .reduce() combined with .forEach() to sum the displacements per date but can’t get it to output exactly what I’m after.
e.g.

let res = arr.reduce(function (prev, currentArr) {
    currentArr.forEach(function (obj) {
        (prev.date == obj.date || []).push(prev.displacement + obj.displacement)
    }, 0);
    return prev;
});

What is the best way to accomplish this?

Stream Audio from another tab to Google Meet tab using Chrome Extension

During virtual calls with friends (in Chrome and over Google Meet), I would like to stream radio for the participants. The usual way for me is to play the Radio over speakers in another tab, turn on the microphone on the GMeet tab, and let the microphone capture the audio from the Speaker. I want to know if bypassing this by using a Chrome extension is possible. The steps are,

  1. Capture the audio from Radio (can be done using tabCapture) — DONE
  2. Play the audio in the Google Meet tab so that participants can hear it (??) — PENDING

Any help with the 2nd step will be appreciated.

Thanks.

Signature Pad (Canvas) to Google Sheets

I’m attempting to create a form which auto populates into Google Sheets. At the moment, I am able to use <input/> to auto populate basic text fields into Google Sheets, but I now need to try to have the user write a digital signature and for that to be put into Google Sheets too – presumably by using toDataURL and then having that be sent to the Google Sheet?

But… I have very little experience with anything like this and have absolutely no idea how to achieve this!

I have taken code from various sources and videos so far to get to the stage I’m at, but now it is getting messy.

Some of the content on the page is somewhat sensitive, so I’ll post whatever code I can here.

This is some of the HTML currently being used – sorry that it is a little messy! (Some of it might not even have use, I’ve been messing around with it so much that I’m lost at this point!)

    <h4>Billing Address</h4>
        <input type="text" name="address-number" placeholder="House/Apartment Number">
            <input type="text" name="address-street" placeholder="Street Name">
        <input type="text" name="address-town" placeholder="Town/City">
        <input type="text" name="address-county" placeholder="County">
            <input type="text" name="address-postcode" placeholder="Postcode">
                    
                    
    <div class="flex-row">
                <div class="wrapper">
                     <canvas id="signature-pad" width="400" height="200"></canvas>
                </div>
                <div>
                     <input type="hidden" name="signature-pad" />
                </div>
                     <div class="clear-btn">
                     <button id="clear"><span> Clear </span></button>
                </div>
                </div> 
                
                 <div>
                
<script src="https://cdnjs.cloudflare.com/ajax/libs/signature_pad/1.3.5/signature_pad.min.js" integrity="sha512-kw/nRM/BMR2XGArXnOoxKOO5VBHLdITAW00aG8qK4zBzcLVZ4nzg7/oYCaoiwc8U9zrnsO9UHqpyljJ8+iqYiQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

   <input type="submit" value="Submit" id="submit">
</div>
</form>

And this is the Javascript currently being used – it’s even more messy and I’m sure a lot of it is doing nothing. Apologies once again.

const form = document.forms['contact-form']


form.addEventListener('submit', e => {
  e.preventDefault()
  fetch(scriptURL, { method: 'POST', body: new FormData(form)})
  .then(response => alert("Thank you! your form is submitted successfully." ))
  .then(() => { window.location.reload(); })
  .catch(error => console.error('Error!', error.message))
})

 
var canvas = document.getElementById("signature-pad");


       function resizeCanvas() {
           var ratio = Math.max(window.devicePixelRatio || 1, 1);
           canvas.width = canvas.offsetWidth * ratio;
           canvas.height = canvas.offsetHeight * ratio;
           canvas.getContext("2d").scale(ratio, ratio);
       }
       
       window.onresize = resizeCanvas;
       resizeCanvas();

       var signaturePad = new SignaturePad(canvas, {
        backgroundColor: 'rgb(250,250,250)'
       });

       document.getElementById("clear").addEventListener('click', function(){
        signaturePad.clear();
       });
       
       
function onSubmit(e) {
    console.log({
        'signature-pad' : dataURL,
    });
}

And this is all connected up to Google Sheets with some kind of script – I honestly have no idea how that is working at all. It’s all a bit dark magic to me. If I need to provide any more code or info then let me know.

Fundamentally, I’d like to be able to get the signature pad to out put the signature image in some way which I can then have auto populate into Google Sheets when the user submits.

Thanks so much for any help with this and to anyone who can decipher my descent into madness. It is VERY much appreciated!

I’ve tried many different variations of code, most of which I have since lost. Apologies. Most of the time, I would half-expect it to work (with little confidence) and it simply would not. The Google Sheet would auto populate as usual, but without any signature section filled. I have attempted to alter the onSubmit section to generate a URL, though I don’t think I did it correctly. And I have tried things such as having other “var” segments at the beginning of the code such as with this example: Create an HTML form with Digital / Electronic Signature using php – but I’ve found that those “var”s at the beginning seem to break the signature pad in WordPress and it will not allow a user to even draw in the box. As soon as I remove them, the signature pad works again.

I’ve tried using both the code I currently have, and the one linked but neither work. The one I currently have allows me to use the pad properly but I cannot work out how to generate the URL and send it to Google Sheets as the other code might allow. However the linked code will not allow the user to use the signature pad. I am unsure as to why and I have tried merging the code in different places and taking bits from each, but to no success, everytime I fail due to it not being able to be drawn in, or not knowing how to send to URL to Google Sheets.

Thank you for any help!

When inserting scripts to innerHTML, scripts with DOMContentLoaded are not executed

I made a script that takes the text of a html file and inserts it into another html file; I did this so I don’t need to update my header and sidebar on every page if I make a change. the script works to insert the html but some scripts from the file are not run once inserted into the main html.

function includeHTML() {
    let elements = document.querySelectorAll("[include-html]");

    for (let i = 0; i < elements.length; i++) { 
        const elem = elements[i];
        let file = elem.getAttribute("include-html");
        
        fetch(file).then(response => response.text()).then(data => {
            elem.innerHTML = data; // inject html
            
            let scripts = elem.querySelectorAll("script");
            for (let i = 0; i < scripts.length; i++) { // find scripts
                let script = scripts[i];
                let newScript = document.createElement("script");

                let attrs = script.attributes;
                for (let i = 0; i < attrs.length; i++) { // copy attributes
                    attr = attrs[i];
                    newScript.setAttribute(attr.name, attr.value);
                };
                newScript.innerHTML = script.innerHTML // copy internal script
                script.replaceWith(newScript); // replace script
            };
        }); 
        elem.removeAttribute("include-html");
    };
};

includeHTML();

^ this is my script, after inserting to innerHTML it replaces the scripts, this make some work but not others

<html>
    <head>
        <script defer src="/include.js"></script>
    </head>
    <body>
        <div include-html="/file.html"></div>
    </body>
</html>

^ and this is an example of how I would use it

if the script inserted uses DOMContentLoaded I guess it is inserted after it’s already fired so it isn’t executed, one solution I found is to fire DOMContentLoaded manually after a second but I feel like this could be dependent on the users computer/internet speed, and it would make any scripts elsewhere on the page run twice if they catch the first firing so surely this is not the best way of doing it

by the way I am hosting on neocities so I dont have any backend access, thank you in advance for any help

use chrome extension matches in javascript [duplicate]

In a Chrome extension you can say on which tab url your extension must be active by editing the manifest.json

"content_scripts": [
      {
        "matches": ["https://*.dynamics.com/*", "http://*/*BC*", "https://*/*BC*"],
        "js": ["./src/content.js"]
      }
    ],

This is working but I need those in javascript to check some history urls.

    var matchesArr =  ["https://*.dynamics.com/*", "http://*/*BC*", "https://*/*BC*"];

    for (let i = 0; i < matchesArr.length; i++) {
        var re = new RegExp(matchesArr[i]);
        if (re.test(url)) {
            return true;
        }
    }
    return false;

But this doesn’t return true.

Tried it in regex online sites but I dont want to change the matchesArr values. Just want to know which regex google uses and get a true?

fullPage.js: Page scrolls twice on single scroll event

I’m using fullPage.js to create a website with multiple full-screen sections that scroll between each other. However, I’m encountering an issue where, after scrolling once, the page sometimes scrolls to the next section automatically, even though I haven’t performed any further scroll action. This behavior seems to happen randomly and is more noticeable after the first scroll event.

Steps to reproduce:

Implement a basic fullPage.js setup with autoScrolling: true and multiple sections.

Scroll down using the mouse wheel or trackpad to move between sections.
Occasionally, the page automatically scrolls one more section after the initial scroll, even though no additional scroll event was triggered.

My setup:

fullPage.js version: 4.0.29
Browser: Google Chrome (latest version)
Device: Desktop (with mouse and trackpad)

What I have tried:

Adjusting the scrollingSpeed and fitToSectionDelay parameters.
Disabling continuousVertical mode.

Testing on different devices and browsers.

Despite these changes, the issue persists. Is there a way to prevent this additional unwanted scroll, or any specific settings I should adjust to fix this?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/4.0.29/fullpage.min.css" integrity="sha512-cdMjnD4i86qiUIK3pyOMeYKdJ2I0gy0CVZm2AvGuXgMRDFdoIEI2I/x39pZlRsMaI4IEZBJbsNuWVawly1nY/A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="fullPage">
        <div class="section s1">
            <h1>The first section</h1>
        </div>
        <div class="section s2">
            <h1>The second section</h1>
        </div>
        <div class="section s3">
            <h1>The third section</h1>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/4.0.29/fullpage.min.js" integrity="sha512-jedW9bHnXiSMKNbXfrEQ1gDCRYO8ewRlWPWPf4Fv1LpUyYB0fphiWlUVSGI2Dvwem1gUk0x1Y+cWs4lCwoEo8w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
        new fullpage('#fullPage', {
            autoScrolling: true,
            scrollingSpeed: 1000,
            fitToSection: true,
            fitToSectionDelay: 600,
            touchSensitivity: 15,
            continuousVertical: false
        });
    </script>
</body>
</html>

Uncaught Runtime Error After Successful React Project Build

I’ve successfully built my React project, but I’m encountering an Uncaught runtime error when running the application. The build process completes without errors, but upon starting the app, this runtime issue emerges.

Here are the details:

Uncaught TypeError: Cannot read properties of null (reading 'indexOf')
    at ut.fromString (index.esm2017.js:1032:1)
    at gh (index.esm2017.js:17952:1)
    at Layout.js:377:1
    at Array.forEach (<anonymous>)
    at Array.<anonymous> (Layout.js:373:1)
    at next (index.esm2017.js:20677:1)
    at index.esm2017.js:16739:1
useEffect(() => {
    if (localStorage.getItem("userdata")) {
        setUserRole(JSON.parse(localStorage.getItem("userdata")).role);
    }
    const unsubscribe = onSnapshot(collection(db, "supportRoom"), (snapshot) => {
        if (snapshot.docs.length == 0) {
            setHelpCall(false);
            setHelpCaller({});
        } else {
            const allData = snapshot.docs.map((doc) => ({
                id: doc.id,
                ...doc.data(),
            }));
            allData.forEach((docs) => {
                if (docs.response == false && docs.reciever == "") {
                    setSupportRoomData(supportRoomData);
                    setHelpCall(true);
                    const docRef = doc(db, "users", docs.creater);
                    getDoc(docRef).then((doc) => {
                        setHelpCaller(doc.data());
                        setHelpCallerId(doc.id);
                    });
                } else {
                    setHelpCall(false);
                }
            });
        }
    });
    return () => {
        // cancelHelpCall()
        unsubscribe();
    };
}, [userData]);

I have already tried to check data fetch from firebase, clearing the cache, resinstalling dependencies, but the issue persists.

Has anyone encountered a similar problem or have any suggestions for resolving this runtime error?

Thank you in advance for your help!

MetaMask Not Prompting Transaction Approval via WalletConnect in Mobile Chrome Browser

I’m building a decentralized application (dApp) using Web3Modal, WalletConnect, and ethers.js. The goal is to enable users to connect their mobile wallets (e.g., MetaMask, Trust Wallet) via WalletConnect and approve transactions directly from the mobile browser (Chrome).

Here’s what I’ve implemented:

WalletConnect Configuration: I disabled the QR code and configured the dApp to prompt the WalletConnect modal for mobile wallets.
Transaction Logic: After the wallet connects, I prepare and send a simple ETH transfer transaction using ethers.js.
However, MetaMask or Trust Wallet is not prompting for transaction approval after connecting. Here is my code:

import WalletConnectProvider from "@walletconnect/web3-provider";
import { ethers } from "ethers";
import { getAccount } from '@wagmi/core';

async function deposit() {
  try {
    console.log("calling deposit from wallet connect");

// Ensure the user is connected via Web3Modal
const account = getAccount(config);
console.log("account", account);

if (account.status === 'connected') {
  // Manually create a WalletConnect provider with QR code disabled
  const walletConnectProvider = new WalletConnectProvider({
    infuraId: 'YOUR_INFURA_PROJECT_ID', // Replace with your Infura Project ID
    qrcode: false, // Disable QR code
    qrcodeModalOptions: {
      mobileLinks: ["metamask", "trust"], // Supported mobile wallets
    },
  });

  // Enable session (this opens the mobile wallet modal)
  await walletConnectProvider.enable();

  // Use WalletConnect provider with ethers.js
  const web3Provider = new ethers.BrowserProvider(walletConnectProvider);
  const signer = await web3Provider.getSigner();
  const userAddress = await signer.getAddress(); // Ensure we get the user address

  console.log("Signer address:", userAddress);

  // Prepare and send the transaction (example: sending 0.01 ETH)
  const tx = {
    to: "0x8230aF7feCd83a49732854eDe52A466E949d6992", // Replace with recipient address
    value: ethers.parseEther("0.01") // Transaction amount (0.01 ETH)
  };

  // Send the transaction and wait for the wallet to prompt the user
  const transactionResponse = await signer.sendTransaction(tx);

  console.log("Transaction sent:", transactionResponse.hash);

  // Wait for the transaction to be confirmed
  await transactionResponse.wait();
  console.log("Transaction confirmed");

} else {
  console.error("No connected wallet. Please connect a wallet first.");
}


} catch (error) {
    console.error("Error sending transaction:", error);
    }
      }

   // Example usage: Call deposit when the button is clicked
   document.getElementById('deposit-button').addEventListener('click', async () => {
     await deposit();
  });

What I’ve Tried:

  1. Ensured that the WalletConnect modal opens correctly, but the
    transaction approval is never prompted.
  2. The mobile wallet (MetaMask, Trust Wallet) is connected properly,
    and I can retrieve the address, but the transaction does not prompt
    for approval.
  3. Verified that signer.getAddress() works and the signer is obtained
    correctly. Checked network settings (currently using Sepolia
    testnet).

Expected Behavior:
After connecting via WalletConnect on mobile Chrome, the connected wallet (e.g., MetaMask, Trust Wallet) should prompt the user to approve the transaction.

Actual Behavior:

  1. The wallet connects successfully, but no prompt appears for
    transaction approval. The transaction is not sent, and there are no
    errors in the console.
  2. If I remove qrcode: false, the qr code modal pops up but this doesn’t make sense for a mobile browser as the user would currently be busy using their phone on the dapp.

I’ve been stuck with this issue for over a week. I am using vanilla js unfortunately so I cannot use the react implementations

Blockquote

Seeking Advice on Optimizing the Tech Stack for My SaaS Web Project [closed]

I’m working on a SaaS-based web app project and could use some insights from the community. Here’s a quick rundown of my stack:

Frontend: Next.js
Backend: Node.js (TypeScript) REST APIs
Database: PostgreSQL
Real-time: Socket.io for chat and notifications
Other Tech: Planning to integrate Kafka and Redis soon
The app operates on a multi-tenant architecture, where companies register and I provide each company with separate databases and domains for their services. Everything is subscription-based. Now, I’m looking for advice on a few key areas:

Single API Endpoint for Multi-Tenant System: Should I stick with a single API block to serve all platforms, or could this approach become overloaded? Could it create bottlenecks or other issues at scale? I’m hosting on KVM v4 VPS with Hostinger, so I’m conscious of the limitations.

Tech Stack Adjustments: Do I need to rethink my current stack? I’ve had suggestions to adopt Docker for containerization—could this be beneficial for managing microservices? If so, how would it improve the current setup?

Subscription Management: What’s the best way to handle blocking access when a company’s subscription expires or goes unpaid? Should I disable API access, or is there a more effective method you’d recommend for this kind of scenario?

Kafka and Nginx: On the VPS, I’m running Nginx and planning to integrate Apache Kafka. I’ve been told that Nginx can act as a reverse proxy for Kafka (for example, using Kafka REST Proxy). Could someone explain the setup for this or point me to the best approach for handling it?

I appreciate any guidance or best practices you can share.

Thanks in advance!

Moeez Ahmed

I’m in the process of refurbishing my project and want to first confirm if my current tech stack is solid, especially since I’m planning to add Kafka and Redis for better performance. Additionally, I’m trying to understand how Docker can help improve my setup.

I’m also debating whether to use a single API to serve all tenants or provide each tenant with their own APIs to better handle workload and boost performance. Finally, regarding subscription control, on the API side, should I block API responses for tenants with expired subscriptions, and if so, what’s the best approach for implementing this?

Disable button for 5 seconds with different label and change after it

I’m trying to create an intro in my shiny app using the rintrojs package with the introjs function. My goal is to create an intro where the first next button is disabled for 5 seconds and has a different label like ‘Wait 5 seconds…’. It currently waits 5 seconds and changes from label but it isn’t disabled during the 5 seconds. So you can still click on it. Here is a reproducible example:

library(shiny)
library(rintrojs)

ui <- fluidPage(
  introjsUI(),
  actionButton("start_intro", "Start Intro"),
  h1("Welcome to the Shiny App"),
  p("This is some description of the app.")
)

server <- function(input, output, session) {
  
  steps <- reactive({
    data.frame(
      element = c(NA, "#start_intro"),
      intro = c("Welcome to the app! This first step has a custom button.",
                "This is the start button for the intro tour."),
      position = c("bottom", "bottom")
    )
  })
  
  observeEvent(input$start_intro, {
    introjs(session, 
            options = list(
              steps = steps(),
              nextLabel = "Wait 5 seconds..." 
            ),
            events = list(
              "onbeforechange" = I("
                if (this._currentStep === 0) {
                  var that = this;
                  var nextButton = document.querySelector('.introjs-nextbutton');
                  
                  if (nextButton) {
                    nextButton.innerHTML = 'Wait 5 seconds...';  // Initial label
                    nextButton.disabled = true;                  // Disable the button
                  }
                  
                  setTimeout(function() {
                    that._options.nextLabel = 'next'; // Change label after 5 seconds
                    that._introItems[0].nextLabel = 'next';
                    var nextButton = document.querySelector('.introjs-nextbutton');
                    if (nextButton) {
                      nextButton.innerHTML = 'next';  // Update the label to 'next'
                      nextButton.disabled = false;    // Enable the button after 5 seconds
                    }
                  }, 5000); // 5 seconds delay
                }
              ")
            )
    )
  })
}
 
shinyApp(ui = ui, server = server)

Output:

enter image description here

As you can see it create the ‘Wait 5 seconds…’ button which is also shown for 5 seconds, but it is not disabled during the 5 seconds. So I was wondering how we can create a button which changes from label after 5 seconds and is disabled during the 5 seconds?

Outlook calendar don’t render with FullCalendar

I am developing an app to see the events on my Outlook calendar using fullcalendar, the problem is that I log in to Microsoft, in principle everything is correct, I return to my website but the calendar is not generated, what’s more, if I click again The login button displays a message that the login is still in progress (errorCode === "interaction_in_progress") and i get the console log ‘im inside the else (accounts.length)’ .

This is my code, I can’t find what is causing the calendar and events to not load.

<div id="calendar"></div>

<script>
    let msalInstance;
    const loginRequest = {
        scopes: ["User.Read", "Calendars.Read", "Calendars.Read.Shared"]
    };

    async function mostrarCalendarioOutlook() {
        console.log('I am inside of mostrarCalendarioOutlook');
        try {
            if (!msalInstance) {
                throw new Error("msalInstance is not initialized");
            }
            const accounts = msalInstance.getAllAccounts();
            if (accounts.length > 0) {
                console.log('Dentro del if (accounts.length > 0)');
                const account = accounts[0];
                const tokenResponse = await msalInstance.acquireTokenSilent({
                    account,
                    scopes: ["User.Read", "Calendars.Read", "Calendars.Read.Shared"]
                });
                const events = await getCalendarEvents(tokenResponse.accessToken);
                console.log('initializing render calendar function');
                renderCalendar(events);
            } else {                
                console.log('im inside the else (accounts.length)');
                await msalInstance.loginRedirect(loginRequest);
            }
        } catch (error) {                        
            handleError(error);            
        }
    }

    function handleError(error) {
        if (error.errorCode === "interaction_in_progress") {
            Swal.fire({
                    icon: 'info',
                    title: 'Proceso en progreso',
                    text: 'El proceso de inicio de sesión está en progreso. Por favor, espera a que se complete.',
                    allowOutsideClick: false
                });
        } else if (error.errorCode === "consent_required" || error.errorCode === "interaction_required") {
            Swal.fire({
                icon: 'error',
                title: 'Permisos necesarios',
                text: 'El administrador debe conceder los permisos necesarios para acceder a los calendarios. Contacta al administrador.'
            });
        } else if (error.errorCode === "access_denied") {
            Swal.fire({
                icon: 'error',
                title: 'Acceso denegado',
                text: 'No se pudo acceder a los datos solicitados. Verifica los permisos y vuelve a intentarlo.'
            });
        } else {
            Swal.fire({
                icon: 'error',
                title: 'Error de autenticación',
                text: 'Ocurrió un error durante la autenticación. Por favor, inténtalo de nuevo más tarde.'
            });
            console.error('Error durante la autenticación:', error);
        }
    }    

    document.addEventListener('DOMContentLoaded', async function() {                
        try {
            const msalConfig = {
                auth: {
                    clientId: "Client_ID", 
                    authority: "https://login.microsoftonline.com/common",                    
                    redirectUri: "redirect_Uri",
                    popUp: true
                }
            };

            msalInstance = new msal.PublicClientApplication(msalConfig);            

            //EVENTS
            async function getCalendarEvents(accessToken) {
                console.log('im inside of getCalendarEvents');
                const response = await fetch('https://graph.microsoft.com/v1.0/me/events', {
                    headers: {
                        'Authorization': `Bearer ${accessToken}`
                    }
                });

                if (!response.ok) {
                    const errorText = await response.text();
                    console.error(`Error al obtener los eventos del calendario: ${response.status} ${response.statusText}`, errorText);
                    throw new Error('Error al obtener los eventos del calendario');
                }

                const data = await response.json();
                const events = [];

                function adjustToLocalTime(dateTime) {
                    const date = new Date(dateTime);
                    const timeZoneOffset = date.getTimezoneOffset() * 60000;
                    return new Date(date.getTime() - timeZoneOffset).toISOString();
                }

                const recurringEvents = data.value.filter(event => event.recurrence && event.recurrence.pattern);

                recurringEvents.forEach(event => {
                    const startDate = new Date(event.start.dateTime);
                    const endDate = new Date(event.end.dateTime);
                    const recurrence = event.recurrence.pattern;
                    let instanceDate = new Date(startDate);
                    const endRecurrenceDate = event.recurrence.range && event.recurrence.range.endDate ? new Date(event.recurrence.range.endDate) : null;

                    while (!endRecurrenceDate || instanceDate <= endRecurrenceDate) {
                        if (!recurrence.daysOfWeek) {
                            const adjustedStartDate = new Date(instanceDate);
                            adjustedStartDate.setHours(startDate.getHours());
                            adjustedStartDate.setMinutes(startDate.getMinutes());

                            const adjustedEndDate = new Date(instanceDate);
                            adjustedEndDate.setHours(endDate.getHours());
                            adjustedEndDate.setMinutes(endDate.getMinutes());

                            if (adjustedStartDate <= endRecurrenceDate || !endRecurrenceDate) {
                                events.push({
                                    title: event.subject,
                                    start: adjustToLocalTime(adjustedStartDate.toISOString()),
                                    end: adjustToLocalTime(adjustedEndDate.toISOString()),
                                    allDay: event.isAllDay
                                });
                            }

                            switch (recurrence.type) {
                                case "daily":
                                    instanceDate.setDate(instanceDate.getDate() + recurrence.interval);
                                    break;
                                case "absoluteMonthly":
                                    instanceDate.setMonth(instanceDate.getMonth() + recurrence.interval);
                                    break;
                                case "absoluteYearly":
                                    instanceDate.setFullYear(instanceDate.getFullYear() + recurrence.interval);
                                    break;
                            }

                            continue;
                        }

                        const daysOfWeekIndices = (recurrence.daysOfWeek || []).map(day => {
                            switch (day.toLowerCase()) {
                                case "monday":
                                    return 1;
                                case "tuesday":
                                    return 2;
                                case "wednesday":
                                    return 3;
                                case "thursday":
                                    return 4;
                                case "friday":
                                    return 5;
                                case "saturday":
                                    return 6;
                                case "sunday":
                                    return 0;
                            }
                        });

                        daysOfWeekIndices.forEach(dayIndex => {
                            let tempDate = new Date(instanceDate);
                            while (tempDate.getDay() !== dayIndex) {
                                tempDate.setDate(tempDate.getDate() + 1);
                            }

                            if (tempDate >= startDate && (!endRecurrenceDate || tempDate <= endRecurrenceDate)) {
                                const adjustedStartDate = new Date(tempDate);
                                adjustedStartDate.setHours(startDate.getHours());
                                adjustedStartDate.setMinutes(startDate.getMinutes());

                                const adjustedEndDate = new Date(tempDate);
                                adjustedEndDate.setHours(endDate.getHours());
                                adjustedEndDate.setMinutes(endDate.getMinutes());

                                if (adjustedStartDate <= endRecurrenceDate || !endRecurrenceDate) {
                                    events.push({
                                        title: event.subject,
                                        start: adjustToLocalTime(adjustedStartDate.toISOString()),
                                        end: adjustToLocalTime(adjustedEndDate.toISOString()),
                                        allDay: event.isAllDay
                                    });
                                }
                            }
                        });

                        instanceDate.setDate(instanceDate.getDate() + 7 * recurrence.interval);
                    }

                    if (endRecurrenceDate && recurrence.daysOfWeek) {
                        const tempDate = new Date(endRecurrenceDate);
                        const endRecurrenceDay = tempDate.toLocaleString('en-US', {
                            weekday: 'long'
                        }).toLowerCase();
                        if (recurrence.daysOfWeek.includes(endRecurrenceDay)) {
                            const adjustedStartDate = new Date(tempDate);
                            adjustedStartDate.setHours(startDate.getHours());
                            adjustedStartDate.setMinutes(startDate.getMinutes());

                            const adjustedEndDate = new Date(tempDate);
                            adjustedEndDate.setHours(endDate.getHours());
                            adjustedEndDate.setMinutes(endDate.getMinutes());

                            if (adjustedStartDate.getTime() !== endRecurrenceDate.getTime()) {
                                events.push({
                                    title: event.subject,
                                    start: adjustToLocalTime(adjustedStartDate.toISOString()),
                                    end: adjustToLocalTime(adjustedEndDate.toISOString()),
                                    allDay: event.isAllDay
                                });
                            }
                        }
                    }
                });

                const singleEvents = data.value.filter(event => !event.recurrence);
                singleEvents.forEach(event => {
                    events.push({
                        title: event.subject,
                        start: adjustToLocalTime(event.start.dateTime),
                        end: adjustToLocalTime(event.end.dateTime),
                        allDay: event.isAllDay
                    });
                });

                //console.log("Eventos procesados FINAL:", events);

                return events;
            }

            async function handleLogoutClick() {
                console.log('Cerrando sesion Microsoft...');
                Swal.fire({
                    title: 'Cerrando sesión...',
                    allowOutsideClick: false,
                    didOpen: () => {
                        Swal.showLoading();
                    },
                });

                try {
                    const accounts = await msalInstance.getAllAccounts();
                    if (accounts.length === 0) {
                        Swal.close();
                        return;
                    }

                    const respuesta = await msalInstance.logoutPopup({
                        account: accounts[0],
                    });

                    if (respuesta) {
                        localStorage.setItem('logoutCompleted', 'true');
                        console.log('Sesión Microsoft cerrada correctamente');
                    } else {
                        localStorage.setItem('logoutCompleted', 'false');
                        console.log('No se cerró sesión');
                    }

                    Swal.close();

                } catch (error) {
                    Swal.fire({
                        icon: 'error',
                        title: 'Error al cerrar sesión',
                        text: 'Ocurrió un error al intentar cerrar sesión. Por favor, inténtalo de nuevo más tarde.'
                    });
                    console.log('Error al cerrar sesión Microsoft', error);
                } finally {
                    Swal.close();
                }
            }

            function renderCalendar(events) {
                console.log('Entro a la funcion renderCalendar');
                const calendarEl = document.getElementById('calendar');
                const calendar = new FullCalendar.Calendar(calendarEl, {
                    customButtons: {
                        myCustomButton: {
                            text: 'Refrescar',
                            click: async function() {
                                console.log('Refrescando calendario...');
                                Swal.fire({
                                    title: 'Actualizando Calendario...',
                                    allowOutsideClick: false,
                                    didOpen: () => {
                                        Swal.showLoading();
                                    }
                                });

                                try {
                                    const accounts = await msalInstance.getAllAccounts();
                                    if (accounts.length === 0) {
                                        await msalInstance.loginRedirect(loginRequest);
                                        return;
                                    }

                                    const response = await msalInstance.acquireTokenSilent({
                                        account: accounts[0],
                                        scopes: ["User.Read", "Calendars.Read", "Calendars.Read.Shared"]
                                    });

                                    if (response !== null) {
                                        const accessToken = response.accessToken;
                                        const events = await getCalendarEvents(accessToken);
                                        renderCalendar(events);
                                        Swal.close();
                                        console.log('Calendario refrescado correctamente');
                                    } else {
                                        console.error('No se pudo obtener el token de acceso.');
                                        console.log('Calendario NO refrescado');
                                        Swal.close();
                                    }
                                } catch (error) {
                                    console.log('Error al refrescar calendario');
                                    handleError(error);
                                }
                            }
                        },
                        logout: {
                            text: 'Cerrar Sesión',
                            click: function() {
                                handleLogoutClick();
                            }
                        }
                    },
                    headerToolbar: {
                        left: 'prev,next today myCustomButton logout',
                        center: 'title',
                        right: 'dayGridMonth,timeGridWeek,timeGridDay'
                    },
                    buttonText: {
                        today: 'Hoy',
                        month: 'Mes',
                        week: 'Semana',
                        day: 'Día',
                        list: 'Lista'
                    },
                    initialView: 'dayGridMonth',
                    locale: <?php echo '"' . session('language') . '"'; ?>, //He añadido la seleccion automatica de locale
                    firstDay: 1,
                    events: events,
                    dayMaxEvents: true,
                    eventClick: function(info) {
                        const event = info.event;
                        const title = event.title;
                        const start = event.start;
                        const end = event.end;
                        const allDay = event.allDay;
                        const location = event.extendedProps.location;

                        const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

                        const startFormatted = start.toLocaleString('es-ES', {
                            timeZone: timeZone
                        });
                        const endFormatted = end ? end.toLocaleString('es-ES', {
                            timeZone: timeZone
                        }) : 'Evento de todo el día';

                        let content = `<h2>${title}</h2>`;
                        if (!allDay) {
                            content += `<p><strong>Inicio:</strong> ${startFormatted}</p>`;
                            content += `<p><strong>Fin:</strong> ${endFormatted}</p>`;
                        } else {
                            content += `<p><strong>Evento de todo el día</strong></p>`;
                        }
                        if (location) {
                            content += `<p><strong>Ubicación:</strong> ${location}</p>`;
                        }

                        Swal.fire({
                            title: 'Información del Evento',
                            html: content,
                            icon: 'info'
                        });

                        console.log('Infomacion:' + info.event);
                        console.log('Titulo:' + title);
                        console.log('Inicio:' + start);
                        console.log('Fin:' + end);
                        console.log('Evento Diario:' + allDay);
                    }
                });
                calendar.render();
            }
        } catch (error) {
            console.error('Error during initialization:', error);
            Swal.fire({
                icon: 'error',
                title: 'Error de inicialización',
                text: 'Ocurrió un error al cargar la configuración. Por favor, inténtalo de nuevo más tarde.'
            });
        }
    });
</script>

Thank you very much!!

Prism js AutoLoader does not work when i’m getting text to be rendered in realtime via a websocket

So i’m trying to implement my own ai code assistant chat in vscode,so i used marked js for parsing the text output i get from the backend via openAI api and stream those values to the frontend which works well and good,but i’m having issues with prism js for syntax highlighting because it’s not working at all and i can’t debug why,it actually worked when i added a code block statically to my html page but hasn’t since i have been getting values to be parsed from the server. because the entire html script is long i will divide the snippets into smaller reader chunks that’s most important.
so here’s where i’m adding prism js cdns needed :

<!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
                <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
                <!-- Prism.js Core CSS -->
                <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet">
                <!-- Prism.js Core JS -->
                <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js" integrity="sha512-7Z9J3l1+EYfeaPKcGXu3MS/7T+w19WtKQY/n+xzmw4hZhJ9tyYmcUS+4QqAlzhicE5LAfMQSF3iFTK9bQdTxXg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
                <!-- Prism.js Autoloader Plugin -->
                <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js" integrity="sha512-SkmBfuA2hqjzEVpmnMt/LINrjop3GKWqsuLSSB3e7iBmYK7JuWw4ldmmxwD9mdm2IRTTi0OxSAfEGvgEi0i2Kw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
                

                <title>Chat UI</title>

This is my script section where i basically do all the parsing :

<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
                <script>
                    
                    const vscode = acquireVsCodeApi();
                    //const chatInput = document.getElementById('chat-input');
                    //const sendButton = document.querySelector('.send-btns');
                    const chatBox = document.querySelector('.chatbox');

                    function generateUUID() {
                        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
                            var r = Math.random() * 16 | 0,
                                v = c === 'x' ? r : (r & 0x3 | 0x8);
                            return v.toString(16);
                        });
                    }

                    function typeText(element, text, speed = 20) {
                        let index = 0;
                        let html = '';
                        
                        function type() {
                            if (index < text.length) {
                                if (text.charAt(index) === '<') {
                                    // Handle HTML tags
                                    let tag = '';
                                    while (text.charAt(index) !== '>' && index < text.length) {
                                        tag += text.charAt(index);
                                        index++;
                                    }
                                    tag += '>';
                                    html += tag;
                                    index++;
                                } else {
                                    // Handle text
                                    html += text.charAt(index);
                                    index++;
                                }
                                element.innerHTML = html;
                                setTimeout(type, speed);
                            }
                        }
                    
                        type();
                    }

                    function sendMessage(){
                        const chatBox = document.getElementById('chatbox');
                        const chatInput = document.getElementById('chat-input');
                        const message = chatInput.value;
                        if (message.trim()) {
                            vscode.postMessage({ command: 'sendMessage', value:{
                                "project_path":"random",
                                "storage_name":"PreciousKent8Storage",
                                "user_prompt":message,
                                "thread_id":"thread_YiYMOcOKifXsKbAYRbAXuZGF",
                                "attachments":[
                                    {
                                      "file_id": "file-gXrvfXdCGAbCy2uswrEwCUoY",
                                      "tools": [
                                        {
                                          "type": "file_search"
                                        }
                                      ]
                                    }
                                  ]}
                            })
                            const userMessageDiv = document.createElement('div');
                            userMessageDiv.classList.add('user-message-div');
                            userMessageDiv.innerHTML = `
                                <div class="profile-img-div">
                                    <img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi67elRmCcCkrdJ36cRr6NJCKslrOl7eMTotxXVvBCaYJuBadcb5PxaYm8k9wnmOw8CgoAS9jVAVA1aA7uTcNMa1fhhOXaSX_eucNfmpomSZLPSezm_TH9qa4jYcB54DlOhZdjA3UZz1r3SGnc1uQCd5IQJtwV7Ubm_suNz0U6xHNb5cg/s220/IMG_20240415_205336_841.jpg" alt="User Image"/>
                                </div>
                                <div id="user-message-${generateUUID()}" class="user-message-box">
                                    ${message}
                                </div>
                            `;
                            chatbox.appendChild(userMessageDiv);
                            chatInput.value='';
                        }
                    }

                    function ParseMessage(text){
                        const renderer = new marked.Renderer();
                        renderer.code = (code, language) => {
                            // Define a base class for all code blocks
                            let langBlock="language-"+code.lang
                            
                
                            
                            //console.log("let's see lang",code);
                
                            // Return custom HTML for the code block
                            
                            return `<div class="code-block">
                                            <div class="code-toolbar">
                                                <div class="language-name">${code.lang}</div>
                                                <div class="toolbar-actions">
                                                    <button id="copy-code"><i class="fas fa-clipboard"></i> &nbsp; Copy Code</button>
                                                    <button id="add-to-file"><i class="fa-solid fa-file"></i> &nbsp; Add to File</button>
                                                    <button id="create-new-file"><i class="fa-solid fa-file"></i> &nbsp;Create New File</button>
                                                </div>
                                            </div>
                                            <pre class="scroll-container"><code class=langBlock>${code.text}</code></pre>
                                    </div>`
                        };
                
                        // Set options for marked.js with custom renderer
                        marked.setOptions({
                            renderer: renderer,
                            langPrefix: '' // Prevent marked.js from adding its own lang class
                        });
                        const htmlContent = marked.parse(text);
                        return htmlContent;
                    }

                    // Handle messages from the extension
                    window.addEventListener('message', event => {
                        const message = event.data; // The message sent from the extension
                        switch (message.command) {
                            case 'receiveMessage':
                                const questionId=message.data.question_id;
                                if(localStorage.getItem(questionId)==null){
                                    const aiMessageDiv = document.createElement('div');
                                    aiMessageDiv.classList.add('message-div');
                                    aiMessageDiv.innerHTML = `
                                        <div class="ai-profile-img-div">
                                            <img src="../ai-image" alt="AI Image"/>
                                        </div>
                                        <div id="ai-reply-${message.data.question_id}" class="ai-message-box">
                                            ${ParseMessage(message.data.message.value)}
                                        </div>
                                    `;
                                    document.querySelector('.chatbox').appendChild(aiMessageDiv);
                                    localStorage.setItem(questionId, questionId);
                                }else{
                                    current_message=document.getElementById(`ai-reply-${questionId}`);
                                    current_message.innerHTML='';
                                    typeText(current_message,ParseMessage(message.data.message.value))

                                }
                                
                                
                                break;
                        }
                    });

                    document.addEventListener('DOMContentLoaded', () => {
                        vscode.postMessage({ 
                            command: 'sendMessage', 
                            value: {
                                "project_path":"random",
                                "storage_name":"PreciousKent8Storage"
                            }
                        });
                    });

                    function addScrollListener(scrollElement) {
                        let isScrolling;
                      
                        // Event listener to show the scrollbar thumb on scroll
                        scrollElement.addEventListener('scroll', () => {
                          scrollElement.classList.add('show-scroll');
                      
                          // Clear the timeout for continuous scrolling
                          clearTimeout(isScrolling);
                      
                          // Remove the class after scrolling stops
                          isScrolling = setTimeout(() => {
                            scrollElement.classList.remove('show-scroll');
                          }, 1000); // 1 second delay after scroll stops
                        });
                      }

                    const scrollElements = document.querySelectorAll('.scroll-container');
                    scrollElements.forEach(scrollElement=>{
                        addScrollListener(scrollElement);
                    });

                    
                </script>

so this part of the code :

// Handle messages from the extension
                    window.addEventListener('message', event => {
                        const message = event.data; // The message sent from the extension
                        switch (message.command) {
                            case 'receiveMessage':
                                const questionId=message.data.question_id;
                                if(localStorage.getItem(questionId)==null){
                                    const aiMessageDiv = document.createElement('div');
                                    aiMessageDiv.classList.add('message-div');
                                    aiMessageDiv.innerHTML = `
                                        <div class="ai-profile-img-div">
                                            <img src="../ai-image" alt="AI Image"/>
                                        </div>
                                        <div id="ai-reply-${message.data.question_id}" class="ai-message-box">
                                            ${ParseMessage(message.data.message.value)}
                                        </div>
                                    `;
                                    document.querySelector('.chatbox').appendChild(aiMessageDiv);
                                    localStorage.setItem(questionId, questionId);
                                }else{
                                    current_message=document.getElementById(`ai-reply-${questionId}`);
                                    current_message.innerHTML='';
                                    typeText(current_message,ParseMessage(message.data.message.value))

                                }
                                
                                
                                break;
                        }
                    });

is basically the entry point where i get the values from my websocket server.
my current css styles for the code blocks are below(the ones to change the token styles do not work at all) :

               .code-block {
                        position: relative;
                        background: black; 
                        border-radius: 8px; /* Rounded corners */
                        margin-top:0.6rem;
                        margin-bottom:0.6rem;
                        margin-right:1rem;
                        overflow: hidden;
                        padding-top:2rem!important;
                        box-sizing: border-box;
                    }
            
                    .code-toolbar {
                        position: absolute;
                        top: 0;
                        left: 0;
                        right: 0;
                        background: #333;
                        color: #fff;
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        padding: 0.5rem;
                        font-family: 'Roboto', sans-serif;
                        z-index: 10;
                        box-sizing: border-box;
                    }
            
                    .code-toolbar .toolbar-actions {
                        display: flex;
                        gap: 0.5rem;
                        box-sizing: border-box;
                    }
            
                    .code-toolbar button {
                        background: transparent;
                        display:flex;
                        color: #fff;
                        border: none;
                        border-radius: 4px;
                        padding: 0.5rem;
                        cursor: pointer;
                        box-sizing: border-box;
                    }
            
                    .code-toolbar button:hover {
                        background: transparent;
                    }
            
                    .code-toolbar .language-name {
                        font-weight: 400;
                        color:#a3a2a2;
                    }
            
                    pre {
                        margin: 0;
                        background-color:transparent!important;
                        padding: 1rem;
                    }
            
                    code {
                        display: block;
                        background-color:transparent!important;
                    }

                    /* Custom styles for specific tokens */
                    .token.function {
                    color: #ffcc00;  /* Custom color for function names */
                    }

                    .token.class-name {
                    color: #ff6b6b;  /* Custom color for class names */
                    }

                    .token.variable {
                    color: #5ccfe6;  /* Custom color for variables */
                    }

                    .token.comment {
                    color: #6a9955;  /* Custom color for comments */
                    }

                    .token.keyword {
                    color: #569cd6;  /* Custom color for keywords */
                    }

                    .token.string {
                    color: #ce9178;  /* Custom color for strings */
                    }

How to resolve “useFipsEndpoint: options.useFipsEndpoint ?? false, SyntaxError: Unexpected token ‘?’ “

Before today everything was working fine but somehow now I am getting this error:

useFipsEndpoint: options.useFipsEndpoint ?? false, SyntaxError: Unexpected token ‘?’

My current node version of the project is 12.18.3.

I tried to change the ?? to || as suggested by many posts but there are many packages which uses that and at each time the error occurs in different files.

I also tried to upgrade the Node version, but that is currently not possible. Below is one of the examples :

Debugger attached.
Waiting for the debugger to disconnect...
/Users/abc/Desktop/Projectname/modules/winston-helper/node_modules/@aws-sdk/client-s3/dist-cjs/index.js
    useFipsEndpoint: options.useFipsEndpoint ?? false;
/Users/abc/Desktop/Projectname/modules/winston-helper/node_modules/@smithy/smithy-client/dist-cjs/index.js:323
    this.input = input ?? {};
                        ^

How can i make a select start at a specific point without using selected

We have this select to select year of birth.
Looking at the statistics of last couple of years, most users (close to 70%) are between the ages of 26-34.
When the user opens the select, We want it to start at around 1994 (or age 30), but without selecting ‘1994’ as a default, we can’t seem to make this work.

I do not want 1994 selected by default, as I want to check if the select is actually selected.

This is our current setup for the select:

<select name="year" required>
   <option value="" disabled selected> - </option>
   <?php for ($i = date('Y') - 110; $i <= date('Y'); $i++) : ?>
      <option value="<?php echo $i; ?>" <?php if ($i == $year) echo 'selected'; ?>>
         <?php echo $i; ?>
      </option>
    <?php endfor; ?>
</select>

I’ve looked for a javascript/jquery solution. Found and tried this:

$(document).ready(function() {
            
            const yearToScroll = 1994;
            const birthYearSelect = $('#geboortedatum_jaar');

            // Find the option index of 1994
            const optionIndex = birthYearSelect.find('option[value="' + yearToScroll + '"]').index();

            // Set the scroll position of the dropdown to show 1994
            birthYearSelect.prop('selectedIndex', -1); // Ensures no option is selected
            birthYearSelect[0].selectedIndex = optionIndex;
            
});

But this still selects the ‘1994’ option, making it no different from just putting selected on the 1994 option and not just scroll to that position when opening the select.