Mocha works when using classes but not on functions

Working through a Mocha section of modules on Codecademy, I thought I was getting it but when i tried to practice on my computer for a basic function, it’s not working.

Clearly I am missing something and I am struggling to find the answer.

When I copy and paste the class from codecademy that all works fine on my computer, so I know its not a node/mocha/package.json issue.

The function below is basic just for the purposes of testing mocha.

Any help would be much appreciated.

*Note – The code below includes the code from CodeCademy that works when uncommented. The only difference I can see between the two is that CodeCademy is calling a method from a class.
*

This is the function within index.js

const returnThree = () => {
    return 3;
}
module.exports = returnThree;

/* const Calculate = {
    factorial(inputInt) {
      if (inputInt === 0){
        return 1;
      }
      for(let x = inputInt - 1; x > 0; x --){
        inputInt *= x;
      }
      return inputInt;
    }
    
  }
  
  module.exports = Calculate; */

This is the code within index.js

const assert = require("assert");
const Calculate = require('./index.js')

describe('returnThree', () => {
    it('returns the number three', () =>{
        const expectedAnswer = 3;
        const result = Calculate.returnThree();

        assert.strictEqual(result, expectedAnswer);
    })
});


/*
describe('Calculate', () => {
  describe('.factorial', () => {
    it('returns the multiple of all the integers before it', () => {
      const testNumber = 5;
      const expectedAnswer = 120;

      const result = Calculate.factorial(testNumber);

      assert.equal(result, expectedAnswer);
    });
    it('returns the multiple of all the integers before it', () => {
      const testNumber = 3;
      const expectedAnswer = 6;

      const result = Calculate.factorial(testNumber);

      assert.equal(result, expectedAnswer);
    });
    it('returns 1 when you pass in 0.', ()=>{
      const testNumber = 0;
      const expectedAnswer = 1;

      const result = Calculate.factorial(testNumber);

      assert.equal(result, expectedAnswer);
    })
  });
});
*/

This is what is in the package.json file

{
  "name": "testing-suite",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "mocha indexTest.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "mocha": "^10.7.3"
  }
}

How to refresh subgrid chart?

I have a subgrid on a form in a Power Apps model-driven app which I want to refresh using JavaScript when a custom page is closed. When the subgrid is shown as a ‘normal’ subgrid (not a chart) on the form, it refreshes as expected. However, if select ‘Show chart only’, the chart is not refreshed by the JavaScript. The user has to hit the refresh button to see the new records in the chart.

This is the JavaScript I use to refresh the subgrid:

formContext.getControl("SubgridName").refresh();

