jQuery UI+Draggable not working from WordPress?

I am trying to make a jQuery-draggable, on a page in WordPress – inserting in custom html:

<script src="https://howtotrainyourrobot.com/wp-includes/js/jquery/jquery.min.js?ver=3.7.1" id="jquery-core-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1" id="jquery-migrate-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/utils.min.js?ver=6.5.5" id="utils-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/dist/vendor/wp-polyfill-inert.min.js?ver=3.1.2" id="wp-polyfill-inert-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/dist/vendor/regenerator-runtime.min.js?ver=0.14.0" id="regenerator-runtime-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/dist/vendor/wp-polyfill.min.js?ver=3.15.0" id="wp-polyfill-js"></script>
<script src="https://howtotrainyourrobot.com/wp-content/plugins/gutenberg/build/hooks/index.min.js?ver=3aee234ea7807d8d70bc" id="wp-hooks-js"></script>
<script src="https://howtotrainyourrobot.com/wp-content/plugins/gutenberg/build/i18n/index.min.js?ver=5baa98e4345eccc97e24" id="wp-i18n-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/jquery/ui/core.min.js?ver=1.13.2" id="jquery-ui-core-js"></script>
<script src="https://howtotrainyourrobot.com/wp-includes/js/jquery/ui/draggable.min.js?ver=1.13.2"></script>

It gives an error, in page or in jsfiddle trying to have the same code from the blog imported.

https://jsfiddle.net/Programmin/jf2twu3a/1/

Uncaught TypeError: i is not a constructor

Uncaught TypeError: jQuery(…).draggable is not a function

I’m probably missing some obvious script/part?

How to include condition of generated select to where parameter in Codeigniter 4?

My code in COdeigniter 4 model is as following:

public function check_header($id){
    $where_params = [
        'a.id' => $id,
        'fee_status' => 'applied'
    ];
    return $this->db->table('header a')
                    ->select('*, IF(NOW() BETWEEN a.fee_date_active AND a.fee_date_exp, "applied", "exp") AS fee_status')
                    ->where($where_params)
                    ->orderBy('a.id', 'DESC')
                    ->get()->getResult();
}

The problem is I include fee_status in the $where_params where fee_status is generated column from the select query above, returned an error from Codeigniter 4 that told me "Unknown column 'active_status' in 'where clause'".
How do I fix it? Thank you.

Stop/Prevent body From Scrolling To Top On dialog.showModal()

I have a div, with a list of divs, that exceeds the height of the browser window.

Each div is an item of interest, with a onClick event.

Exposing the bad behavior of dialog.showModal():

Scroll To Bottom Of List Causing Top Of Page To Scroll Out Of Sight.

User clicks on a DIV, in the list, and an event is triggered that calls for a dialog to be opened with showModal()

oDlg.showModal() ;

The Page Is Scrolled Back To The Top Causing The div that was clicked on to now scroll out of view below the bottom of the browser window, then the dialog is made visible.

All I Want To Do Is Stop The Body From Scrolling.

I have seen many suggestions that do not work dating back from 2012.

I am hoping since it is now middle of 2024; there is an actual solution to this design flaw of showModal().

Why can the dialog not just open exactly over where the body is currently positioned.

I have tried scrolling the page after the dialog is opened; but then the dialog is scrolled off the top of the page.

I have seen suggestions like <a href=”javascript(void), bootstrap, jquery, body{position:absolute;}.

I tried the position of body; did not change the behavior of showModal.

I am using Pure HTML, Javascript and CSS.

I believe that this behavior, of showModal, is a defect!

Replacing Class Background Color based on inner text

Just can’t figure out why this code won’t work.
I’m trying to replace the background colour of a class based on the inner text of the document.

I don’t have an Id to connect to so I have to search for class.

    <script> 
if (window.location.href.startsWith('https://mytestsite.com.au/')) {
if (( document.documentElement.innerText).indexOf('API') > -1) {
    document.getElementsByClassName('training-card__name').style.backgroundColor = "red";
}
}
</script>

