Please help to add a smoth slider [closed]

so i cant add smoth slider, i have a slider and it’s working good but i need it to work with swipe too, chatgpt and copilot are not helping so please help me,my js knowledge is not good

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Галерея фильмов</title>
    <link rel="stylesheet" href="style.css">
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            overflow-x: hidden;
        }
        
        .slider-container {
            position: relative;
            /* width: 100%; */
            overflow: hidden;
            max-width: 100%; /* 3 x 240px например */
            margin: 0 auto;
            overflow: hidden;
            scroll-behavior: smooth;
            cursor: grab;
        }
        .slider-container:active {
        cursor: grabbing;
      }

        .slider-track {
        display: flex;
        /* gap: 0; Убирает промежутки между элементами */
        transition: transform 0.3s ease-in-out;
        cursor: pointer;
        width: max-content;
    }

    .slide {
        /* flex: 0 0 calc(100% / 3); Показывать 3 изображения одновременно */
        box-sizing: border-box;
        padding: 0; /* Убираем внутренние отступы */
        margin: 0; /* Убираем внешние отступы */
        text-align: center;
        flex: 0 0 220px; /* фиксированная ширина */
        text-align: center;
    }

    .slide img {
        width: 200px;
        height: 120px;
        margin: 0; /* Убираем отступы вокруг изображений */
        border-radius: 13px;
    }

        .slider-buttons {
            position: absolute;
            top: 50%;
            width: 100%;
            display: flex;
            justify-content: space-between;
            transform: translateY(-50%);
        }

        .slider-buttons button {
            border: none;
            padding: 10px 20px;
            cursor: pointer;
            width: 50px;
            height: 50px;
            margin-top: -45px;
            background-color: none;
            color: none;
            background: none;
        }

        .slider-buttons button:hover {
            /* background-color: rgba(190, 190, 190, 0.8); */
        }
        .slider-buttons button img {
            width: 50px;
            height: 50px;
            margin-top: -45px;
            background-color: none;
            color: none;
            margin-left: -28px;
            margin-top: -14px;

        }
    </style>