[Subgrid settings1

Refresh button on subgrid chart

The weird thing is, that I am 100% sure this was working at one point, because I demoed the functionality for my colleagues where the chart refreshed when the custom page was closed.

Is there any other way, to refresh a subgrid or chart? Or could this potentially be a bug?

Any help is appreciated.

Pass information into Provider from Module OPTIONALLY

I have provider:

export const SomeProvider = {
  provide: "Name",
  inject: [ 
    UserRepository,
    AnotherRepository,

    "ProvidersName",
  ],
  useFactory: async (
    user: UserRepository,
    another: AnotherRepository,  
    options: { throwError?: boolean },
  ) => {

    if (!!user.some((x) => !!x.details["user_account_id"])) {
      return user;
    }

        if (!!another.some((x) => !!x.details["another_account_id"])) {
      return another;
    }

    if (options?.throwError)
      throw new Error("No connection found for someone");
  },
};

And 2 modules:

@Module({
  controllers: [UserController],
  providers: [
    SomeProvider
    {
      provide: "ProvidersName",
      useValue: { throwError: false },
    },
  ],
  imports: [
    TypeOrmModule.forFeature([UserEntity]),
  ],
})
export class UserModule {}


@Module({
  controllers: [AnotherController],
  providers: [
    SomeProvider
    {
      provide: "ProvidersName",
      useValue: { throwError: true },
    },
  ],
  imports: [
    TypeOrmModule.forFeature([AnotherEntity]),
  ],
})
export class AnotherModule {}

I want that 'throwError' was in provider as true by default and I shoudn’t register them in different depended modules. From UserModule I want to rewrite it by setting false. But by default it is true

I tried to register provider in each module but it is not what I want. I want to have a default state of flag to avoid passing the options from all modules but UserModule

is not getting interpreted in string.replace correctly [closed]

I am not able to put character in string using string.replace.

e.g.

const str = '%';
const newStr = str.replace(/[%]/g, '\$&');

console.log(newStr);
document.write(newStr);

//the debugger shows: '\%'
// can also be reproduced if above lines are pasted in node shell or chrome console and value is logged directly without using console.log()

// console.log(newStr) shows %

The newStr’s value is \% though in my opinion it should be %

I have also tried $& as replacer string and it just returns the original string with that.
Am I doing something wrong?

NodeJs version: v20.16.0

Webm audio blob to Wav file Js

i’m trying to convert a webm blob to a wav audio file.

The webm file : no problem to get it from a recorder audio stream

const url = URL.createObjectURL(recording);
const anchor = document.createElement("a");
var filename="audio.webm";
anchor.download =filename;
anchor.href = url;
anchor.click();
window.URL.revokeObjectURL(url);

I think it’s about the stereo channel of the buffer…

I tried this but it does not work :

const arrayBuffer = await new Response(recording).arrayBuffer();
const blob = new Blob([arrayBuffer], { type: "audio/wav" });

I can’t use npm package…

Thanks for your help.

My first JS Image slider, how add transition?

i have been starting to learn HTML / CSS / JS the past few days.
Now I’ve startet my first little project, an absolute simple image-slider in Vanilla JS.
Got it to work, but have no idea how I could add a transition when the images changing.

Anyone can give me some advice what possibilities I have ?

HTML :

<!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="styles.css">
    <link rel="stylesheet" href="font-awesome-4.7.0/css/font-awesome.min.css">
</head>
<body>
    <section id="mainSection">
        <div id="mainDiv">
            <div id="previous" onclick="changeImageBackward()"><i id="arrow" class="fa fa-arrow-left fa-5x" aria-hidden="true"></i></div>
            <div id="mainImage">
                <img class="image"  src="#" alt="">
            </div>
            <div id="next" onclick="changeImageForward()"><i id="arrow" class="fa fa-arrow-right fa-5x" aria-hidden="true"></i></div>
        </div>
    </section>
<script src="script.js"></script>
</body>
</html>

CSS:

#mainDiv {
    background-color: rgb(81, 81, 81);
    height: 40vh;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-evenly
}

#previous {
    background-color: grey;
    height: 80%;
    width: 20%;
    border: solid 1px black;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

#mainImage {
    background-color: rgb(108, 108, 108);
    height: 80%;
    width: 50%;
    border: solid 1px black;
    border-radius: 10px;
    overflow: hidden;
}

#next {
    background-color: grey;
    height: 80%;
    width: 20%;
    border: solid 1px black;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image {
    height: 100%;
    width: 100%;
    object-fit: cover;
}
#next:hover, #previous:hover {
    box-shadow: inset  0 0 40px white;
}


JS:

let image = document.querySelector(".image");
const imageSource = ["bee-8978619_1280.jpg", "forest-8371211_1280.jpg", "mushroom-8313142_1280.jpg", "toadstool-8362901_1920.jpg"];
image.src = imageSource[0];
const next = document.querySelector("#next");
let i=0;


function changeImageForward () {
 if (i < 3){  
    i++  
    image.src = imageSource[i] 
    
    } else {
        i = 0
        image.src = imageSource[i];
    }
};

function changeImageBackward (){
if (i > 0) {
    i--
    image.src = imageSource[i]
} else {
    i = 3
    image.src = imageSource[i]
}
};

I don’t really know where I could start

How can I create a fly-out column menu

I’m trying to develop the following vertical navigation. If parent item has children, show those children in a smooth transition (i’ve used translateX) in a column next to the first one. So for the first level of children, show a new column.

But if those children have child items, you need to show them under each of its parents. From level 2 children, no column layout.

I’ve already created a small poc: https://codepen.io/dennisperremans/pen/MWNvVod But still a lot of issues:

  • in the case of lots of items a scrollbar is shown (which is a must in our case). But the scrollbar causes that I can’t hover the second column because. It disappears before I can even hover it.
  • the transition animation isn’t visible. Probably because of the display: none; on the .menu .menu element ?

General question:

  • What about the mobile navigation? That probably should be done with Javascript because hover isn’t possible.

The code_verifier does not match the code_challenge supplied in the authorization request for PKCE. error

I’m trying to get access token and refresh token of Microsoft account.

