Laravel 9 Ajax Update Record Returning 404 error

I am trying to update a database record with ajax. The code below is returning a 404 error code.

Javascript

 data = {
         id: item_id,
         our_cost: new_price,
         _token: "{{csrf_token()}}",
      };

 $.ajax({
        url: '/change_item_price/{id}/{our_cost}',
        data: data,
        type: 'POST',
        success: function( data ) {
             console.log(data);
        }
      });

Route

Route::post('/change_item_price/{id}/{our_cost}',[itemController::class, 'change_item_price'])->name('change_item_price');

Controller

    public function change_item_price($id, $our_cost){
        $get_id = Item::findOrFail($id);
        DB::table('items')
            ->where('id', $get_id)
            ->update([
                'our_cost' => $our_cost
            ]);
        return Item::where('id',$id)->first();
    }

Is there a way to make something scroll when the users mouse is not in the scroll area

Ok, so this is a pretty tricky question. How can you make something scroll when the users mouse isn’t in the scroll area? An great example is from apple’s [IPad Mini page.][1] At the very front, you can scroll the text while your mouse isn’t at the scroll area at the top. I want to do something like this in my webpage. Here is my code:

#scroll-text-vr {
    color:white;
    text-align: center;
    font-family: "Pixelify Sans", Arial, Helvetica, sans-serif;
    font-size: 50px;
    overflow-y: scroll;
    height:10vh;
    background-color: black;
    padding-top: -200px;
    margin: 0px;
    line-height: 5px;
}
.vr-text-scroll {
    padding-top:90px;
}
#vr-image-scroll {
    height:90vh;
    width:100vw;
    object-fit: contain;
    background-color: black;
}
#vr-animation {
    position: sticky;
    top: 0;
    height:100vh;
    width:100vw;
}
#vr-animation-scroller {
    height:300vh;
    width:100vw;
    background-color: black;
    position: relative;
}
#content {
 height:1000vh;
 }
 <div id="vr-animation-scroller">
    <div id=vr-animation>
    <div id="scroll-text-vr">
        <p>Experience It.</p>
        <p class="vr-text-scroll">Immerse in It.</p>
        <p class="vr-text-scroll">Push the Gas.</p>
        <p class="vr-text-scroll">Turn the Wheel</p>
        <p class="vr-text-scroll">Fly the plane.</p>
        <p class="vr-text-scroll">You Know It.</p>
        <p class="vr-text-scroll">You Love It.</p>
        <p class="vr-text-scroll">It's VR</p>
    </div>
    <img id="vr-image-scroll" src="vrimage.jpg"/>
</div>
</div>
<div id="content">
<p>some more content...</p>
</div>

Also, make sure to look at the snippet in fullscreen.

Thanks for any help you can provide.
[1]: https://www.apple.com/ipad-mini/

How to get eslint to select jsx elements that have a className with a particular class?

I am implementing eslint, and I am using 'no-restricted-syntax' to create custom selections my selection looks like this:

  'no-restricted-syntax': [
    'error',
    {
      selector: 'JSXElement JSXAttribute JSXIdentifier[name="className"] + Literal[value="bg-red"]',
      message: 'Do not set background colors directly.',
    },
  ],

I am testing the code on this test component, and it isn’t finding the error:

export function TestComponent() {
  return <button className="bg-red">Click me</button>;
}

I have also tried modifying my selector to these without luck:

// On the attribute
JSXElement JSXAttribute[name="className"][value="bg-red"]

// removing the + Literal
JSXElement JSXAttribute JSXIdentifier[name="className"][value="bg-red"]

How can I get eslint to select jsx elements that have a className containing a particular class (or even better a class that starts with bg)?

If it helps, here is the ESLint explorer

NotAllowedError on datetime-local input when swiping between applications

I’ve got an Angular Material datetime-local input like so:

<input
  matInput
  #startDatePicker
  type="datetime-local"
  step="1"
  formControlName="startDate"
  placeholder="Select start date"
  (focus)="startDatePicker.showPicker()"
  max="9999-12-31T23:59:59"
  required />

If I focus the input to open the calendar picker and either swipe to a fullscreen app then swipe back, or even just change tabs then change back, I get:

