ClientId Not Updating On Spotify’s Web API Authorization Example

I wanted to get my hands dirty with Spotify’s Web API, and it seems that the first thing I need to get a hang of is Authorization. So, I cloned Spotify’s Web API Examples repository from github and opened it in vscode. I followed the instructions on the README and replaced the client id with the one I received from Spotify after I created an app through Spotify For Developers. I also replaced their Redirect URI with https://127.0.0.1:8080. After this, I ran npm install, and finally npm start. At this point, I saw the first part of the application run correctly, but after I pressed Log In with Spotify, I got redirected to a page that said “Invalid Client ID”. I looked at the url and realized that the client id it was looking for was the default: “yourClientIdGoesHere” rather than the updated client Id I had replaced it with.

I made sure the changes were saved to the file, and I tried restarting the server multiple times, but that did not work.

Here is what my app.js looks like. I made no other changes to files in the directory.

/**
 * This is an example of a basic node.js script that performs
 * the Authorization Code with PKCE oAuth2 flow to authenticate 
 * against the Spotify Accounts.
 *
 * For more information, read
 * https://developer.spotify.com/documentation/web-api/tutorials/code-pkce-flow
 */

const clientId = 'ca93bf90292e4f13b9708468fbf516c0'; // your clientId
const redirectUrl = 'http://127.0.0.1:8080';        // your redirect URL - must be localhost URL and/or HTTPS

const authorizationEndpoint = "https://accounts.spotify.com/authorize";
const tokenEndpoint = "https://accounts.spotify.com/api/token";
const scope = 'user-read-private user-read-email';

// Data structure that manages the current active token, caching it in localStorage
const currentToken = {
  get access_token() { return localStorage.getItem('access_token') || null; },
  get refresh_token() { return localStorage.getItem('refresh_token') || null; },
  get expires_in() { return localStorage.getItem('refresh_in') || null },
  get expires() { return localStorage.getItem('expires') || null },

  save: function (response) {
    const { access_token, refresh_token, expires_in } = response;
    localStorage.setItem('access_token', access_token);
    localStorage.setItem('refresh_token', refresh_token);
    localStorage.setItem('expires_in', expires_in);

    const now = new Date();
    const expiry = new Date(now.getTime() + (expires_in * 1000));
    localStorage.setItem('expires', expiry);
  }
};

// On page load, try to fetch auth code from current browser search URL
const args = new URLSearchParams(window.location.search);
const code = args.get('code');

// If we find a code, we're in a callback, do a token exchange
if (code) {
  const token = await getToken(code);
  currentToken.save(token);

  // Remove code from URL so we can refresh correctly.
  const url = new URL(window.location.href);
  url.searchParams.delete("code");

  const updatedUrl = url.search ? url.href : url.href.replace('?', '');
  window.history.replaceState({}, document.title, updatedUrl);
}

// If we have a token, we're logged in, so fetch user data and render logged in template
if (currentToken.access_token) {
  const userData = await getUserData();
  renderTemplate("main", "logged-in-template", userData);
  renderTemplate("oauth", "oauth-template", currentToken);
}

// Otherwise we're not logged in, so render the login template
if (!currentToken.access_token) {
  renderTemplate("main", "login");
}