const loginAndGetAuthorizationCode = async () => {
const code_verifier = generateCodeVerifier();
const code_challenge = await generateCodeChallenge(code_verifier);

localStorage.setItem('code_verifier', code_verifier);
localStorage.setItem('code_challenge', code_challenge);
const loginRequest = {
  tenant: "common",
  scopes: ["User.Read", "Mail.Read"],
  response_type: "code",
  responseMode: "query",
  state: code_verifier,
  codeChallenge: code_challenge,
  codeChallengeMethod: "S256",
};


try {
  const loginResponse = await msalInstance.acquireTokenRedirect(loginRequest);
  console.log("loginResponse => ", loginResponse);
} catch (error) {
  console.error("Login failed: ", error);
}
};

This is config

import { PublicClientApplication } from "@azure/msal-browser";

const msalConfig = {
    auth: {
        clientId: "ID", // client ID
        authority: "https://login.microsoftonline.com/tenantID", // tenant ID
        redirectUri: "http://localhost:3000/dashboard",
    },
    cache: {
        cacheLocation: "sessionStorage",
        storeAuthStateInCookie: true,
    }
};

const msalInstance = new PublicClientApplication(msalConfig);

await msalInstance.initialize();
// await msalInstance.handleRedirectPromise();

export { msalInstance };

This are utils functions

export function generateCodeVerifier() {


const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
  const array = new Uint8Array(43); // Minimum length of 43
  window.crypto.getRandomValues(array);
  return Array.from(array, (b) => characters[b % characters.length]).join("");
}