Help appreciated.

I am not able to call a function in Javascript from browser [duplicate]

Code Snippet

When I click on Write button nothing is happening. Also it is showing an error ‘Cannot read properties of null (reading ‘addEventListener’)’ in browser console.

I was expecting that after I click on ‘Write’ button on browser, the function in Javascript file will be called. First it will show a prompt with “Inside Function” after that it will print “Hello All” on console.

Reanimated Carousel blocks navigation gesture

I have a screen that uses reanimated carousel the screen uses material top tab navigation which reqires me to swipe to go to the next screen but the Carousel blocks that
here is the code

<Carousel
        loop={false}
        width={width}
        height={height - 200}
        autoPlay={false}
        vertical
        data={[image, ...images]}
        scrollAnimationDuration={10}
        onSnapToItem={(index) => {
          setCurrentIndex(index);
          if (index > 0) {
            setTimeout(() => {
              setOverlayVisible((prev) => {
                const newVisibility = [...prev];
                newVisibility[index] = false;
                return newVisibility;
              });
            }, 5000);
          }
        }}
        renderItem={({ item: img, index }) => (
          <View style={{ flex: 1 }} key={index}>
            <Image
              source={{ uri: img }}
              style={{
                width,
                height: "100%",
                flex: 1,
                paddingTop: 20,
              }}
              resizeMode="contain"
            />
            <Bubble
              onClick={() => refRBSheet.current[2].open()}
              imageIndex={index === 0 ? -1 : index - 1}
            />
            <CommentOverlay
              visible={index !== 0 && overlayVisible[index]}
              comments={commentsForImages[index] || []}
            />
          </View> 
        )}
      />

here is the navigation code:

import React from "react";
import { createMaterialTopTabNavigator } from "@react-navigation/material-top-tabs";
import MangaReader from "../screens/MangaReader";
import CommentScreen from "../screens/CommentScreen";
import RecordsScreen from "../screens/RecordsScreen";
import ScreenStore from "../store/ScreenStore";
import { useRoute } from "@react-navigation/native";

const Tab = createMaterialTopTabNavigator();

const SwipeNavigation = () => {
  const { secondScreen } = ScreenStore();
  const route = useRoute();
  const params = route.params;

  return (
    <Tab.Navigator
      initialRouteName="Reader"
      screenOptions={{
        headerShown: false,
        tabBarStyle: { display: "none" },
      }}
    >
      <Tab.Screen name="Reader" component={MangaReader} />
      <Tab.Screen
        name={secondScreen}
        component={secondScreen === "Comment" ? CommentScreen : RecordsScreen}
        initialParams={params}
      />
    </Tab.Navigator>
  );
};

export default SwipeNavigation;

I’m trying to access second screen when i swipe right , it works when i remove carousel . I could have use other alterantive like react native swiper or snap carousel but that would cause another issue.

How to ignore lines of code from coverage in vitest?

I have my unit tests setup with vitest and I am looking for a way to ignore specific lines of code from vitest coverage.

Looking for something similar to /* istanbul ignore next */.

Is there something available for vitest?

I skimmed through the docs and tried googling. Found the solution for jest but not vitest.

How can I make sure all my links in my SPA keep the user within my SPA?

I recently started working on my first SPA. There’s some basic JavaScript and php on it right now. Anyway, the biggest issue I’m having right now, is how can I put links inside my SPA without them sending me into an entirely new page and basically ruining the whole purpose of making my website an app. Here is my code. I will explain more after.

index.php