async function redirectToSpotifyAuthorize() {
  const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  const randomValues = crypto.getRandomValues(new Uint8Array(64));
  const randomString = randomValues.reduce((acc, x) => acc + possible[x % possible.length], "");

  const code_verifier = randomString;
  const data = new TextEncoder().encode(code_verifier);
  const hashed = await crypto.subtle.digest('SHA-256', data);

  const code_challenge_base64 = btoa(String.fromCharCode(...new Uint8Array(hashed)))
    .replace(/=/g, '')
    .replace(/+/g, '-')
    .replace(///g, '_');

  window.localStorage.setItem('code_verifier', code_verifier);

  const authUrl = new URL(authorizationEndpoint)
  const params = {
    response_type: 'code',
    client_id: 'ca93bf90292e4f13b9708468fbf516c0',
    scope: scope,
    code_challenge_method: 'S256',
    code_challenge: code_challenge_base64,
    redirect_uri: redirectUrl,
  };

Would appreciate any help!

WebWorker giving a vague error. How do i understand what the error actually is?

I’m using a webworker to delegate some tasks related to world generation in a html/css/Javascript project.

I’m currently using replit static HTML to preview and run it.

The error message shows up in the eruda devtools console alongside all other diagnostic and debugging code but it’s the only error so far and the only vague one.

It states:

WorldGenerator: Worker encountered an error:
Event {isTrusted: true}

World generator is the link between the main js file and and this webworker. Regardless of what the error is i just want to be able to know where it stems from exactly in the worker. I’m aware that by default the message itself gets hidden for security reasons and that’s what I’m trying to get around.

I tried try-catch blocks and simple console logs yet it’s all obscured when this error appears so nothing else shows.

How do I make Vite work on a multi-page website?

I have a multi-page website built with vite. When I build and deploy the website, only my index.html file gets the file paths updated for my css and js files. My other .html files end up looking all weird since they are not reading properly the css and js files given that the file paths point out to my src folder instead of the dist/asset folder. I tried to update my vite.config file to add multi entry points but it hasn’t been working. The website works perfeclty fine until I build and deploy. I’m new to web dev so any help would be greatly appreciated 🙂

My file structure:
file structure

CSS and JS files imports:

    <link rel="stylesheet" href="src/styles/styles.css">
<link rel="stylesheet" href="src/styles/styles-threejs.css">

My vite.config.js:

import { defineConfig } from “vite”;
import react from “@vitejs/plugin-react”;

export default defineConfig({
plugins: [react()],
base: “/”,
build: {
outDir: “dist”,
assetsDir: “assets”,
sourcemap: true,
},
rollupOptions: {
input: {
index: “index.html”,
about: “/About.html”,
vt: “/VT.html”,
ksu: ‘/KSU.html’,
jhu: “/JHU.html”,
renderings: “/Renderings.html”,
},
},
});

Thanks in advance!

How to Identify Browser back, page close and redirect to another route in React Js

I need to Identify and display a custom confirmation modal on browser back, page close and redirect to another route in React. Below BeforeUnloadEvent give the behavior but can’t display a custom confirmation modal so that is not fulfill my requirement.

useEffect(() => {
  const handleBeforeUnload = (event: BeforeUnloadEvent) => {
    if (isDirty) {
      // Show default browser confirmation
      event.preventDefault();
      event.returnValue = '';
      // showConfirm();
    }
  };

  if (isDirty) {
    window.addEventListener('beforeunload', handleBeforeUnload);
  } else {
    window.removeEventListener('beforeunload', handleBeforeUnload);
  }

  return () => {
    window.removeEventListener('beforeunload', handleBeforeUnload);
  };
}, [isDirty]);

useBlocker from React-Router-DOM can use to identify and display a custom confirmation modal on browser back and on router change but it can’t identify the page/window close.

const blocker = useBlocker(useCallback(() => isDirty, [isDirty]));

What can I use to identify and display a custom confirmation modal on browser back, page close and redirect to another route?

HTML/Javascript that is filterable and submits on tab keystroke

I have an HTML select element that I can filter using selectize JS (based on this answer: Creating a select box with a search option .) However, I would also like to be able to submit the item selected on hitting tab. I would like the precise search functionality from the linked answer above but also the submit on tab ability. But it currently seems that, using selectize JS, I can have one or the other, but not both. Here is the version where I can search like I want but can’t submit on tab:

$(document).ready(function() {
  $('select').selectize({
    sortField: 'text'
  });
});
  <label>Select Team:</label>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/js/standalone/selectize.min.js" integrity="sha256-+C0A5Ilqmu4QcSPxrlGpaZxJ04VjsRjKu+G82kl5UJk=" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/css/selectize.bootstrap3.min.css" integrity="sha256-ze/OEYGcFbPRmvCnrSeKbRTtjG4vGLHXgOqsyLFTRjg=" crossorigin="anonymous" />
  <select name="team"  id="select-team" placeholder="Pick a team...">
    <option value="Bills">Bills</option> 
    <option value="Jaguars">Jaguars</option>
    <option value="Broncos">Broncos</option>
    <option value="Bears">Bears</option>
    <option value="Bengals">Bengals</option>
  </select>
</form>

(Obviously, this is just a slightly modified version of the linked answer.) However, when I add selectOnTab: true, it lets me select on tab (obviously) but now the ability to see what I’m typing is gone. It just auto-completes to the best match:

$(document).ready(function() {
  $('select').selectize({
    sortField: 'text';
    selectOnTab: true;
  });
});
  <label>Select Team:</label>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/js/standalone/selectize.min.js" integrity="sha256-+C0A5Ilqmu4QcSPxrlGpaZxJ04VjsRjKu+G82kl5UJk=" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/css/selectize.bootstrap3.min.css" integrity="sha256-ze/OEYGcFbPRmvCnrSeKbRTtjG4vGLHXgOqsyLFTRjg=" crossorigin="anonymous" />
  <select name="team"  id="select-team" placeholder="Pick a team...">
    <option value="Bills">Bills</option>
    <option value="Jaguars">Jaguars</option>
    <option value="Broncos">Broncos</option>
    <option value="Bears">Bears</option>
    <option value="Bengals">Bengals</option>
  </select>
</form>

How can I achieve both features at once?

In summary, I desire a <select> that:

  • Can be searched by typing.
  • Does not autocomplete or autoselect the best match (the user has to do the selecting).
  • Does select the top option matching what the user has typed on hitting tab.
  • Ideally, though not necessarily, uses selectize JS.

Thanks!

A dead loop problem in JavaScript about Set

Why the following code caused dead loop?

const s = new Set([1]);

s.forEach(e => {
    s.delete(e)
    s.add(e)
})

I tried to change the order about delete and add operation,the dead loop disapperd.

const s = new Set([1]);

s.forEach(e => {
    s.add(e)
    s.delete(e)
})

How can I apply hover to one bar only in a series created by Highcharts?

Code

Highcharts.chart('container', {
    chart: {
        type: 'column'
    },
    xAxis: {
        categories: ['Jan', 'Feb', 'Mar']
    },
    plotOptions: {
        series: {
            grouping: true
        }
    },
    series: [
        {
            "name": "Anna",
            "data": [
                {
                    "y": 100
                },
                {
                    "y": 100
                },
                {
                    "y": 100
                }
            ],
            "color": "#5B5BD7",
            "borderWidth": 1
        },
        {
            "name": "Billy",
            "data": [
                {
                    "y": 125
                },
                {
                    "y": 125
                },
                {
                    "y": 125
                }
            ],
            "color": "#FD8D62",
            "borderWidth": 1
        }
    ]
});

Expected
Only the leftmost bar in January has the hover effect applied.

Actual
The leftmost bars in each of the months have the hover effect applied.
enter image description here

I have tried a number of variations to configure this correctly, all to no avail.

JSFiddle

TypeError: Can not read property ‘store’ of undefined, react-native 0.79.2

I’m encountering the following issue on Android after upgrading my React Native project to version 0.79.2. This error does not occur on iOS, which makes it harder to trace since the same codebase behaves differently across platforms.

TypeError: Can not read property ‘store’ of undefined, react-native 0.79.2
more details are given in screenshots.

Package.json has,

“react-redux”: “9.2.0”,
“redux-mock-store”: “1.5.4”,
“redux-saga”: “1.3.0”,
“redux-saga-test-plan”: “4.0.6”,
“@reduxjs/toolkit”: “2.8.2”,

Error Screenshots
enter image description here
enter image description here

App.tsx

import React, { useEffect } from 'react';
import { Provider } from 'react-redux';
import AppHelperComponent from './appHelperComponent/index';
import { store } from '@store';
import { StatusBar } from 'react-native';
import { Core, readColor } from '@colors/core';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { initializeSSLCertification } from './appHelperComponent/helper';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 0,
    },
  },
});