// Generate the code challenge from the code verifier
export async function generateCodeChallenge(codeVerifier: string) {
  const encoder = new TextEncoder();
  const data = encoder.encode(codeVerifier);
  const digest = await window.crypto.subtle.digest("SHA-256", data);

  // Convert Uint8Array to an array using Array.from() before processing
  const base64Digest = btoa(String.fromCharCode(...Array.from(new Uint8Array(digest))))
    .replace(/+/g, "-")
    .replace(///g, "_")
    .replace(/=+$/, "");

  return base64Digest;
}

This is backend

@staticmethod
def get_access_token(code, code_verifier):
    url = f'https://login.microsoftonline.com/{MICROSOFT_TENANT_ID}/oauth2/v2.0/token'

    headers = {}

    print("code => ", code)
    print("code_verifier => ", code_verifier)
    data = {
        'client_id': MICROSOFT_CLIENT_ID,
        'grant_type': 'authorization_code',
        'code': code,
        'redirect_uri': MICROSOFT_REDIRECT_URI,
        "code_verifier": code_verifier,
    }
    
    print("code => ", code)
    print("MICROSOFT_CLIENT_ID => ", MICROSOFT_CLIENT_ID)
    print("MICROSOFT_REDIRECT_URI => ", MICROSOFT_REDIRECT_URI)
    print("MICROSOFT_CLIENT_SECRET => ", MICROSOFT_CLIENT_SECRET)

    response = requests.post(url, headers=headers, data=data)
    print("response => ", response.json())

    if response.status_code == 200:
        access_token = response.json()['access_token']
        refresh_token = response.json()['refresh_token']
        return access_token, refresh_token
    else:
        return None, None

I’m getting this error response => {‘error’: ‘invalid_grant’, ‘error_description’: ‘AADSTS501481: The Code_Verifier does not match the code_challenge supplied in the authorization request. Trace ID: 03bb855a-c418-4039-9008-7eec48e91e00 Correlation ID: 6e2d26b8-9a8b-4d06-9326-40ec7659c4a9 Timestamp: 2024-10-21 11:13:56Z’, ‘error_codes’: [501481], ‘timestamp’: ‘2024-10-21 11:13:56Z’, ‘trace_id’: ’03bb855a-c418-4039-9008-7eec48e91e00′, ‘correlation_id’: ‘6e2d26b8-9a8b-4d06-9326-40ec7659c4a9’}

How to Keep a Camera Stream Active Across Pages Without Reinitializing the Camera on Each Page?

I am working on a web application that requires a live camera stream to stay active across multiple pages. The stream is displayed at the top of each page, but currently, the camera stops and reinitializes every time the user navigates to a new page.

I want users to be able to navigate between pages without restarting the camera or causing interruptions in the stream. Ideally, I’d prefer solutions other than converting the site into a Single Page Application (SPA), but I am open to it if it’s the best option.

How to integrate LocationIQAutocomplete data into formData state in React?

I’m working on a React component to create a trip planner. I’m using the useState hook to manage form data with an object called formData, and everything works fine with regular inputs and selections. However, I’m having trouble integrating data from a custom LocationIQAutocomplete component into the same formData state.

Here’s a simplified version of my index.jsx:


import React, { useState, useEffect } from "react";
import LocationIQAutocomplete from "@/components/LocationIQAutocomplete/LocationIQAutocomplete.jsx";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";

function CreateTrip() {
  const [formData, setFormData] = useState({});
  
  const handleInputChange = (name, value) => {
    setFormData({
      ...formData,
      [name]: value,
    });
  };

  useEffect(() => {
    console.log(formData);
  }, [formData]);

  return (
    <div>
      <h2>Tell us your travel preferences</h2>

      {/* Other form inputs */}
      <div>
        <h3>What is your destination choice?</h3>
        <LocationIQAutocomplete />
      </div>

      <div>
        <h3>How many days are you planning?</h3>
        <Input
          type="number"
          onChange={(e) => handleInputChange("noOfDays", e.target.value)}
        />
      </div>

      {/* More inputs... */}
      
      <Button>Generate Trip</Button>
    </div>
  );
}

export default CreateTrip;

Issue:
I can easily update the formData using regular inputs like the one for noOfDays with handleInputChange. However, I’m struggling to update the formData with the selected location data from the LocationIQAutocomplete component.

I passed the data from the autocomplete component as a prop, but I’m unsure how to integrate the selected value from LocationIQAutocomplete into my formData.

How can I capture the selected location from LocationIQAutocomplete and update my formData state in React?

Cannot GET (Express route)

I’m working on a project using JS and Express but when I make a request from JS to the Express server it says ‘Cannot GET /checkInit’ (or any other route other than the first one)

JS (index.js):

$.ajax({
    url: 'http://localhost:3000/checkInit',
    method: 'GET',
    async: false,
    dataType: 'json',
    success: function (data) {
        var format = new Intl.NumberFormat('it-IT', { 
            minimumIntegerDigits: 3,
        });

        $("#numero-azienda").val(format.format(data[0]["numero-azienda"]));
        $("#porto-azienda").val(data[0].porto);
        $("#compilatore-azienda").val(data[0].compilatore);
        compilatore = data[0].compilatore;
        portofranco = data[0].porto;
    },
    error: function (request, status, error) {
        alert(request.responseText);
    }
});

JS (server.js, Express):

app.get('/getData', async (req, res) => {
    try {
        - - -
    } catch (err) {
        console.error('Errore nella query:', err);
        res.status(500).send('Errore nella query al database');
    }
});

app.get('/getDataFiltered', async (req, res) => {
    try{
        - - -
    } catch (err) {
        console.error('Errore nella query:', err.message);
        res.status(500).json({ error: 'Errore nella query' });
    }
});

app.get('/getDataTable', async (req, res) => {
    try{
        - - -
    } catch (err) {
        console.error('Errore nella query:', err.message);
        res.status(500).json({ error: 'Errore nella query' });
    }
});

// Endpoint per ottenere i dati dalla tabella config
app.get('/checkInit', async (req, res) => {
    try{
        - - -
    } catch (err) {
        console.error('Errore nella query:', err.message);
        res.status(500).json({ error: 'Errore nella query' });
    }
});

app.post('/saveInit', async (req, res) => {
    try{
        - - -
    } catch (err) {
        console.error('Errore nella query:', err.message);
        res.status(500).json({ error: 'Errore nella query' });
    }
});

Now I have to say that before this app.get() function there are already 5 app.get() specifying other routes (such as getDataTable or getDataFiltered). One of these 5 is getData (the first one) which is working fine, but all others are not (such as checkInit, getDataTable…).

Issue with Uploading Multiple Images Captured via Mobile Camera

I am working on a web application that allows users to capture and upload images using their mobile devices. The application includes a file input element that accepts multiple image files (PNG, JPEG, JPG) and displays them in a gallery for preview. Users can also remove images from the gallery and view them in fullscreen mode.

The issue arises when users take multiple pictures using the camera directly from the file input. The application successfully uploads images selected from the gallery, but when capturing images directly, the server only receives one image instead of the multiple images that were captured. This problem occurs specifically on mobile devices.

<input id="file-input" type="file" name="images[]"
style="display:none" accept="image/png, image/jpeg, image/jpg"
multiple data-role="none" capture="camera" id="photo"
 onchange="preview()" />

 <div id="gallery-foto" class="gallery"></div>

let images = [];
function preview() {
    const fileInput = document.getElementById('file-input');
    const gallery = document.getElementById('gallery-foto');
    for (let i = 0; i < fileInput.files.length; i++) {
        const file = fileInput.files[i];
        const reader = new FileReader();
        reader.onload = function (e) {
            const imgContainer = document.createElement('div');
            imgContainer.style.position = 'relative';
            const img = document.createElement('img');
            img.src = e.target.result;
            img.onclick = () => openFullscreen(img.src);
            const removeBtn = document.createElement('button');
            removeBtn.classList.add('remove-btn');
            const img5 = document.createElement('img');
            img5.src = "/css/external/Icone/Delete.svg";
            img5.id = "delete";
            img5.alt = "Rimuovi";
            removeBtn.appendChild(img5);
            removeBtn.onclick = (event) => {
                event.stopPropagation();
                gallery.removeChild(imgContainer);
                images.splice(images.indexOf(file), 1);
            };
            imgContainer.appendChild(img);
            imgContainer.appendChild(removeBtn);
            gallery.appendChild(imgContainer);
            images.push(file);
        }
        reader.readAsDataURL(file);
    }
}
function openFullscreen(src) {
    const fullscreenDiv = document.createElement('div');
    fullscreenDiv.classList.add('fullscreen');
    const img = document.createElement('img');
    img.src = src;

    img.onclick = () => {
        document.body.removeChild(fullscreenDiv);
    };
    fullscreenDiv.appendChild(img);
    document.body.appendChild(fullscreenDiv);
}
$request->validate([
'images.*' => 'required|image|mimes:jpg,jpeg,png|max:8000',
'videos.*' => 'nullable|file|mimes:mp4,x-flv,x-mpegURL,MP2T,3gpp,quicktime,x-msvideo,x-ms-wmv|max:20000',
'audios.*' => 'nullable|file|mimes:ogg,mp3,m4a,mp4,mpeg,mpga,wav,aac,webm',
'pdfs.*' => 'nullable|file|mimes:pdf'
]);
if ($request->hasFile('images')) {
 foreach ($request->file('images') as $image) {
  $imageName = $image->hashName();
   $image->storeAs('images', $imageName, 'private');
    Foto::create([
    'attivita_id' => $attività_id,
     'step_id' => $step_id,
      'foto' => htmlspecialchars($imageName, ENT_QUOTES, 'UTF-8')
      ]);
      }
  }

Additionally, I have validation on the server-side to check the uploaded images, but the problem persists only when images are captured directly with the camera on mobile devices.
The same issue also occurs with videos and PDFs.
What could be the problem? Nginx seems to work correctly because everything functions properly from the PC browser.

how to make this horizontal menu start scroll from right to left?

you can see a full demo code for the menu here :

https://codepen.io/testkart/pen/OJBJZbp

document.addEventListener("DOMContentLoaded", function () {
      const scrollImages = document.querySelector(".scroll-images");
      const scrollLength = scrollImages.scrollWidth - scrollImages.clientWidth;
      const leftButton = document.querySelector(".left");
      const rightButton = document.querySelector(".right");

      function checkScroll() {
        const currentScroll = scrollImages.scrollLeft;
        if (currentScroll === 0) {
          leftButton.setAttribute("disabled", "true");
          rightButton.removeAttribute("disabled");
        } else if (currentScroll === scrollLength) {
          rightButton.setAttribute("disabled", "true");
          leftButton.removeAttribute("disabled");
        } else {
          leftButton.removeAttribute("disabled");
          rightButton.removeAttribute("disabled");
        }
      }

      scrollImages.addEventListener("scroll", checkScroll);
      window.addEventListener("resize", checkScroll);
      checkScroll();

      function leftScroll() {
        scrollImages.scrollBy({
          left: -200,
          behavior: "smooth"
        });
      }

      function rightScroll() {
        scrollImages.scrollBy({
          left: 200,
          behavior: "smooth"
        });
      }

      leftButton.addEventListener("click", leftScroll);
      rightButton.addEventListener("click", rightScroll);
    });
#left, #right {
    position: relative;
    float: left;
    margin: 0 5px 0 0;
    border: 1px solid black;
    width: 200px;
    height: 300px;
    overflow: hidden;
}