</head>
<body>
    <div class="slider-container">
        <div class="slider-track">
            <div class="slide">
                <img src="img/a1.jpg" alt="img1">
                <h5>Թթենի 1980</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img2">
                <h5>Фильм 2</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img3">
                <h5>Фильм 3</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img4">
                <h5>Фильм 4</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img5">
                <h5>Фильм 5</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img6">
                <h5>Фильм 6</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img7">
                <h5>Фильм 7</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img8">
                <h5>Фильм 8</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img9">
                <h5>Фильм 9</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img10">
                <h5>Фильм 10</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img11">
                <h5>Фильм 11</h5>
            </div>
            <div class="slide">
                <img src="img/a1.jpg" alt="img12">
                <h5>Фильм 12</h5>
            </div>
        </div>
        <div class="slider-buttons">
            <button id="prev"><img src="img/left.png" alt="left"></button>
            <button id="next"><img src="img/right.png" alt="right"></button>
        </div>
    </div>

    <script>
        const track = document.querySelector('.slider-track');
        const slides = Array.from(track.children);
        const prevButton = document.getElementById('prev');
        const nextButton = document.getElementById('next');
    
        let currentIndex = 0;
        const slidesToShow = 3; // Количество видимых слайдов
        const slideWidth = slides[0].getBoundingClientRect().width;
        let startX = 0;
        let currentTranslate = 0;
        let prevTranslate = 0;
        let animationID = 0;
        let isDragging = false;
    
        function updateSliderPosition() {
            track.style.transition = 'transform 0.3s ease-in-out';
            track.style.transform = `translateX(-${currentIndex * slideWidth}px)`;
        }
    
        function setSliderPosition() {
            track.style.transition = 'none';
            track.style.transform = `translateX(${currentTranslate}px)`;
        }
    
        function animation() {
            setSliderPosition();
            if (isDragging) requestAnimationFrame(animation);
        }
    
        nextButton.addEventListener('click', () => {
            if (currentIndex < slides.length - slidesToShow) {
                currentIndex++;
                updateSliderPosition();
            }
        });
    
        prevButton.addEventListener('click', () => {
            if (currentIndex > 0) {
                currentIndex--;
                updateSliderPosition();
            }
        });
    
        // Mouse and touch events
        track.addEventListener('mousedown', startDrag);
        track.addEventListener('touchstart', startDrag);
    
        track.addEventListener('mousemove', drag);
        track.addEventListener('touchmove', drag);
    
        track.addEventListener('mouseup', endDrag);
        track.addEventListener('touchend', endDrag);
    
        track.addEventListener('mouseleave', () => {
            if (isDragging) endDrag();
        });
    
        function startDrag(e) {
            isDragging = true;
            startX = getPositionX(e);
            prevTranslate = currentTranslate;
            animationID = requestAnimationFrame(animation);
    
            // Убираем переход, чтобы не было задержки при перетаскивании
            track.style.transition = 'none';
        }
    
        function drag(e) {
            if (!isDragging) return;
            const currentPosition = getPositionX(e);
            currentTranslate = prevTranslate + currentPosition - startX;
    
            // Ограничение перемещения
            const maxTranslate = -(slides.length - slidesToShow) * slideWidth;
            if (currentTranslate > 0) {
                currentTranslate = 0;
            } else if (currentTranslate < maxTranslate) {
                currentTranslate = maxTranslate;
            }
        }
    
        function endDrag() {
            isDragging = false;
            cancelAnimationFrame(animationID);
    
            const movedBy = currentTranslate - prevTranslate;
    
            if (movedBy < -slideWidth / 4 && currentIndex < slides.length - slidesToShow) {
                currentIndex++;
            }
    
            if (movedBy > slideWidth / 4 && currentIndex > 0) {
                currentIndex--;
            }
    
            updateSliderPosition();
        }
    
        function getPositionX(e) {
            return e.type.includes('mouse') ? e.clientX : e.touches[0].clientX;
        }
    
        window.addEventListener('resize', () => {
            updateSliderPosition();
        });
    </script>
</body>
</html>

i need it to be smooth swipe,like when i grab it it need to allow me to swipe what positioon i want it to be, and when i drop it it stop to work,i hope you understand i am bad at explaining

i tried chatgpt and copilot but they didin’t help

Can you use Ionic Angular Capacitor with Angular SSR?

I just started implementing Angular SSR with Angular Ionic Capacitor. However I am becoming skeptic if this even works, after running into some issues like:

ERROR ReferenceError: window is not defined
    at impl (./node_modules/@capacitor/preferences/dist/esm/web.js:59:9)
    at <anonymous> (./node_modules/@capacitor/preferences/dist/esm/web.js:13:28)
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:3:1)
    at _next (./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:22:1)
    at executor (./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:27:1)
    at constructor (./node_modules/zone.js/fesm2015/zone-node.js:1385:25)
    at <anonymous> (./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:19:1)
    at get (./node_modules/@capacitor/preferences/dist/esm/web.js:14:26)
    at impl (./node_modules/@capacitor/core/dist/index.js:197:35)

And even more skpetic after reading answers like this one:

“I don’t think Ionic Angular & SSR are a great fit. There are some
older posts here including responses from the team. So I don’t think
that will be resolved soon

Seeing the same when trying to integrate with SvelteKit. So, have to
disable ssr.”

So now my question is, if the two are compatible in general and if anyone managed to combine the two, without issues like the one with the preferences plugin above.

Is there a way to check if an animation is playing on an SVG

I have an issue with an SVG that shows an ugly default state prior to the anim starting.

I had hoped I could set the visibility of the SVG to hidden then check the SVG anim status is playing using js or css and set the visibility to visible.

Unfortunately I have no idea how to do this and I’m struggling to find any helpful documentation.

How to traverse between children of transportationOptions in json? [closed]

This is my JSON