function App(): React.JSX.Element {
  
  useEffect(() => {  
    initializeSSLCertification();  
  }, []);         

  return (
    <>
      <StatusBar
        barStyle="dark-content" // setting status bar font color dark for both Dark and light theme
        backgroundColor={readColor(Core.white)}
      />
      <QueryClientProvider client={queryClient}>
        <Provider store={store}>
            <AppHelperComponent />
        </Provider>
      </QueryClientProvider>
    </>
  );
}

export default App;

store/index.ts



/*
 *Store Configurations will be here
 *The file from where all redux related stuff will be fetched
 */

//Redux
import {configureStore} from '@reduxjs/toolkit';

// Local Imports
import {onboardingContentReducer} from '../slices/onboarding/onboarding';

import {watcherSaga} from '../sagas';

import { errorReducer } from '@slices/error';
import createSagaMiddleware from 'redux-saga';

//Setup sagas
// eslint-disable-next-line @typescript-eslint/no-require-imports
//const createSagaMiddleware = require('redux-saga');
const sagaMiddleWare = createSagaMiddleware();

//const sagaMiddleWare = createSagaMiddleware.default();
const middleWares = [sagaMiddleWare];

// Store configurations
const store = configureStore({
  reducer: {
    onboardingContentReducer,
    errorReducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({serializableCheck: false}).concat(middleWares),
});
//starting saga and it will go to sagas
sagaMiddleWare.run(watcherSaga);

export {store};

accordion only working as button inside container class but working as expected outside

I have created a accordion from w3school example. It is working as expected when I keet it separate. But when I place it with other inputs it is working as button only. The content of the accordion are just flashed when I click the accordion button.
My complete code::

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/5/w3.css">
  
  <style>
  .advance-search {
  background: #fff;
  padding: 40px 15px 25px 15px;
  border-radius: 3px;
  margin-bottom: -50px;
  box-shadow: -1px 3px 6px rgba(0, 0, 0, 0.12);
}


@media (min-width: 1200px) {
  .container {
    max-width: 1140px;

  }
}

.row {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
}


.align-content-center {
  -ms-flex-line-pack: center !important;

  align-content: center !important;

}
@media (min-width: 992px) {
  .col-lg-12 {
    -ms-flex: 0 0 100%;

    flex: 0 0 100%;

    max-width: 100%;

  }
}

.form-row {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  margin-right: -5px;
  margin-left: -5px;
}

.form-row > .col, .form-row > [class*="col-"] {
  padding-right: 5px;
  padding-left: 5px;
}

.form-group {
  margin-bottom: 1rem;
}

.form-control {
  border-radius: 2px;
  height: 50px;
  background-color: transparent;
  color: #666;
  box-shadow: none;
  font-size: 15px;
}

.btn {
  font-size: 15px;
  letter-spacing: 1px;
 display: inline-block;
  padding: 15px 30px;
  border-radius: 4px;
}
.w-100 {
  width: 100% !important;
}
.accordion {
  background-color: #eee;
  color: #444;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 0.4s;
}

.active, .accordion:hover {
  background-color: #ccc; 
}

.panel {
  padding: 0 18px;
  display: none;
  background-color: white;
  overflow: hidden;
}
  </style>
</head>
<body>

<div class="container mt-3">
  <h2>Basic Card</h2>
    
    <div class="advance-search">
                    <div class="container">
                        <div class="row justify-content-center">
                            <div class="col-lg-12 col-md-12 align-content-center">
                                <form>
                                    <div class="form-row">
                                        <div class="form-group col-xl-4 col-lg-3 col-md-6">
                                            <input type="text" class="form-control my-2 my-lg-1" id="inputtext4" placeholder="What are you looking for">
                                        </div>
                                        <div class="form-group col-lg-3 col-md-6">
                                            <select class="w-100 form-control mt-lg-1 mt-md-2">
                                                <option>Category</option>
                                                <option value="1">Top rated</option>
                                                <option value="2">Lowest Price</option>
                                                <option value="4">Highest Price</option>
                                            </select>
                                        </div>
                                        <div class="form-group col-lg-3 col-md-6">
                                            <button class="accordion ">Section 1</button>
                                            <div class="panel">
                                              <p>Lorem ipsum</p>
                                            </div>
                                        </div>
                                        <div class="form-group col-lg-3 col-md-6">
                                            <input type="text" class="form-control my-2 my-lg-1" id="inputLocation4" placeholder="Location">
                                        </div>
                                        <div class="form-group col-xl-2 col-lg-3 col-md-6 align-self-center">
                                            <button type="submit" class="btn btn-primary active w-100">Search Now</button>
                                        </div>
                                    </div>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
    
</div>
<br><br><br>
<div class="container mt-3">
<br>
<div class="form-group col-lg-3 col-md-6">
                                            <button class="accordion form-control">Section 1</button>
                                            <div class="panel">
                                              <p>Lorem ipsum </p>
                                            </div>
                                        </div>
</div>


    <script type="text/javascript">
var acc = document.getElementsByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
  acc[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var panel = this.nextElementSibling;
    if (panel.style.display === "block") {
      panel.style.display = "none";
    } else {
      panel.style.display = "block";
    }
  });
}
    </script>