div.panel {
    position: absolute;
    height: 100%;
    width: 100%;
    display: none;
}

.cover {
    position: relative;
    padding: 0px 30px;
    margin-top: 100px;
}

.left {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}

.right {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
}

.scroll-images {
    position: relative;
    width: 100%;
    padding: 40px 0px;
    height: auto;
    display: flex;
    flex-wrap: nowrap;
    overflow-x: hidden;
    overflow-y: hidden;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
}

.child {
    display: flex;
    justify-content: center;
    align-items: center;
    min-width: 250px;
    height: 200px;
    padding: 0px 15px;
    margin: 1px 10px;
    border: 1px solid #f1f1f1;
    overflow: hidden;
    -webkit-box-shadow: 0px 0px 15px 2px rgb(0 0 0 / 10%);;
    box-shadow: 0px 0px 15px 2px rgb(0 0 0 / 10%);;
}

.child img, .child > svg {
    position: absolute;
    margin-top: -195px;
    width: 80px;
    height: 80px;
    object-fit: cover;
    object-position: center;
    border-radius: 50%;
    background: #03A9F4;
}

.scroll-images::-webkit-scrollbar {
    width: 5px;
    height: 8px;
    background-color: #aaa;
}

.scroll-images::-webkit-scrollbar-thumb {
    background-color: black;
}