<html>
    <head>
        <link rel="stylesheet" href="./styles/style.css">
    </head>

    <body>
        <?php include './includes/header.php'; ?>

        <div id="main-content">
            <!-- Content will be loaded here dynamically -->
        </div>

        <script>
            document.addEventListener('DOMContentLoaded', () => {
                // Function to load content into the main-content div
                const loadContent = (page) => {
                    fetch(page)
                        .then(response => {
                            if (!response.ok) {
                                throw new Error('Network response was not ok');
                            }
                            return response.text();
                        })
                        .then(data => {
                            document.getElementById('main-content').innerHTML = data;
                        })
                        .catch(error => {
                            console.error('There has been a problem with your fetch operation:', error);
                            document.getElementById('main-content').innerHTML = '<p>Error loading page</p>';
                        });
                };

                // Load the default page
                loadContent('./pages/home.php');

                // Handle navigation click
                document.querySelectorAll('.nav-link').forEach(link => {
                    link.addEventListener('click', (e) => {
                        e.preventDefault();
                        const page = e.target.getAttribute('data-page');
                        if (page) {
                            loadContent(page);
                        } else {
                            console.error('The data-page attribute is missing on the clicked link.');
                        }
                    });
                });
            });
        </script>

    </body>

</html>

header.php

<!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
            <title>Jethro Blemur</title>
            <link rel="preconnect" href="https://fonts.googleapis.com">
            <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
            <link href="https://fonts.googleapis.com/css2?family=Sevillana&family=Tangerine:wght@400;700&display=swap" rel="stylesheet">
            <link rel="stylesheet" href="./styles/style.css">
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
            
            <style>
                #navbar{
                    position: fixed;
                    top: 1vh;
                    right: 1%;
                    width: 15%; 
                    padding: .5% .1%;
                    box-shadow: 10px 10px 10px 1px black;
                    text-align: center;
                    border-radius: 20px;
                    background-color: white;
                }
                #navbar a {
                    font-size: 40px;
                    margin: 1%;
                    text-decoration: none;
                    color: turquoise;
                    text-shadow: 2px 2px 4px #000000;
                    transition: color .5s ease;
                }
                #navbar a:visited{
                    color: turquoise;
                    text-shadow: 2px 2px 4px #000000;
                }
                #navbar a:hover{
                    color:white;
                    background-color: aqua;
                }
                #navbar a:active,
                #navbar a.active{
                    border-bottom: 3px solid white;
                    transition: border-bottom .5s ease;
                }
                #navbar a:active:hover,
                #navbar a.active:hover {
                    border-bottom: 3px solid turquoise;
                }
            </style>
        </head>

        <body>
            <nav id="navbar">
                <a href="#" class="nav-link" data-page="./pages/home.php">Home</a>
                <a href="#" class="nav-link" data-page="./pages/projects.php">Projects</a>
                <a href="#" class="nav-link" data-page="./pages/about.php">About</a>
                <a href="#" class="nav-link" data-page="./pages/contact.php">Contact</a>
            </nav>
        </body>

</html>

about.php

<?php $currentPage = 'about'?>
<link rel="stylesheet" href="./styles/style.css">
<head>
    <title>About me</title>
</head>
<body id="sboutpage">
    <div id="container">
        <h2>About Me</h2>
        <p>
            Some text for now
        </p>
    </div>
</body>

Basically, using my navbar (the contents are in the header.php code) the app works like it should. It just displays the new portion of the app without making me navigate to a new page. However, when I click on one of my quicklinks, it makes me navigate to a new page in other words, it makes me leave the app, which is not what I want. What do I do to make it so that whenever I click on any link in the website, it keeps me in the app? Feel free to ask me any questions if I was not clear enough!

Chatgpt was not very helpful it basically told me to just combined all my pages into one, which defeats the purpose of an app. It would make my code a bit harder to read. Better to have a file for every page.

When the right time to use [Symbol.iterator] in javascript?

so im learnig javascript and i found about [Symbol.iterator], i don’t know what is this, when to use it and why we use it?