"location" : {
    "address" : "St Katharine's & Wapping",
    "coordinates" : {
      "latitude" : 51.5081,
      "longitude" : -0.0759
    },
    "city" : "London",
    "country" : "United Kingdom",
    "neighborhood" : "Tower Hamlets",
    "transportationOptions" : "[{"_children":{"type":{"_value":"tube"},"details":{"_value":"Tower Hill Station (District and Circle lines)"},"distance":{"_value":"0.3"}},"_nodeFactory":{"_cfgBigDecimalExact":false}},{"_children":{"type":{"_value":"river"},"details":{"_value":"Tower Pier (Thames Clipper)"},"distance":{"_value":"0.1"}},"_nodeFactory":{"_cfgBigDecimalExact":false}}]"
  }
} 

This code is returning undefined, so how do I loop through to print???

const jsonString = JSON.stringify(location);
//console.log(jsonString);

//To convert a JSON string to a JavaScript object, use JSON.parse() method
const parsedJSONObject = JSON.parse(jsonString);
console.log(parsedJSONObject.location);

document.getElementById("address").innerHTML      =   parsedJSONObject.location.address;
document.getElementById("city").innerHTML         =   parsedJSONObject.location.city;
document.getElementById("country").innerHTML      =   parsedJSONObject.location.country;
document.getElementById("neighborhood").innerHTML =   parsedJSONObject.location.neighborhood;

//coordinates
document.getElementById("latitude").innerHTML     =   parsedJSONObject.location.coordinates.latitude;
document.getElementById("longitude").innerHTML    =   parsedJSONObject.location.coordinates.longitude;

//Transportation options
console.log(parsedJSONObject.location.TransportationOptions.children[1].nodeValue);

Google Apps Script isn’t appending paragraphs / tables and is throwing an error that document cannot be found

I am trying to build a quote generator where data is taken from a spreadsheet and put into a document. Multiple items may be chosen, so I want to put one page per spreadsheet item. Therefore I was trying to copy elements from a template document to a new document then change the text. However, no matter which method I try the paragraphs / tables are not appended, and the final message in Apps Script is “Document is missing (perhaps it was deleted, or you don’t have read access?).” No other information, no line noted, nothing.
I’ve tried using SWTICH() and IF() chains and neither work.

function test() {
  const tempDoc = DocumentApp.openById(<ID_1>).getBody();
  const newDoc = DocumentApp.openById(<ID_2>);

  let numEl = tempDoc.getNumChildren();
  let outBody = newDoc.getBody();

  console.log(outBody);

  let el, type;
  for (let j = 0; j < numEl; j++) {
    el = tempDoc.getChild(j).copy();
    type = el.getType();

    switch (type) {
      case DocumentApp.ElementType.PARAGRAPH:
        outBody.appendParagraph(el.asParagraph());
        break;
      case DocumentApp.ElementType.TABLE:
        outBody.appendTable(el.asTable());
        break;
      default:
        console.log("end");
        break;
    }
  }
}

How do I use trim with Vietnamese [closed]

I have a list with Vietnamese words which have some whitespace in front and the back, e.g.: quá .

I’m trying to use the trim function to remove all the whitespace.
Expected result should be quá. But in fact the result is qu only.

I’ve also tested with some other words ending with á and the same problem occurs:

  • " Lá ".trim() => return L;
  • " Má ".trim() => return M

Is this error of this function or I miss something?

console.log("   quá   ".trim());

Is there a way we can get a unique primitive for a given unique object in JavaScript?

This question appears to have been asked 8 years ago, but I’m hoping things have changed since then.

Is there a unique identifier for an object in javascript?

I have a situation relating to data caching/memoization, (specifically using the graphql/dataloader) library where I’ve got some code like this:

const request = new Request('http://example.com'); 
const someObject = {}; 

function myFunction() {

    const result = someOtherFunction({
         request, 
         someObject
    });
    console.log(result); 
}