button {
    background-color: transparent;
    border: none;
    outline: none;
    cursor: pointer;
    font-size: 25px;
}
<!DOCTYPE html>
<html lang="en">
<!--
For more details-
https://www.testkarts.com/blog/horizontal-card-scroll-with-arrow -->
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <script src="https://kit.fontawesome.com/a59b9b09ab.js" crossorigin="anonymous"></script>
  
  <title>Static Template</title>
</head>

<body>
  <div class="cover">
    <button class="left" onclick="leftScroll()">
      <i class="fas fa-angle-double-left"></i>
    </button>
    <div class="scroll-images">
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-1-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0ZM9.283 4.002H7.971L6.072 5.385v1.271l1.834-1.318h.065V12h1.312V4.002Z"/>
        </svg>
        <h4>Card 1</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-2-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0ZM6.646 6.24c0-.691.493-1.306 1.336-1.306.756 0 1.313.492 1.313 1.236 0 .697-.469 1.23-.902 1.705l-2.971 3.293V12h5.344v-1.107H7.268v-.077l1.974-2.22.096-.107c.688-.763 1.287-1.428 1.287-2.43 0-1.266-1.031-2.215-2.613-2.215-1.758 0-2.637 1.19-2.637 2.402v.065h1.271v-.07Z"/>
        </svg>
        <h4>Card 2</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-3-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-8.082.414c.92 0 1.535.54 1.541 1.318.012.791-.615 1.36-1.588 1.354-.861-.006-1.482-.469-1.54-1.066H5.104c.047 1.177 1.05 2.144 2.754 2.144 1.653 0 2.954-.937 2.93-2.396-.023-1.278-1.031-1.846-1.734-1.916v-.07c.597-.1 1.505-.739 1.482-1.876-.03-1.177-1.043-2.074-2.637-2.062-1.675.006-2.59.984-2.625 2.12h1.248c.036-.556.557-1.054 1.348-1.054.785 0 1.348.486 1.348 1.195.006.715-.563 1.237-1.342 1.237h-.838v1.072h.879Z"/>
        </svg>
        <h4>Card 3</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-4-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0ZM7.519 5.057c-.886 1.418-1.772 2.838-2.542 4.265v1.12H8.85V12h1.26v-1.559h1.007V9.334H10.11V4.002H8.176c-.218.352-.438.703-.657 1.055ZM6.225 9.281v.053H8.85V5.063h-.065c-.867 1.33-1.787 2.806-2.56 4.218Z"/>
        </svg>
        <h4>Card 4</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-5-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-8.006 4.158c1.74 0 2.924-1.119 2.924-2.806 0-1.641-1.178-2.584-2.56-2.584-.897 0-1.442.421-1.612.68h-.064l.193-2.344h3.621V4.002H5.791L5.445 8.63h1.149c.193-.358.668-.809 1.435-.809.85 0 1.582.604 1.582 1.57 0 1.085-.779 1.682-1.57 1.682-.697 0-1.389-.31-1.53-1.031H5.276c.065 1.213 1.149 2.115 2.72 2.115Z"/>
        </svg>
        <h4>Card 5</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-6-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0ZM8.21 3.855c-1.868 0-3.116 1.395-3.116 4.407 0 1.183.228 2.039.597 2.642.569.926 1.477 1.254 2.409 1.254 1.629 0 2.847-1.013 2.847-2.783 0-1.676-1.254-2.555-2.508-2.555-1.125 0-1.752.61-1.98 1.155h-.082c-.012-1.946.727-3.036 1.805-3.036.802 0 1.213.457 1.312.815h1.29c-.06-.908-.962-1.899-2.573-1.899Zm-.099 4.008c-.92 0-1.564.65-1.564 1.576 0 1.032.703 1.635 1.558 1.635.868 0 1.553-.533 1.553-1.629 0-1.06-.744-1.582-1.547-1.582Z"/>
        </svg>
        <h4>Card 6</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-7-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0ZM5.37 5.11h3.972v.07L6.025 12H7.42l3.258-6.85V4.002H5.369v1.107Z"/>
        </svg>
        <h4>Card 7</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-8-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-5.03 1.803c0-1.248-.943-1.84-1.646-1.992v-.065c.598-.187 1.336-.72 1.336-1.781 0-1.225-1.084-2.121-2.654-2.121-1.57 0-2.66.896-2.66 2.12 0 1.044.709 1.589 1.33 1.782v.065c-.697.152-1.647.732-1.647 2.003 0 1.39 1.19 2.344 2.953 2.344 1.77 0 2.989-.96 2.989-2.355Zm-4.347-3.71c0 .739.586 1.255 1.383 1.255s1.377-.516 1.377-1.254c0-.733-.58-1.23-1.377-1.23s-1.383.497-1.383 1.23Zm-.281 3.645c0 .838.72 1.412 1.664 1.412.943 0 1.658-.574 1.658-1.412 0-.843-.715-1.424-1.658-1.424-.944 0-1.664.58-1.664 1.424Z"/>
        </svg>
        <h4>Card 8</h4>
      </div>
      <div class="child">
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-9-circle-fill" viewBox="0 0 16 16">
          <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0Zm-8.223 4.146c2.104 0 3.123-1.464 3.123-4.3 0-3.147-1.459-4.014-2.97-4.014-1.63 0-2.871 1.02-2.871 2.73 0 1.706 1.171 2.667 2.566 2.667 1.06 0 1.7-.557 1.934-1.184h.076c.047 1.67-.475 3.023-1.834 3.023-.71 0-1.149-.363-1.248-.72H5.258c.094.908.926 1.798 2.52 1.798Zm.118-3.972c.808 0 1.535-.528 1.535-1.594s-.668-1.676-1.56-1.676c-.838 0-1.517.616-1.517 1.659 0 1.072.708 1.61 1.54 1.61Z"/>
        </svg>
        <h4>Card 9</h4>
      </div>
    </div>
    <button class="right" onclick="rightScroll()">
      <i class="fas fa-angle-double-right"></i>
    </button>
  </div>
</body>

</html>

when the site is LTR (left to right) the menu is working 100% good .
but in RTL direction it is not working good .
i think that this code force the menu scroll from the left :
if (currentScroll === 0)

how to force the menu to detect rtl or start scroll from right if the site is rtl direction ?

htmx:afterRequest event not working in my HTMX form submission

i am building a simple form to learn HTMX but I am unable to make htmx:afterRequest work properly.

<form autocomplete="off" id="wa-link-form"
                                hx-post="<?= $baseUrl ?>/api/create_link"
                                hx-trigger="submit"
                                hx-target="#result"
                                hx-swap="outerHTML"
                                hx-on="htmx:afterRequest: clearForm(); reissueCsrfToken();">
...
</form>

Here’s my JS function that I want to call:

<script>
        function clearForm() {
            document.getElementById('wa-link-form').reset(); // Reset all form fields
        }

        function reissueCsrfToken() {
            fetch('whatsapp/api/get_csrf_token') // Endpoint that provides a new CSRF token
                .then(response => response.json())
                .then(data => {
                    document.getElementById('csrf_token').value = data.csrf_token; // Update the CSRF token value
                })
                .catch(error => console.error('Error fetching new CSRF token:', error));
        }
    </script>

Please somebody tell me what I am doing wrong?