NotAllowedError: Failed to execute 'showPicker' on 'HTMLInputElement': HTMLInputElement::showPicker() requires a user gesture.

From what I understand, it’s specifically wanting a click or touch from the user. That said, I’d prefer to use (focus) instead of (click) on the input just in case someone wants to Tab into it to focus it.

I assume the Mac/Chrome is “re-focusing” the last selected input when I return to the window by itself, thus causing the error. I’d appreciate any advice:

  • Is there a way to suppress the “re-focus” entirely?
  • Should I just suppress the error itself in my application?
  • Or is there another way I could swap out (focus) and get my desired similar functionality?

Thanks for your time!

Dropdown menu contents gone after form submission in Livewire component

I am currently making a component for my website with Laravel Livewire. I have a multi-select dropdown where the options are dynamically generated with JavaScript. Issue is, after form submission the options within here are gone:

<div id="dropdown" style="display: none;"
class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
wire:ignore.self>
<!-- Dynamically generated options will go here -->
</div>

The problem is, that I can’t use the newest Alpine version with @livewireScripts since I’m using a library of components for my website that has Alpine v2.8 packed into the code. I would extract the code the components need from there, but I can’t since it’s all mixed together.
I’ve been stuck on this issue for like 3 hours now and I give up.
So basically the code works fine until the form within the livewire component is refreshed and poof! The dropdown list is gone.

Here’s my frontend (both console logs within the send-message event work fine):

<div class="relative">
                    <label class="block text-sm mb-1" for="roles">Mention roles</label>
                    <div class="mt-1 relative">
                        <button type="button" id="toggleDropdown"
                            class="relative w-full bg-white border border-gray-200 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary sm:text-sm">
                            <span id="displayText" class="block truncate">Select roles</span>
                            <span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
                                <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg"
                                    viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
                                    <path fill-rule="evenodd"
                                        d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
                                        clip-rule="evenodd" />
                                </svg>
                            </span>
                        </button>

                        <div id="dropdown" style="display: none;"
                            class="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
                            wire:ignore.self>
                            <!-- Dynamically generated options will go here -->
                        </div>
                    </div>
                </div>

                <input type="hidden" id="selectedRoles" wire:model="selectedRoles">

                <script>
                    let isDropdownInitialized = false; // Flag to track if dropdown is initialized

                    document.addEventListener('livewire:initialized', () => {
                        @this.on('send-message', (data) => {
                            console.log('Message sent!');
                            console.log('Roles:', data.roles); // Log roles to check if they are passed correctly
                            roles = data.roles; // Assign the roles to the roles variable
                            initializeDropdown(roles); // Reinitialize the dropdown with the new roles
                        });
                    });

                    document.addEventListener('DOMContentLoaded', () => {
                        // Initialize dropdown when the page is loaded
                        initializeDropdown(
                        @json($roles)); // Assuming @json($roles) is available in the page

                        function initializeDropdown(roles) {
                            const selectedRolesInput = document.getElementById('selectedRoles');
                            const toggleDropdownButton = document.getElementById('toggleDropdown');
                            const dropdown = document.getElementById('dropdown');
                            const displayText = document.getElementById('displayText');
                            const dropdownContainer = document.querySelector('.relative');

                            let selectedOptions = [];

                            // Function to create dropdown items
                            function createDropdownItems() {
                                dropdown.innerHTML = ''; // Clear previous dropdown items

                                roles.forEach(role => {
                                    const div = document.createElement('div');
                                    div.classList.add('cursor-pointer', 'select-none', 'relative', 'py-2', 'pl-3',
                                        'pr-9',
                                        'hover:bg-primary', 'hover:text-white');
                                    div.setAttribute('data-role-id', role.id);
                                    div.addEventListener('click', function(event) {
                                        event.stopPropagation();
                                        toggleOption(role);
                                    });

                                    const span = document.createElement('span');
                                    span.textContent = role.name;
                                    span.classList.add('block', 'truncate');

                                    const checkIcon = document.createElement('span');
                                    checkIcon.classList.add('absolute', 'inset-y-0', 'right-0', 'flex', 'items-center',
                                        'pr-4',
                                        'text-primary');
                                    checkIcon.style.display = selectedOptions.some(selected => selected.id === role
                                        .id) ? 'block' :
                                        'none';

                                    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                                    svg.setAttribute('class', 'h-5 w-5');
                                    svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
                                    svg.setAttribute('viewBox', '0 0 20 20');
                                    svg.setAttribute('fill', 'currentColor');

                                    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                                    path.setAttribute('fill-rule', 'evenodd');
                                    path.setAttribute('d',
                                        'M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z'
                                    );
                                    path.setAttribute('clip-rule', 'evenodd');

                                    svg.appendChild(path);
                                    checkIcon.appendChild(svg);
                                    div.appendChild(span);
                                    div.appendChild(checkIcon);
                                    dropdown.appendChild(div);
                                });
                            }

                            // Toggle the dropdown visibility
                            toggleDropdownButton.addEventListener('click', function(event) {
                                event.stopPropagation();
                                dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
                            });

                            // Toggle selection of a role
                            function toggleOption(role) {
                                const index = selectedOptions.findIndex(selected => selected.id === role.id);
                                if (index !== -1) {
                                    selectedOptions.splice(index, 1);
                                } else {
                                    selectedOptions.push(role);
                                }
                                updateDisplayText();
                                createDropdownItems();
                                updateSelectedRolesInput();
                            }

                            // Update the displayed text of selected roles
                            function updateDisplayText() {
                                displayText.textContent = selectedOptions.length ? selectedOptions.map(option => option.name)
                                    .join(', ') :
                                    'Select roles';
                            }

                            // Update the hidden input field with selected roles
                            function updateSelectedRolesInput() {
                                const selectedIds = selectedOptions.map(option => option.id).join(',');
                                selectedRolesInput.value = selectedIds;
                                selectedRolesInput.dispatchEvent(new Event('input'));
                            }

                            // Initialize the dropdown items
                            createDropdownItems();

                            // Close the dropdown if clicked outside
                            document.addEventListener('click', function(event) {
                                if (!dropdownContainer.contains(event.target) && dropdown.style.display === 'block') {
                                    dropdown.style.display = 'none';
                                }
                            });
                        }
                    });
                </script>