function myFunction2() {

    const result = someOtherFunction({
         request, 
         someObject
    }, () => {
      return "xyz"; 
    });
    
    console.log(result); 
}


const memoMap = new Map(); 
function someOtherFunction(args, cacheKeyFn) {

    const key = cacheKeyFn ? cacheKeyFn(args) : args; 
    const existingResult = memoMap.get(key); 
    if(existingResult){
        return existingResult; 
    }

    const value = Math.random(); 
    memoMap.set(key, value); 
    return value; 
}

console.log("myFunction"); 
myFunction();
myFunction();
myFunction();
console.log("myFunction2");
myFunction2();
myFunction2();
myFunction2();

The purpose of this someOtherFunction is to memoize the result of this call. However, it determines uniques of the function parameters by shallow compare.

So in this case, although both request and someObject will be the same objects in the repeated calls of myFunction, I’m declaring a new object when I pass them into someOtherFunction and so the result is not memoized.

someOtherFunction does accept a cacheKeyFn, which we can use generate uniqueness another way.

So I’m looking for a way I can create a single primitive, such as a string, from multiple multiple objects.

The best I’ve got is something like this:

const weakMap = new WeakMap(); 
let weakMapCounter = 0; 
function getKeyForUniqueObject(value) {
   if(weakMap.has(value)) {
        return weakMap.get(value); 
   }
   
   const key = `unique-key-for-object-${weakMapCounter++}`; 
   weakMap.set(value, key); 
   return key; 
}


const req = new Request("https://example.com"); 
const obj1 = {}; 
const obj2 = {}; 

console.log(getKeyForUniqueObject(req));
console.log(getKeyForUniqueObject(obj1));
console.log(getKeyForUniqueObject(obj2));
console.log(getKeyForUniqueObject(req));

The use of WeakMap means that I don’t need to worry about the object’s presence in the map preventing its garbage collection.

Is there a much nicer way to do this?

I’ve looked at:

  • Symbol. Both the Symbol constructor, and Symbol.for. But they don’t do what I want.

Zod validation for array of objects

assuming there’s a form with a repeater component so there could be 1, 2, or any number of subforms, like a form of vehicles that could have many vehicles defined.
I want to generate a schema to validate each vehicles’ data.
Issue is that 1 field is mandatory boolean, 2nd field is optional string.

currently generated schema is:

validator = function (formData, validationContext) {
    return Zod.z.object({
        'vehicles': Zod.z.array(Zod.z.object({
            'garageAddressSameAsMailingAddress': Zod.z.boolean().nullish(),
            'garageAddress': Zod.validateIfVisible(Zod.z.any().nullish().refine((value) => {
                if (Zod.evaluateFeel('it.garageAddressSameAsMailingAddress != true', validationContext) === true) {
                    return Zod.z.object({
                        'value': Zod.z.any(),
                        'label': Zod.z.string(),
                        'optionLabel': Zod.z.string().nullish()
                    }).strict().safeParse(value).success
                } else {
                    return true
                }
            }, {message: '$validation_text.mandatory$'}), 'not((it.garageAddressSameAsMailingAddress = true))', validationContext, "$validation_text.field_not_visible$", "$validation_text.feel_not_executable$"),
        }))
    }).strict().safeParse(formData);
}

formData structure:

{
“vehicles” : {garageAddressSameAsMailingAddress: Boolean, garageAddress: String?}[]
}

validationContext is a superset of formData containing more data which is irrelevant

I have tried to use superRefine as well, but failed – the main challenge is having kind of iterator or a reference to the current vehicle object that is being evaluated.

Invalid hook call error in production but working in development

I would like to ask. I am using react ^18.3.1 and also react-redux ^9.2.0 for my project. After deploying the project to production, I am getting some “hooks” error as follows:

useFilterByPermission.js:5 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

useFilterByPermission.js:5 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

chunk-I773Y2XN.js?v=2aedf8be:1062 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
    at useFilterByPermission (useFilterByPermission.js:5:27)
    at AppointmentCalendar (AppointmentCalendar.jsx:20:29)