</body>
</html>

Please help with this issue. Thank You!!!

DateTimePicker and React Native Picker not working on TestFlight build but ok on simulator

"@react-native-community/datetimepicker": "8.4.1",
"@react-native-picker/picker": "2.11.1",
"expo": "53.0.18",

When running the build and testing with Testflight, both my types of pickers (@react-native-community/datetimepicker and @react-native-picker/picker) show up as the attached image. They are, however, interactive (somehow) although I’m not sure what their hotarea is.

Anyone has any idea on how to solve this? I’ve went ahead and removed their styling, thinking that that was the issue, but that didn’t solve the problem.

I’m using the components as they are from the dependencies, like so

 <Picker
  selectedValue={value}
  onValueChange={onValueChange}
  style={[styles.picker, { fontSize: 16, fontFamily: 'System' }]}
>
  {items.map((item) => (
    <Picker.Item
      key={item.value}
      label={item.label}
      value={item.value}
     />
    ))}
</Picker>

and the date time picker

<DateTimePicker
  value={dateOfBirth || new Date()}
  mode="date"
  display="spinner"
  onChange={onDateChange}
  maximumDate={new Date()}
  style={{ height: 200, width: '100%' }}
/>

common amongst all pickers on how they look like on the testflight build

Please how can I fix this error “TypeError: Cannot set properties of undefined (setting ‘userId’)”?