And this is my backend (partially):

<?php

namespace AppLivewire;

use LivewireComponent;
use GuzzleHttpClient;
use DanHarrinLivewireRateLimitingExceptionsTooManyRequestsException;
use DanHarrinLivewireRateLimitingWithRateLimiting;
use IlluminateSupportFacadesLog;

class ManageMessage extends Component
{

    public $server;
    public $channels;

    public $channel;
    public $message;
    public $roles = [];
    public $selectedRoles;
    public $webhook = null;

    public function mount($server, $roles, $channels)
    {
        $this->server = $server;
        $this->roles = $roles;
        $this->channels = $channels;
    }


    // more code...

    public function send()
    { 
        // actions unrelated to the problem... 

        try {
            $response = $client->post($url, $options);

            if ($response->getStatusCode() === 200 || $response->getStatusCode() === 204) {
                flash()->flash('success', 'Message has been sent.', [], 'Success');
                $this->dispatch('send-message', roles: $this->roles);
            } else {
                flash()->flash('error', 'An error occurred while sending the message.', [], 'Error');
                $this->dispatch('send-message', roles: $this->roles);
            }
        } catch (Exception $e) {
            Log::error('Error sending message: ' . $e->getMessage());
            flash()->flash('error', 'An error occurred while sending the message.', [], 'Error');
            $this->dispatch('send-message', roles: $this->roles);
        }
    }
}

BTW my controller contains the $roles variable, which is passed on to the livewire component:

@livewire('manage-message', ['server' => $server, 'roles' => $roles, 'channels' => $channels ?? []])

Does anyone know a solution to this problem?

Is there a reason my JS countdown doesn’t work on mobile? [closed]

My code seems to work on desktop, but it’s not showing up on mobile. I checked on both an iPhone and Android.

For context, I also need the countdown to cut-off after 5pm ET.