useFilterByPermission.js:5 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

useFilterByPermission.js:5 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

chunk-I773Y2XN.js?v=2aedf8be:1062 Uncaught TypeError: Cannot read properties of null (reading 'useContext')
    at useFilterByPermission (useFilterByPermission.js:5:27)
    at AppointmentCalendar (AppointmentCalendar.jsx:20:29)

I created a custom hook that uses useSelector fromRedux:

useFilterByPermission.js

import { useSelector } from "react-redux";

const useFilterByPermission = () => {
  const { currentUser } = useSelector((state) => state.auth);

  const hasPermission = (permission) => {
    return currentUser?.permissions?.includes(permission);
  };

  const filterItemsByPermission = (items) => {
    return items.filter(
      (item) => !item.permission || hasPermission(item.permission)
    );
  };

  return { hasPermission, filterItemsByPermission };
};

export default useFilterByPermission;

And I am calling the custom hooks inside a React Component:

import React, { useEffect } from "react";
import { useNavigate } from "react-router-dom";
// import getIcon from "@/utils/getIcon";
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from "@fullcalendar/interaction";
import { useDispatch, useSelector } from "react-redux";
import { fetchAllAppointments } from "@/store/slice/appointmentSlice";
import { format } from "date-fns";
import { PERMISSIONS } from "../../../shared/permissionsConstant";
import useFilterByPermission from "@/hooks/useFilterByPermission";

const AppointmentCalendar = () => {
  const navigate = useNavigate();
  const dispatch = useDispatch();
  const { appointments } = useSelector((state) => state.appointments)
  const { hasPermission } = useFilterByPermission();

  useEffect(() => {
    dispatch(fetchAllAppointments())
  }, [])
  return (
    <>
      {hasPermission(PERMISSIONS.APPOINTMENTS.VIEW) &&
              <div className="card">
                <div className="card-body">
                  <div className="card-body custom-card-action p-0">
                    <FullCalendar
                      height={'auto'}
                      plugins={[timeGridPlugin, dayGridPlugin, interactionPlugin]}
                      initialView="timeGridDay"
                      eventDisplay="auto"
                      firstDay={1}
                      hiddenDays={[7]}
                      eventMaxStack={1}
                      slotMinTime={"10:00:00"}
                      eventClick={(info) => navigate(`/appointments/${info.event.id}`)}
                      eventTimeFormat={{
                        hour: 'numeric',
                        minute: '2-digit',
                        hour12: false,
                      }}
                      eventBackgroundColor="red"
                      headerToolbar={{
                        left: 'prev,next',
                        center: 'title',
                        right: 'timeGridDay,timeGridWeek,dayGridMonth'
                      }}
                      events={appointments.map(item => ({
                        id: item.id,
                        title: item.title,
                        start: `${format(item.appointmentDate, 'yyyy-MM-dd')} ${item.appointmentTime.split(' - ')[0]}`,
                        end: `${format(item.appointmentDate, 'yyyy-MM-dd')} ${item.appointmentTime.split(' - ')[1]}`,
                      }))}
                  />
              </div>
          </div>
      </div>}
    </>
  );
};

export default AppointmentCalendar;

As what I have read, I think I am not breaking the React hooks rules but I keep on getting this error.

Add left/right navigation arrows to WooCommerce product gallery

I’m using WooCommerce with the following theme:
https://demo2.wpopal.com/bikys/shop/cube-nature-pro/

On the product detail page, the default product gallery only allows switching product images by clicking the thumbnail images below the main image.

I want to enhance the user experience by adding left and right arrow buttons to the sides of the main images, so that visitors can navigate through the gallery more easily.

I’ve implemented the feature using the code below:

    <style>