I want to display the various food orders in the customers food basket.

This is my “server.js” file.

import express from "express";
import cors from "cors";
import { connectDB } from "./config/db.js";
import foodRouter from "./routes/foodRoute.js";
import userRouter from "./routes/userRoute.js";
import foodbasketRouter from "./routes/foodbasketRoute.js";
import "dotenv/config";

// app config
const app = express();
const port = process.env.PORT || 4000;

// middleware
app.use(express.json());
app.use(cors());

// db connection
connectDB();

// api endpoints
app.use("/api/food", foodRouter);
app.use("/images", express.static("uploads/foods") ); // image path
app.use("/api/user", userRouter);
app.use("/api/foodbasket", foodbasketRouter);

app.get( "/", ( request, response ) => {
    response.send("All Good!");
} );

app.listen( port, () => {
    console.log(`Server Started on http://localhost:${port}`);
} );

This is my “foodbasketRoute.js” file.

import express from "express";
import { addTofoodbasket, removeFromfoodbasket, showFoodbasket } from "../controllers/foodbasketController.js";
import authMiddleware from "../middleware/auth.js";

const foodbasketRouter = express.Router();

foodbasketRouter.post("/addtofoodbasket", authMiddleware, addTofoodbasket);
foodbasketRouter.post("/removefromfoodbasket", authMiddleware, removeFromfoodbasket);
foodbasketRouter.post("/showfoodbasket", authMiddleware, showFoodbasket);

export default foodbasketRouter;

This is my “foodbasketController.js” file.

import User from "../models/User.js";

//! show customer foodbasket
const showFoodbasket = async (request, response) => {
    try {
        let userData = await User.findById(request.body.userId);

        let foodbasket = await userData.foodbasket;

        response.json({success: true, foodbasket});
    } catch (error) {
        console.log(error);
        response.json({success: false, message: "Error Occured!"});
    }
};

export { addTofoodbasket, removeFromfoodbasket, showFoodbasket};

This is my “auth.js” file.

import jwt from "jsonwebtoken";

const authMiddleware = async (request, response, next) => {
    const {token} = request.headers;

    if (!token) {
        return response.json( {success: false, message: "Not Authorized! Please Login"} );
    }

    try {
        const tokenDecode = jwt.verify(token, process.env.JWT_SECRET);
        request.body.userId = tokenDecode.id;
        next();
    } catch (error) {
        console.log(error);
        response.json( {success: false, message: "Error! Authentication Failed!"} );
    }
};

export default authMiddleware;

This is the url: “http://localhost:4000/api/foodbasket/showfoodbasket”.

I can successfully addTofoodbasket and successfully removeFromfoodbasket but when I want to showFoodbasket, it throws this error “TypeError: Cannot set properties of undefined (setting ‘userId’) at authMiddleware”.

How to scroll the last message from user to the top of chat container

Automatically scroll a fixed-height chat viewport so that each new user message is positioned flush at the top—pushing earlier messages upward and out of view (only visible by scrolling)—just like ChatGPT.
Messages remain in chronological order (top-to-bottom) in the DOM, but when an assistant reply is added and causes overflow, the container should scroll to the bottom to reveal that latest content.
How can I implement this behavior using JavaScript and CSS