class CustomRange {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  [Symbol.iterator]() {
    let current = this.start;
    let end = this.end;
    return {
      next() {
        if (current <= end) {
          return { value: current++, done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
}

let range = new CustomRange(1, 5);

for (let num of range) {
  console.log(num); // 1 2 3 4 5
}

i hose someone tell me about this with easy explanation

How to merge two intersecting shapes using ctxRenderer in vis-network?

I want to get the merged shape and contour of two intersecting ellipses, but now I can’t remove the redundant lines inside and only keep the contour,

{
      id: 1,
      label: "Node5",
      shape: "custom",
      ctxRenderer: ({
        ctx,
        id,
        x,
        y,
        state: { selected, hover },
        style,
      }) => {
        const r = style.size;
        const drawNode = () => {
          ctx.beginPath();
    
          // Draw first ellipse
          ctx.ellipse(x, y, r, r/2, 0, 0, 2 * Math.PI);
    
          // Draw second ellipse, rotated and translated
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(Math.PI / 2);
          ctx.ellipse(0, 0, r, r/2, 0, 0, 2 * Math.PI);
          ctx.restore();
    
          // Close the path
          ctx.closePath();
    
          // Fill and stroke the combined shape
          ctx.fillStyle = "yellow";
          ctx.fill();
          ctx.strokeStyle = "black";
          ctx.stroke();
        };
        return {
          drawNode,
          nodeDimensions: { width: 2 * r, height: 2 * r },
        };
      },
    }

It seems that the closePath() function is not executed correctly, how should I do it correctly?

SDK Object not available when injecting script ReactJS

I am injecting some javascript/sdk into my project via react-helmet. It is successfully injecting the script and min.js link into the head, but I am unable to access any of the objects/functionality that the SDK provides. If I only throw in a console log inside the Helmet it will print out the log though. I am injecting the script on the App.tsx level. If I paste the javascript directly into the head or body of the index file everything works as expected, but I don’t want it to be there for security purposes.

My main question is it is successfully injecting the script in, but why can’t I access anything from it? It comes back as undefined each time.

EDIT

I just did some additional debugging and I think the issue may be that the SDK isn’t fully loaded at the time I am calling it…

App file

<Authentication>
   <Helmet>
     <script type="text/javascript">
     {`
        //some complex javascript goes here
        //some promise/async functions goes here too
     `}
     </script>
   </Helmet>
</Authentication

Can’t get userId to check Refresh Token (express/node authentication)

I am baffled. I am trying to follow a tutorial to create a api with authentication using refresh and access tokens.

I have it working when the access token doesn’t need to be updated/refreshed. However, as soon as it does I run into an issue.

I can’t check if the refreshToken is valid because I am storing refresh token in a database (containing the userId and the refresh token). However, I can’t fetch it, because I can’t get the userId from req.user.userId since the access token is expired meaning that the userId is now undefined. Therefore I can’t see if the refresh token is valid, and can’t create a new access token

/*ISSUE: I need to get userID here to check if the refresh token is valid via database,
  but req.user is undefined since the access token expired */
const storedRefreshToken = await findRefreshToken(req.user.userId);

if (!storedRefreshToken) {
   return res.status(401).json({ error: 'Invalid refresh token' });
}

Maybe I am completely misunderstanding the guide I am following because this makes no sense, feel free to tell me I am completely doing everything wrong

authentication Middleware:

const { verify } = require('jsonwebtoken');
const { findRefreshToken} = require('./userModel');
const { generateAccessToken} = require('./authHelper');

const tokenValidation = async (req, res, next) => {
  const accessToken = req.header('Authorization') ? req.header('Authorization').replace('Bearer ', '') : null;

  if (!accessToken) {
    return res.status(401).json({ error: 'Access token not found' });
  }

  try {
    const decoded = verify(accessToken, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      try {
        const storedRefreshToken = await findRefreshToken(req.user.userId /*I NEED TO GET THE userID here to check if the refresh token is valid but can't*/);

        if (!storedRefreshToken) {
          return res.status(401).json({ error: 'Invalid refresh token' });
        }

        const newAccessToken = generateAccessToken(newRefreshToken);

        req.user = jwt.verify(newAccessToken, process.env.JWT_SECRET);
    res.setHeader('Authorization', `Bearer ${newAccessToken}`);
        next();
      } catch (error) {
        return res.status(401).json({ error: 'Failed to refresh token' });
      }
    } else {
      return res.status(401).json({ error: 'Invalid token' });
    }
  }
};

module.exports = tokenValidation;

User Model for storing/fetching refresh tokens:

const storeRefreshToken = async (userId, refreshToken) => {
  const [result] = await db.execute(
    'INSERT INTO refresh_tokens (userId, refreshToken) VALUES (?, ?) ON DUPLICATE KEY UPDATE refreshToken = VALUES(refreshToken)',
    [userId, refreshToken]
  );
  return result;
};

const findRefreshToken = async (userId) => {
  const [rows] = await db.execute('SELECT * FROM refreshToken WHERE userId = ?', [userId]);
  return rows[0];
};

Generating tokens:

const { sign } = require('jsonwebtoken');

const generateAccessToken = (userId) => {
  return sign({ userId }, process.env.JWT_SECRET, { expiresIn: '10s' }); /*10s for testing*/
};

module.exports = {
  generateAccessToken
};

In React Application when NVDA is on , the accessibility focus is getting lost when using ENTER key, but works with SHIFT + ENTER

I am working on a React application and encountering an accessibility issue with NVDA screen reader. When NVDA is on, the focus is lost after pressing the ENTER key on a button, though it works correctly when pressing SHIFT + ENTER.

Here’s the scenario:

I use the TAB key to navigate and focus on a button.
The button has an onKeyDown event that triggers an asynchronous API call when the ENTER key is pressed.
This functionality works perfectly when NVDA is off. I can use the TAB key to focus on the button and press ENTER to trigger the event without losing focus. However, when NVDA is on, using TAB to focus on the button and pressing ENTER causes the focus to be lost. Interestingly, pressing SHIFT + ENTER works without any issue.

Has anyone encountered a similar issue or can suggest a solution for this?

User not filtering on VirtualSelect option

So i have this livewire component for Approval Configurations, In this page a user selects the Level of Approvals, once the user select the numbes of approvals
it generate VirtualSelect, like if a user select 3 levels it generates 3 VirtualSelect.

Now the problem is it does not filter the ones the are already selected. but it works for some..
Here is the bug explanation

Example User options: Felix K. Bean, Howard G. Sanford, Holly C. Beck
Example:
I selected 3 levels of approvals

Level 1 Approver selected: Felix K. Bean
-other options-
Howard G. Sanford
Holly C. Beck

Level 2 Approver selected: Howard G. Sanford
-other options-
Holly C. Beck

Level 3 Approver selected: Holly C. Beck
-other options-
None

So when i click the Level 1 Approver again it still shows the users that are already selected, And when i check on Level 2 approver the user “Holly C. Beck” still in options even though already seleced on Level 3 approver. But it level 3 Approver the filtering works when i check the options are none.

Can anyone check the code why is it not filtering, but only filters on the higher levels?

Here is my Livewire controller

class CreateHelpTopic extends Component
{
    use Utils, BasicModelQueries;

    public $approvalLevels = [1, 2, 3, 4, 5];
    public $level1Approvers = [];
    public $level2Approvers = [];
    public $level3Approvers = [];
    public $level4Approvers = [];
    public $level5Approvers = [];
    public $approvalLevelSelected;
    public $buDepartment;

    public function cancel()
    {
        $this->reset();
        $this->resetValidation();
        $this->dispatchBrowserEvent('close-modal');
        $this->hideSpecialProjectContainer();
    }

    public function updatedApprovalLevelSelected()
    {
        $this->resetLevels();
        $this->getFilteredApprovers(1);
    }

    public function updatedLevel1Approvers()
    {
        $this->getFilteredApprovers(2);
    }

    public function updatedLevel2Approvers()
    {
        $this->getFilteredApprovers(3);
    }

    public function updatedLevel3Approvers()
    {
        $this->getFilteredApprovers(4);
    }

    public function updatedLevel4Approvers()
    {
        $this->getFilteredApprovers(5);
    }

    public function getFilteredApprovers($level)
    {
        $selectedApprovers = array_merge(
            (array)$this->level1Approvers,
            (array)$this->level2Approvers,
            (array)$this->level3Approvers,
            (array)$this->level4Approvers,
            (array)$this->level5Approvers
        );

        $filteredApprovers = User::with(['profile', 'roles'])
            ->role([Role::APPROVER, Role::SERVICE_DEPARTMENT_ADMIN])
            ->whereNotIn('id', $selectedApprovers)
            ->orderByDesc('created_at')
            ->get();

        $this->dispatchBrowserEvent('load-approvers', ['approvers' => $filteredApprovers, 'level' => $level]);
    }

    protected $listeners = [
        'approver-level-changed' => 'handleApproverLevelChanged',
        'approval-level-selected' => 'updatedApprovalLevelSelected'
    ];

    public function handleApproverLevelChanged($event)
    {
        $level = $event['level'] + 1;
        $this->getFilteredApprovers($level);
    }

    private function resetLevels()
    {
        $this->level1Approvers = [];
        $this->level2Approvers = [];
        $this->level3Approvers = [];
        $this->level4Approvers = [];
        $this->level5Approvers = [];
    }

    public function render()
    {
        return view('livewire.staff.help-topic.create-help-topic', [
            'serviceLevelAgreements' => $this->queryServiceLevelAgreements(),
            'serviceDepartments' => $this->queryServiceDepartments(),
            'buDepartments' => $this->queryBUDepartments(),
        ]);
    }
}

And here is my Blade file

<div>
    <div wire:ignore.self class="modal fade help__topic__modal" id="addNewHelpTopicModal" tabindex="-1"
        aria-labelledby="addNewHelpTopicModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-lg modal-dialog-centered">
            <div class="modal-content modal__content">
                <div class="modal-header modal__header p-0 border-0">
                    <h1 class="modal-title modal__title" id="addNewHelpTopicModalLabel">Add new help topic</h1>
                    <button class="btn btn-sm btn__x" data-bs-dismiss="modal">
                        <i class="fa-sharp fa-solid fa-xmark"></i>
                    </button>
                </div>
                <div class="modal-body modal__body">
                    <!-- Approval Configurations -->
                    <hr>
                    <div class="row">
                        <h6 class="fw-semibold mb-4" style="font-size: 0.89rem;">Approval Configurations</h6>
                        <div class="col-md-6">
                            <div class="mb-2">
                                <label for="department" class="form-label form__field__label">
                                    Level of Approval
                                </label>
                                <div>
                                    <div id="select-help-topic-approval-level" wire:ignore></div>
                                </div>
                                @error('bu_department')
                                    <span class="error__message">
                                        <i class="fa-solid fa-triangle-exclamation"></i>
                                        {{ $message }}
                                    </span>
                                @enderror
                            </div>
                        </div>
                        <div wire:ignore class="row" id="dynamic-approval-container"></div>
                    </div>
                    <!-- Modal Footer -->
                    <div class="modal-footer modal__footer p-0 justify-content-between border-0 gap-2">
                        <div class="d-flex align-items-center gap-2">
                            <button type="submit"
                                class="btn d-flex align-items-center justify-content-center gap-2 m-0 btn__modal__footer btn__send">
                                <span wire:loading wire:target="saveHelpTopic" class="spinner-border spinner-border-sm"
                                    role="status" aria-hidden="true">
                                </span>
                                Add New
                            </button>
                            <button type="button" class="btn m-0 btn__modal__footer btn__cancel" id="btnCloseModal"
                                data-bs-dismiss="modal" wire:click="cancel">
                                Cancel
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

@push('livewire-select')
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const approvalLevelSelect = document.querySelector('#select-help-topic-approval-level');


            const approvalLevels = @json($approvalLevels);
            const approvalLevelOption = approvalLevels.map(approvalLevel => ({
                label: `${approvalLevel} ${approvalLevel >= 2 ? 'Levels' : 'Level'}`,
                value: approvalLevel
            }));


            VirtualSelect.init({
                ele: approvalLevelSelect,
                options: approvalLevelOption,
                search: true,
                markSearchResults: true,
            });

            approvalLevelSelect.addEventListener('change', () => {
                @this.set('approvalLevelSelected', approvalLevelSelect.value);
            });

            const dynamicApprovalLevelContainer = document.querySelector('#dynamic-approval-container');
            const approvers = {};
            let selectedApprovers = [];

            const initializeApproverSelect = (level) => {
                approvers[`level${level}`] = document.querySelector(
                    `#select-help-topic-approval-level-${level}`);
                VirtualSelect.init({
                    ele: approvers[`level${level}`],
                    search: true,
                    multiple: false,
                    showValueAsTags: false,
                    markSearchResults: true,
                    hasOptionDescription: true
                });

                approvers[`level${level}`].addEventListener('change', () => {
                    selectedApprovers[level - 1] = approvers[`level${level}`].value;
                    @this.set(`level${level}Approvers`, approvers[`level${level}`].value);
                    window.dispatchEvent(new CustomEvent('approver-level-changed', {
                        detail: {
                            level
                        }
                    }));
                });

                approvers[`level${level}`].addEventListener('virtual-select:option-click', () => {
                    @this.call('getFilteredApprovers', level);
                });
            };

            approvalLevelSelect.addEventListener('change', () => {
                dynamicApprovalLevelContainer.innerHTML = '';
                selectedApprovers = [];

                for (let i = 1; i <= approvalLevelSelect.value; i++) {
                    const approverFieldWrapper = document.createElement('div');
                    approverFieldWrapper.className = 'col-md-6';
                    approverFieldWrapper.innerHTML = `
                        <div class="mb-2">
                            <label for="department" class="form-label form__field__label">Level ${i} Approver</label>
                            <div>
                                <div id="select-help-topic-approval-level-${i}" wire:ignore></div>
                            </div>
                        </div>`;
                    dynamicApprovalLevelContainer.appendChild(approverFieldWrapper);
                    initializeApproverSelect(i);
                }
                window.dispatchEvent(new CustomEvent('approval-level-selected'));
            });

            window.addEventListener('load-approvers', (event) => {
                const level = event.detail.level;
                const approverSelect = approvers[`level${level}`];
                if (approverSelect) {
                    const approverOptions = event.detail.approvers.filter(approver => {
                        return !selectedApprovers.flat().includes(approver.id);
                    }).map(approver => ({
                        label: `${approver.profile.first_name} ${approver.profile.middle_name ? approver.profile.middle_name[0] + '.' : ''} ${approver.profile.last_name}`,
                        value: approver.id,
                        description: approver.roles.map(role => role.name).join(', ')
                    }));
                    approverSelect.setOptions(approverOptions);
                }
            });

            approvalLevelSelect.addEventListener('change', () => {
                window.dispatchEvent(new CustomEvent('approval-level-selected'));
            });
        });
    </script>
@endpush

JavasScript Open Local File

I am writing a Figma plugin that uses JavaScript and I need to open a file from the plugin folder. This is not JS on a webpage. I mention that because all the JS examples I can find assume a <input type='file'/>.

The code should look something like this:

function readFile (file: File)
{
    let reader = new FileReader() ;
    reader.onload = () =>
    {
        console.log(reader.result) ;
    }
    reader.readAsText(file) ;
}

readFile(new File("folder/File.xml")) ;