.woo-gallery-nav {position: absolute;top: 50%;z-index: 10;transform: translateY(-50%);background: rgba(0,0,0,0.5);color: #ffdb00;font-size: 30px;width: 30px;height: 30px;line-height: 30px;text-align: center;cursor: pointer;user-select: none;border-radius: 15px;transition: all 0.3s ease;}
.woo-gallery-nav:hover {background: rgba(0,0,0,0.8);}
.woo-gallery-nav.prev {left: 0px;}
.woo-gallery-nav.next {right: 0px;}
.flex-control-thumbs li {cursor: pointer;transition: opacity 0.3s ease;}
.flex-control-thumbs li.flex-active {opacity: 0.7;border: 2px solid #333;}
.woocommerce-product-gallery__image {transition: opacity 0.5s ease;}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
  function initializeGalleryNavigation() {
    const galleryWrapper = document.querySelector(".woocommerce-product-gallery__wrapper");
    const slides = Array.from(galleryWrapper.querySelectorAll('.woocommerce-product-gallery__image'));
    const thumbs = Array.from(document.querySelectorAll(".flex-control-thumbs li"));
    if (!slides.length || !thumbs.length) {
      setTimeout(initializeGalleryNavigation, 100);
      return;
    }
    let currentIndex = slides.findIndex(slide => slide.classList.contains('flex-active-slide'));
    if (currentIndex === -1) currentIndex = 0;
    const prevBtn = document.createElement("div");
    prevBtn.className = "woo-gallery-nav prev";
    prevBtn.innerHTML = "‹";
    const nextBtn = document.createElement("div");
    nextBtn.className = "woo-gallery-nav next";
    nextBtn.innerHTML = "›";
    galleryWrapper.parentNode.appendChild(prevBtn);
    galleryWrapper.parentNode.appendChild(nextBtn);
    function updateGallery(index) {
      if (index < 0) index = slides.length - 1;
      if (index >= slides.length) index = 0;
      thumbs[index].querySelector('img').click();
      currentIndex = index;
    }
    prevBtn.addEventListener("click", () => updateGallery(currentIndex - 1));
    nextBtn.addEventListener("click", () => updateGallery(currentIndex + 1));
    document.addEventListener("keydown", (e) => {
      if (e.key === "ArrowLeft") updateGallery(currentIndex - 1);
      if (e.key === "ArrowRight") updateGallery(currentIndex + 1);
    });
    thumbs.forEach((thumb, i) => {
      thumb.addEventListener("click", () => {
        currentIndex = i;
      });
    });
  }
  initializeGalleryNavigation();
});
</script>

and it’s somewhat functional. However, I’ve encountered a small bug on mobile devices:
When using the arrow buttons to switch images, the logic sometimes conflicts with the default thumbnail click behavior. For example, clicking the arrows may occasionally cause the thumbnails to stop working, or clicking a thumbnail may cause the arrow buttons to stop functioning correctly.

Is this an issue with how I’m handling the event bindings or gallery state? Do I need to further optimize my JavaScript to handle mobile interactions more gracefully?

Thanks in advance!

Undo the last visual change made by the mouse one by one by clicking on DIV

The goals here is when you click on the UNDO div, the last visual change made by the mouse should be undone one by one.

There are 2 div’s you can click on that make changes:

  1. kopje: This is a used as a collapse menu.

  2. taak: if you click on this, the DIV will be removed.

The undo div should undo any changes.

Example:

I expand a DIV kopje by clicking on it. After that I delete a task by clicking on it.

If I click on the undo div the task should come back on the same place where it was. If I then click undo again the div kopje should close.

// Find all headers
const kopjes = document.querySelectorAll('.kopje');

// Add a click event to each header
kopjes.forEach(kopje => {
  kopje.addEventListener('click', function() {
    // Find the task divs that come directly after the header
    let taken = [];
    let nextElement = kopje.nextElementSibling;
    while (nextElement && nextElement.classList.contains('taak')) {
      taken.push(nextElement);
      nextElement = nextElement.nextElementSibling;
    }

    // Check if the task divs are already visible
    const isVisible = taken.some(taak => taak.style.display === "block");

    if (isVisible) {
      // If they are visible, hide them
      taken.forEach(taak => {
        taak.style.display = "none";
      });
    } else {
      // If they are hidden, show them
      taken.forEach(taak => {
        taak.style.display = "block";
      });
    }
  });
});