<!DOCTYPE html>
<html>
<head>
  <style>
    .chat-container { display: flex; flex-direction: column; height: 100vh; }
    .chat-header  { padding: 1rem; background: #444; color: white; }
    .chat-messages {
      flex: 1 1 auto;
      min-height: 0;               
      overflow-y: auto;
      border: 1px solid #ccc;
      padding: 1rem;
      display: flex;
      flex-direction: column;      
      gap: 0.5rem;
    }
    .message { max-width: 70%; padding: 0.5rem; border-radius: 1rem; }
    .user    { background: #007aff; color: white; align-self: flex-end; }
    .bot     { background: #ddd;     color: #333;  align-self: flex-start; }
    .composer { padding: 0.5rem; border-top: 1px solid #ccc; }
    .input    { width: 80%; padding: 0.5rem; }
    .send-btn { padding: 0.5rem 1rem; }
  </style>
</head>
<body>
  <div class="chat-container">
    <div class="chat-header">Chat Demo</div>
    <div class="chat-messages" id="msgs">
      <div class="message bot">Welcome!</div>
    </div>
    <div class="composer">
      <div id="input" class="input" contenteditable="true"></div>
      <button id="send" class="send-btn">Send</button>
    </div>
  </div>

  <script>
    const msgs    = document.getElementById('msgs');
    const inputEl = document.getElementById('input');
    const sendBtn = document.getElementById('send');

    function addMessage(text, cls) {
      const m = document.createElement('div');
      m.className = `message ${cls}`;
      m.textContent = text;

      // I append chronologically:
      msgs.appendChild(m);

      // then try to scroll the new message into view at the top:
      m.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }

    sendBtn.addEventListener('click', () => {
      const txt = inputEl.textContent.trim();
      if (!txt) return;
      addMessage(txt, 'user');
      inputEl.textContent = '';
      setTimeout(() => addMessage('Echo: ' + txt, 'bot'), 200);
    });
  </script>
</body>
</html>

How to intercept a form submit in websocket connection?

I have “inherited” a piece of code from a chat application. I would like to add some custom checks on the user input upon submission, allowing the submit to be aborted on client side if necessary.
I have created a submit handler javascript function in order to execute the checks and transformations, including preventDefault as first instruction:

async handleSubmit(event) {

    event.preventDefault(); // Prevent default form submission
...

I have linked the handler to the form:

<form
    class="pg-chat-input-bar"
    ws-send
    @submit="handleSubmit($event)"
    enctype="multipart/form-data"
>

Yet, no matter what, the form is submitted immediately when the submit button is pressed. The server receives the form in parallel to / before the handler being executed. I can assess that the handler is triggered and does what it is supposed to do but unfortunately the form has already been submitted.
I tried @submit.prevent, @submit.stop
and even combined both but it doesn’t change the outcome. I found many posts asking to capture/intercept/interrupt a form submit but the solutions are as simple as what I tried. What am I doing wrong?

As I am not starting from scratch I would prefer modify the code as little as possible and use what is already there.
Could it be related to the way the WebSocket functions? I am not too familiar with it.

Im trying to write parser, that will be parse steam inventories for users from input file

Parser must can process a big count of users (about 1500) in a short time (about 2-3 minutes) with 429 or 403 errors not more than 10-15% of all users. I dont know ho to write parsers and i actually tried write it on python, but its too slow. There is some stupid ideas like, but i dont know how to do it without blocking by steam:/

import axios from 'axios';
import fs from 'fs/promises';
import { SocksProxyAgent } from 'socks-proxy-agent';

async function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
  // reading configs
  const config = JSON.parse(await fs.readFile('config/inventories.json', 'utf-8'));
  const players = JSON.parse(await fs.readFile('output/players_output.json', 'utf-8'));

  const appid = config.game;
  const contextid = config.contextid;
  const proxies = config.PROXIES; // SOCKS5

  // Reqest parameters
  const country = config.country || 'US';
  const language = config.language || 'english';
  const currency = config.currency || '1'; // USD
  const two_factor = config.two_factor || '0';

  const bannedProxies = new Set();

  for (let i = 0; i < players.length; i++) {
    const player = players[i];
    const steamid = player.steamid64;
    const name = player.name;

    //forming url
    const baseUrl = `https://steamcommunity.com/inventory/${steamid}/${appid}/${contextid}`;
    const url = `${baseUrl}?country=${country}&language=${language}&currency=${currency}&two_factor=${two_factor}`;

    const proxy = proxies[i % proxies.length];

    if (bannedProxies.has(proxy)) {
      console.log(`Proxy banned, skip: ${proxy}`);
      continue;
    }

    // New socks agent
    const agent = new SocksProxyAgent(proxy);

    // Browser-like headers
    const headers = {
      'Accept': 'application/json, text/javascript, */*; q=0.01',
      'Accept-Language': 'en-US,en;q=0.9',
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
      'Referer': baseUrl,
      'Origin': 'https://steamcommunity.com',
      'Host': 'steamcommunity.com',
      'X-Requested-With': 'XMLHttpRequest',
      'Connection': 'keep-alive',
      'Cache-Control': 'no-cache',
    };

    try {
      console.log(`Steam Inventory reqesest for ${name} with proxy: ${proxy}`);

      const response = await axios.get(url, {
        httpsAgent: agent,
        headers,
        timeout: 10000,
      });

      console.log(`Status: ${response.status}`);

      if (response.status === 429 || response.status === 403) {
        console.log(`Proxy has been banned: ${proxy}`);
        bannedProxies.add(proxy);
        continue;
      }

      // Working with response data

    } catch (err) {
      console.log(`Proxy error ${proxy}: ${err.message}`);
      bannedProxies.add(proxy);
      continue;
    }

    // Pause
    await sleep(500);
  }
}

main().catch(console.error);

And my JSON configs like after nuclear war (There is a huge count of trash)

{
  "steam_api_key": "KEY",
  "database": {
    "filename": "data/data.db"
  },
  "PLAYERS": "output/players_output.json",
  "URL": "https://steamcommunity/inventory",
  "DELAY": 0.5,
  "TIMEOUT": 1.5,
  "game": 730,
  "contextid": 2,
  "mode": "scrape",
  "searchFor": null,
  "outputFile": "./output/inventories.json",

  "USE_PROXY": true,
  "PROXY_CHANGERATE": 2,
  "PROXIES": [
      there is 10 proxies
    ]
}

Output must be like this in future (its not full code, because im stuck on steam blocking)

[
  {
    "name": "",
    "steamid64": "",
    "address": ""
  }, ...
]

And input looks like

[
  {
    "nickname": "",
    "steamid": "",
    "server": "its frome another script, nothing to do there, only for next",
    "inventory": [
      {
        "id": "45072097998",
        "market_hash_name": "Dreams & Nightmares Case",
        "type": "Container, base class"
      }, ...
    ]
  }, ...
]

How to dynamically create a Likert-scale matrix based on user-defined input rows in LimeSurvey

I’m building a questionnaire in LimeSurvey (v6.x) and need to implement a two-part question with the following logic:

Goal:

  • In Question 1, the respondent should be able to enter the name of as many organizations as they work with, one per row.

    • Ideally, the respondent can add as many rows as needed, dynamically.
    • Each row contains just a text field for the name of the organization.
  • In Question 2, I want to display a matrix where:

    • Each row corresponds to one organization entered in the previous question
    • There are three columns, each representing a Likert-type scale from 1 to 7, to assess different aspects (e.g. importance, influence, current collaboration).

What I tried:

  • I used a “Multiple short text” question type in Question 1, with predefined subquestions and JavaScript to reveal more fields with a button (e.g. up to 10 rows).
  • In Question 2, I created an “Array (Numbers)” question and used {question1_SQ001} to {question1_SQ010} as subquestion texts.
  • I used JavaScript in Question 2 to hide rows where the corresponding input was empty.

Limitations:

  • This approach works only for a fixed number of possible rows (e.g. 10).
  • It doesn’t truly allow for dynamic row creation — I have to guess the maximum number of rows in advance.

What I want to know:

  • Is there a way in LimeSurvey to:
    • Allow the user to freely enter N rows (organizations),
    • And then automatically populate a matrix question with exactly those N inputs as subquestions?
    • Ideally without needing to predefine or cap the number of entries?

If not possible natively, are there known workarounds or plugins (e.g. using JavaScript or custom question themes) that allow this functionality?

Thanks in advance!