$("#Timeremaining").each(function() {
  var $this = $(this),
    date = new Date(),
    usTime = new Date(date.toLocaleString('en-US', {
      timeZone: 'America/New_York'
    })),
    countDownDate = usTime.setHours(16, 59, 59);
  var x = setInterval(function() {
    var distance = countDownDate - Date.now(),
      hours = ('0' + Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))).slice(-2),
      minutes = ('0' + Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))).slice(-2),

      $($this).html(hours + " hr " + minutes + " min");
    if (distance < 0) {
      clearInterval(x);
      $('.beforefive').addClass('hide');
      $('.afterfive').removeClass('hide');
    }
  }, 1000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<span class="beforefive">
<p id="Timeremaining"></p>
</span>

<span class="afterfive hide">
<p>[other text]</p>
</span>

Javascript: passing in a dynamic array: returning multiple promises in a function

I have a Javascript function that takes in an int argument and returns a promise. I also have an array of ints(variable length) and I would like to call my function multiple times passing in each int to it and return multiple promises in one function. How do I accomplish this? The closest I could find on SO was JS return multiple promises in one function



function myFunction(input)
{
    return Promise.resolve(input);
}

/*
function invokedFunction(input)
{
    return function myFunction() {return Promise.resolve(input);}
}
function waitForAll()
{
    var resultArray = [];
    resultArray = await callMyFunction();
}
*/

function callMyFunction(inputArray)
{
    Promise.all[myFunction(pass in each item from inputArray)..... ];


/*
    const promisesArray = [];
    if(Array.isArray(inputArray)){
        inputArray.forEach(function(item, index){
            promisesArray[index] = invokedFunction(item);                      
        });
    }
    return Promise.all(promisesArray);
*/
}

var inputArray = [1, 2, 3, 4, 5];
callMyFunction(inputArray);

Using counter as an identifier for grandchildren in React

I have multiple forms as grandchildren, and all forms are submitted at once by clicking the Submit button available in the parent.

To achieve this, we need to have a state called forms in the parent, which is an array of objects. Each object corresponds to one form. Additionally, for the onChange of each form, we need to pass the data to the parent.

The issue I encounter is that when changing the data in each form, I want to check if this form already exists and update it, rather than adding a new one to the array. For this, we need an identifier for each form, which should be passed along with the object.

I figured out that I can use a counter in the parent. This counter will increment for each grandchild we have on the screen, and we can store this counter before incrementing it as the identifier. This way, each form will have a unique identifier like: 0, 1, 2, 3, and so on, depending on which one is rendered first.

Part of my code:

Parent Component:

function Parent({
  userDetails,
  availableViewTypes,
  availableDiscountReason,
}) {
  const [views, setViews] = useState([]);
  const [counter, setCounter] = useState(0);

 const getNextCounter = () => {
    const currentCounter = counter;
    setCounter(counter + 1);
    return currentCounter;
  };


  const handleViewChange = (index, updatedView) => {
    console.log(index);
    setViews((prev) => {
      const newViews = [...prev];
      newViews[index] = updatedView; // Update the specific view by index
      return newViews;
    });
  };

  
  const handleSubmit = () => {
    console.log(views)
  };
  return (
    <div className="form">
      <Box>
        {userDetails.data.length > 0 &&
          userDetails.data.map((p, i) => {
            return (
              <Box key={i}>
                <div className="forms">
                  {p.data.map((payment, index) => (
                    <TypeForm
                      onViewChange={handleViewChange}
                      key={index}
                      data={payment}
                      userDetails={userDetails}
                      getNextCounter={getNextCounter}
                      counter={counter}
                    />
                  ))}
                </div>
              </Box>
            );
          })}
      </Box>

      <Box>
        <LoadingButton
          onClick={handleSubmit}
        >
          Submit
        </LoadingButton>
      </Box>
    </div>
  );
}

export default Parent;

Children Component:

function Child({
  data,
  types,
  onViewChange,
  getNextCounter,
}) {
  return (
      <Box sx={{ display: "flex" }}>
        {types?.length > 0 &&
          types.map((v, i) => (
            <GrandChild
              key={`${data.id}-${v.id}-${i}`}
              onViewChange={onViewChange}
              getNextCounter={getNextCounter}
            />
          )
        )}
      </Box>
  );
}

export default Child;

GrandChild:

function GrandChild({ onViewChange, counter, getNextCounter }) {

  const [formIdentifier, setFormIdentifier] = useState(null);
  const [viewData, setViewData] = useState({
    quantity: 0,
    amount: 0,
    identifier: null,
  });

  const updateViewData = (updates) => {
    setViewData((prev) => {
      const updatedData = { ...prev, ...updates };
      onViewChange(formIdentifier, updatedData);
      return updatedData;
    });
  };
  useEffect(() => {
    const newIdentifier = getNextCounter();
    setFormIdentifier(newIdentifier);
    setViewData((prev) => {
      const updatedData = { ...prev, identifier: newIdentifier };
      return updatedData;
    });
  });

reutrn (
// rest of the code
)

If I pass the getNextCounter function in the dependencies, it will cause an infinite loop. If I don’t pass it, the counter will only increment once, so all forms will have the same identifier (which will be 1), and that’s absolutely wrong.

Could you please tell me how to do this the right way?

Chrome extension preventing my deployed website from functioning

I am fairly new to web development. I have deployed only a few static sites, but only today did I encounter the following error message after trying to deploy through Cloudfare, Vercel, and Netlify:

Denying load of chrome-extension://bkdgflcldnnnapblkhphbgpggdiikppg/public/font/ProximaNova-Reg-webfont.woff2. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.

I would like potential employers to be able to access these sites & not be met by a blank page, so I wonder if there’s anything I can do as the developer of these sites to prevent this from happening, or to, at least, make the UX better.

Has anyone else been in this situation? If so, what did you do to fix it? Nothing I have found online in the last 5 hours has been of any help for this particular question.

Embeddable JavaScript SQL console with autocomplete [closed]

My company has a web app that includes a SQL console for MySQL. It is very primitive, and with our database having hundreds of tables, it is missing one of the most helpful features: autocomplete.

Is there an existing embeddable JavaScript SQL console with autocomplete? It wouldn’t have to be for MySQL, as if it’s for any other database, adapting it to MySQL shouldn’t be difficult.

Update Chart Links of a new report copy and new workbook copy (java)

I am using appscript (google for developers) to try and write a script for a monthly report I do. Basically, I take the Google slides that are the same each month and I make a copy, then I make a copy of the corresponding workbook.

function updateChartLinks() {
  // Replace with the ID of the presentation you want to update
  var presentationId = "abcdefg";
  // Replace with the ID of the new spreadsheet you want to link to
  var spreadsheetId = "abcdefg";

  var ss2 = SpreadsheetApp.openById(spreadsheetId);
  var sheet2 = ss2.getSheets()[0];
  var chart2 = sheet2.getCharts()[0];
  Logger.log('spreadsheet2 name is ' + ss2.getName());

  // get all charts from all sheets of the spreadsheet copy 
  var sheets2 = ss2.getSheets();
  var allCharts = []; // keep track of all charts on all sheets of the spreadsheet 
  var allChartsIds = []; // keep track of the ids for all the charts 
  var chartsnum = 0; 
  for (var i = 0; i < sheets2.length; i++) {
    var curSheet2 = sheets2[i];
    if (curSheet2) { // Check if curSheet2 is defined
      var charts2 = curSheet2.getCharts();
      for (var j = 0; j < charts2.length; j++) {
        var curChart2 = charts2[j]; 
        allCharts[chartsnum] = curChart2;
        allChartsIds[chartsnum] = curChart2.getChartId();
        chartsnum++;
        Logger.log('n chart2 Id is ' + curChart2.getChartId());
      }
    }
  }

  //total number of charts in all sheets of the spreadsheet 
  var lengthAllCharts = allCharts.length;
  var pres2 = SlidesApp.openById(presentationId);
  Logger.log('pres2 name is ' + pres2.getName()); 

  var slides2 = pres2.getSlides(); 
  for (var i = 0; i < slides2.length; i++) {
    var slide = slides2[i];
    var shapes = slide.getShapes();

    shapes.forEach(shape => {
      if (shape.getShapeType() == SlidesApp.ShapeType.CHART) {
        var chart = shape.asChart();
        var chartData = chart.getChartData();

        // Assuming the charts are in the same order as in the new spreadsheet
        var newChart = allCharts.shift();

        chartData.setDataSourceId(newChart.getChartId());
        chart.setChartData(chartData);

        // Force a refresh of the chart data
        chart.refresh();
      }
    });
  }
}

The problem is, the copy of the google slides are still linked to the original workbook, not the copy. These presentations are usually super long with 30-50+ charts. Rather than copy and paste each individual chart, I’d like to write a script that takes the copy of the presentation and re-links the embedded charts with the copy of the workbook. I would like to run it manually. This is as far as I got, I have a feeling the bottom of the code is where things are going awry– the code will run, but at the end when I refresh the copy of the presentation, it is still linked to the original workbook (not the copy).

How can I dynamically render a component in Angular with complex dependencies injected into its constructor?

I am trying to dynamically load a component into a ViewContainerRef, and the component’s constructor depends on multiple services (e.g., HttpClient, a custom service, etc.). However, I get an error related to missing providers. Here’s what I have tried so far:

Injecting Injector and using it with createComponent.
Manually providing dependencies in the module where the component is declared.

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { LoggingService } from './logging.service';

@Component({
    selector: 'app-dynamic',
    template: `<p>Dynamic Component Loaded!</p>`,
})
export class DynamicComponent {
    constructor(private http: HttpClient, private loggingService: LoggingService) {
        console.log('DynamicComponent initialized with HttpClient and LoggingService');
    }
}

import {
    Component,
    ComponentRef,
    Injector,
    ViewChild,
    ViewContainerRef,
} from '@angular/core';
import { DynamicComponent } from './dynamic.component';

@Component({
    selector: 'app-root',
    template: `<button (click)="loadComponent()">Load Dynamic Component</button>
               <ng-container #container></ng-container>`,
})
export class AppComponent {
    @ViewChild('container', { read: ViewContainerRef, static: true })
    container!: ViewContainerRef;

    constructor(private injector: Injector) {}

    loadComponent() {
        const componentRef: ComponentRef<DynamicComponent> = this.container.createComponent(DynamicComponent, {
            injector: this.injector, // Provide the injector to resolve dependencies
        });

        const instance = componentRef.instance;
        console.log('Dynamic component instance:', instance);
    }
}


What I Am Looking For:
A solution that allows dynamic rendering of a component with proper dependency injection.
An approach that does not compromise modularity and avoids manual dependency management.
Bonus: How to add custom providers to a dynamically created component.


Copy and paste indexed words maintaining unique index

I am trying to figure how to index every word in a text box and maintain these indexes when the text is copy and pasted (into another text area). The problem I am facing is giving each word a unique index even if the word is duplicated.

Currently javascript is duplicating indexes for duplicate words. These words actually each have a unique timecode saved in a database which I later on want to retrieve but can’t do this if there are duplicate indexes.

The aim is to allow users to copy and paste portions of text and then construct a list on indexes from their selections. How can I make sure each words gets a unique index?
I made a fiddle

Html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Word Index Tracker</title>
    <style>
        #output {
            margin-top: 10px;
            padding: 10px;
            border: 1px solid #ccc;
            background: #f9f9f9;
        }
    </style>
</head>
<body>
    <h1>Word Index Tracker</h1>
    <p>Original Text: <span id="original-text"></span></p>
    <textarea id="text-box" rows="5" cols="50" placeholder="Paste text here to see indexes"></textarea>
    <div id="output">Indexes will appear here...</div>
    </body>
</html>

Javascript

// Original string
        const originalString = "As you can see the script does not give unique indexes to words that are duplicated in the script. The gets the same index throughout the script.";
        document.getElementById('original-text').innerText = originalString;

        // Create a map of words to their indexes
        const wordIndexMap = {};
        originalString.split(/s+/).forEach((word, index) => {
            wordIndexMap[word] = index;
        });

        // Textbox and output elements
        const textBox = document.getElementById('text-box');
        const output = document.getElementById('output');

        // Event listener for tracking changes in the text box
        textBox.addEventListener('input', () => {
            const pastedWords = textBox.value.split(/s+/);
            const indexes = pastedWords
                .filter(word => word in wordIndexMap) // Only track words that are in the original text
                .map(word => wordIndexMap[word]); // Map to their indexes

            // Display the indexes
            output.innerText = `Indexes of words: ${indexes.join(', ')}`;
        });