// Remove task divs with delay and color change
document.querySelectorAll('.taak').forEach(taak => {
  taak.addEventListener('click', function() {
    // Temporarily change the background color of the task
    this.style.backgroundColor = "#128771"; // Red temporarily

    // Wait a few seconds and then remove the task
    setTimeout(() => {
      this.remove(); // Remove the task div
    }, 100); // Remove after 500ms
  });
});

// Function for reset (optional)
document.querySelector('.knop_reset').addEventListener('click', () => {
  document.querySelectorAll('.taak').forEach(taak => {
    taak.style.display = "none"; // Hide all tasks
  });
});
body {
  background-color: #000000;
  margin: 0px;
}

.kopje {
  background-color: #128771;
  color: #FFFFFF;
  cursor: pointer;
  padding: 15px 8px 15px 10px;
  font-size: 20px;
  font-family: Arial;
}

.taak {
  display: none;
  /* Standaard niet zichtbaar */
  color: #FFFFFF;
  padding: 15px 8px 15px 10px;
  font-size: 20px;
  font-family: Arial;
  cursor: pointer;

}

.knop_undo {
  background-color: #FFFFFF;
  padding: 20px 20px;
  font-size: 16px;
  cursor: pointer;
  position: fixed;
  z-index: 1000;
  left: 150px;
  bottom: 10px;
}

.knop_reset {
  background-color: #FFFFFF;
  padding: 20px 20px;
  font-size: 16px;
  cursor: pointer;
  position: fixed;
  z-index: 1000;
  left: 10px;
  bottom: 10px;
}
<div class="kopje">KOPJE 1</div>
<div class="taak">taak 1</div>
<div class="taak">taak 2</div>
<div class="taak">taak 3</div>

<div class="kopje">KOPJE 2</div>
<div class="taak">taak 1</div>
<div class="taak">taak 2</div>
<div class="taak">taak 3</div>

<div class="kopje">KOPJE 3</div>
<div class="taak">taak 1</div>
<div class="taak">taak 2</div>
<div class="taak">taak 3</div>

<div class="knop_undo">Undo</div>
<div class="knop_reset">Reset</div>

I want to create a callable navigation bar so that when I need to update it, it will automatically update the navigation bar for all pages

I currently have a site where I want to create a navigation bar where when I add a page to the nav bar, it will automatically add it to all pages that I have currently uploaded to my site.

I currently have a script for a “Back to Top” button as well as a script for a responsive navigation bar. I’m now looking to add a script that will load the nav bar from another HTML page that contains my actual nav bar. But for some reason, even after adding the script, the nav bar isn’t loading for some reason.

Below is my main index.html page that contains all the scripts:

<!doctype html>
<html lang="en-US">
<head>
    <title>Title</title>
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <meta charset="utf-8">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
    <script src="https://kit.fontawesome.com/0a48c3a8e0.js" crossorigin="anonymous"></script>
    <script>
        $(document).ready(function() {
            $("#nav-placeholder").load("nav.html")
        })
    </script>
    <link href="styles/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <button onclick="topFunction()" id="myBtn" title="Go to top">Back to Top</button>
    <script src = "scripts/topnav.js"></script>
    <script src = "scripts/topbutton.js"></script>
    <div id = "nav-placeholder"></div> 
    <header>
        <nav class = "topnav" id = "myTopnav">
            <h1 class = "logo">General Gaming Guides</h1>
            <a href = "javascript:void(0);" class = "icon" onclick = "myFunction()">
                <i class = "fa fa-bars"></i>
            </a>
        </nav>
    </header>
    <div class = "middle_text">
        Text here.
    </div>
</body>
</html>

And my navigation bar page called nav.html code is here:

<div>
    <ul class = "mainnav">
        <li><a href = "index.html">Home</a></li>
            <li><a href = "games.html">Games</a>
                <ul class = "gamesnav">
                    <li><a href = "lostark.html">Lost Ark</a>
                        <ul class = "subnav">
                            <li><a href = "news.html">News</a></li>
                            <li><a href = "patch_notes.html">Patch Notes</a></li>
                            <li><a href = "beginner_guide.html">Beginner's Guide</a>
                                <ul class = "subnav2">
                                    <li><a href = "character_info.html">Understanding Game Design</a></li>
                                    <li><a href = "road_to_50.html">Road to Level 50</a></li>
                                </ul>
                            </li>
                            <li><a href = "dailies.html">Dailies</a></li>
                            <li><a href = "weeklies.html">Weeklies</a></li>
                            <li><a href = "current-events.html">Current Events</a></li>
                            <li><a href = "abyssaldungeons.html">Abyssal Dungeons</a></li>
                            <li><a href = "legionraids.html">Legion Raids</a>
                                <ul class = "subnav2">
                                    <li><a href = "valtan-gate-1-guide.html">Normal Mode</a></li>
                                    <li><a href="valtan-hell-gate-1.html">Inferno/Extreme Mode</a></li>
                                </ul>
                            </li>
                            <li><a href = "kazerosraids.html">Kazeros Raids</a></li>
                            <li><a href = "adventure_islands.html">Adventure Islands</a></li>
                        </ul>
                    </li>
                </ul>
            </li>
        <li><a href = "about.html">About</a></li>
        <li><a href = "support.html">Support</a></li>
    </ul>
</div>

Any help to get it to show would be appreciated!

Is it possible for pipeThrough and TransformStream to produce a byte stream?

The following code does not work. It produces the error Failed to execute 'getReader' on 'ReadableStream': Cannot use a BYOB reader with a non-byte stream Even though byteStream started out life as a byte stream, piping it through transformedStream turned it into a non-byte stream. I can’t find anywhere how to create a TransformStream that inputs and outputs byte streams.

const byteStream = new ReadableStream({
    type: "bytes",
    pull(controller) {
        controller.enqueue(new Uint8Array([1, 2, 3, 4]))
        controller.close()
    }
})

const identityTransform = new TransformStream({
    transform(chunk, controller) {
        controller.enqueue(chunk)
    }
})

const transformedStream = byteStream.pipeThrough(identityTransform)

const reader = transformedStream.getReader({ mode: "byob" })

Is there a better way to make my browser action show a popup when left clicked but do something else when shift-clicked?

I’m writing my first firefox browser extension. I want to have a typical pop-up appear when my browser action is clicked, but I also want users to be able to Shift+click or Ctrl+click on the browser action to quickly execute certain actions.

Because the browserAction.onClicked() event doesn’t fire if the browser action has a popup (default or otherwise, per the Mozilla documentation), the only way I’ve figured out how to achieve this functionality is the following code (in my background.js).

My method doesn’t seem like it should be the intended method of accomplishing this. Is there a better way to do this?

I have written the following code:

// Show the popup if the browser action is clicked on with no other key pressed
// Do something else if shift or control is held when the browser action is clicked
function browserActionClickHandler(tab, data){
    // If no other key was held, or more than one key was held, enable the popup, open it, then disable it so the onClicked event will fire on future clicks
    if(data.modifiers.length == 0 || data.modifiers.length > 1){
        browser.browserAction.setPopup({ popup: "popup.html"});
        browser.browserAction.openPopup();
        browser.browserAction.setPopup({ popup: null});
    }else if(data.modifiers.includes("Shift")){
        // Do something
    }else if(data.modifiers.includes("Ctrl")){
        // Do something else
    }
}

browser.browserAction.onClicked(browserActionClickHandler);

This code produces the result I want, but it doesn’t seem right to me that enabling, manually opening, and then disabling the popup is the only way to produce this functionality. Because I don’t know a lot about writing browser extensions, I wonder if there is a better way to do this.