Expanding Reviews in Vue.js Causes Page to Scroll to the Top

I’m experiencing an issue with a Vue.js component that displays customer reviews. The functionality to expand and collapse individual reviews mostly works, but there’s a problem when revisiting a previously expanded review.

When I perform the following actions:

  1. Expand Review 1 (click “Read Full Review”).
  2. Collapse Review 1.
  3. Expand Review 2.
  4. Go back and expand Review 1 again.

Instead of expanding Review 1 as expected, the page scrolls to the top.

let currentlyExpandedReview: HTMLElement | null = null;

reviewMessages.forEach((message) => {
  const truncated = truncateText(message.textContent || "", 100);

  if (message.textContent && message.textContent.length > 100) {
    message.dataset.fullReview = message.textContent;
    message.textContent = truncated;

    const readMoreLink = document.createElement("a");
    readMoreLink.href = "#";
    readMoreLink.textContent = "more";
    readMoreLink.classList.add("read-more-link");

    const readLessLink = document.createElement("a");
    readLessLink.href = "#";
    readLessLink.textContent = "...less";
    readLessLink.classList.add("read-less-link");

    readMoreLink.addEventListener("click", (event) => {
      event.preventDefault();

      if (currentlyExpandedReview && currentlyExpandedReview !== message) {
        currentlyExpandedReview.classList.remove("expanded");
        const truncatedText = truncateText(
          currentlyExpandedReview.dataset.fullReview || "",
          100
        );
        currentlyExpandedReview.textContent = truncatedText;
        currentlyExpandedReview.appendChild(readMoreLink.cloneNode(true));
      }

      if (message.classList.contains("expanded")) {
        message.classList.remove("expanded");
        message.textContent = truncated;
        message.appendChild(readMoreLink);
        currentlyExpandedReview = null;
      } else {
        message.classList.add("expanded");
        message.textContent =
          message.dataset.fullReview || message.textContent;
        message.appendChild(readLessLink);
        currentlyExpandedReview = message;
      }
    });

    readLessLink.addEventListener("click", (event) => {
      event.preventDefault();
      message.classList.remove("expanded");
      message.textContent = truncated;
      message.appendChild(readMoreLink);
      currentlyExpandedReview = null;
    });

    message.appendChild(readMoreLink);
  }
});

Observations

  • The issue occurs only when re-expanding a previously expanded review.
  • The page scrolls to the top instead of toggling the review.

Steps to Reproduce

  1. Expand and collapse a review.
  2. Expand another review.
  3. Go back and expand the first review again.

Expected Behavior

The first review should expand properly without scrolling the page to the top.

Actual Behavior

The page scrolls to the top instead of expanding the review.

Potential Cause

The issue might be related to the href="#" on the links, causing the browser to scroll to the top by default.

What I Tried

  • Changing href="#" to href="" but that refreshes the entire page.

How can I fix this issue to ensure smooth expansion and collapsing of reviews without the page scrolling to the top? Are there best practices for managing such toggle states in Vue.js with dynamically added event listeners?

Audio fadeout using exponentialRampToValueAtTime in Chrome or Firefox is not reliable

The following code respects the MDN documentation but results in an abrupt mute instead of a 2-second-long fadeout:

const audioContext = new window.AudioContext();
let oscillator;
let gainNode;
document.getElementById("playSweep").addEventListener("click", () => {
    oscillator = audioContext.createOscillator();
    oscillator.type = "sine"; // Sine wave
    oscillator.frequency = 200;
    gainNode = audioContext.createGain();
    gainNode.gain.setValueAtTime(1, audioContext.currentTime);
    oscillator.connect(gainNode);
    gainNode.connect(audioContext.destination);
    oscillator.start();
});
document.getElementById("fadeOut").addEventListener("click", () => {
    gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 2);
});
document.getElementById("fadeOut2").addEventListener("click", () => {
    gainNode.gain.linearRampToValueAtTime(0.001, audioContext.currentTime + 2);
});
<button id="playSweep">Play Frequency Sweep</button>
<button id="fadeOut">Exp Fade Out</button>
<button id="fadeOut2">Lin Fade Out</button>

Even with the linear version, we can hear a click, it’s not a clean fadeout.

How to do a proper fadeout in JS Web Audio API?

Is it posible using bootstrap-typeahead to append the dropdown to the body, and keep the location?

I have a problem with my typeahead, and the parent container. my parent container has overflow: auto(I needed it for th x axis).
But when I try to use it, it is clipped by overflow like in the image:
image-1

Is there any way to do it like it is for select2? to move the dropdown to body and set the location the same? (image bellow)
image-2

Thank you!

I tried to move it to body and set the top and left properties, but it is not working well.

Why does my convert button do nothing on click?

I’ve been trying to create a unit converter. One of the units is temperature. When I tried to convert from one temperature unit to another, however, the convert button did nothing.

Here is my code:

document.getElementById("confirm").addEventListener("click", function () {
    const inputTemp = parseFloat(document.getElementById("inputTemp").value);
    const inputUnit = document.getElementById("inputUnit").value;
    const outputUnit = document.getElementById("inputUnit").value;

    const conversions = {
        Celsius: {
            Fahrenheit: (temp) => temp * 9 / 5 + 32,
            Kelvin: (temp) => temp + 273.15,
            Celsius: (temp) => temp,
        },
        Fahrenheit: {
            Celsius: (temp) => (temp - 32) * 5 / 9,
            Kelvin: (temp) => (temp - 32) * 5 / 9 + 273.15,
            Fahrenheit: (temp) => temp,
        },
        Kelvin: {
            Celsius: (temp) => temp - 273.15,
            Fahrenheit: (temp) => (temp - 273.15) * 9 / 5 + 32,
            Kelvin: (temp) => temp,
        },

    }

    const result = conversions[inputUnit][outputUnit](inputTemp);
    document.getElementById("outputTemp").textContent = String(result || 0);

});
body {
    font-family: Montserrat, sans-serif;
    display: flex;
    justify-content: center;
    place-items: center;
    height: 100vh;
    background-color: #F4F4F9;

}

.container {
    background-color: #ffffff;
    padding: 20px 30px;
    border-radius: 10px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    text-align: center;

}

h1 {
    margin-bottom: 20px;
    font-size: 24px;

}

.inputs, .outputs {
    margin-bottom: 15px;

}

input, select, output, button {
    padding: 10px;
    margin: 5px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 14px;
    transition: 0.5s ease-in-out;

}

button {
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;

}

button:hover {
    background-color: #0056b3

}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Temperature | Unit Converter</title>
    <script src="../js/temp.js" defer></script>
    <link rel="stylesheet" href="../css/converters.css">
</head>
<body>
<div class="container">
    <div class="inputs">
        <input type="number" id="inputTemp" placeholder="Enter Length">
        <select id="inputUnit">
            <option value="celsius">Celsius</option>
            <option value="fahrenheit">Fahrenheit</option>
            <option value="kelvin">Kelvin</option>
        </select>
    </div>
    <div class="outputs">
        <select id="outputUnit">
            <option value="celsius">Celsius</option>
            <option value="fahrenheit">Fahrenheit</option>
            <option value="kelvin">Kelvin</option>
        </select>
        <output id="outputTemp">0</output>
    </div>
    <button id="confirm">Convert</button>
</div>
</body>
</html>

I thought it may be something to do with the DOM not loading in before the elements loaded in so I tried adding to the start of the JS code:
document.addEventListener("DOMContentLoaded", function () {
But that also didn’t work.

Pondjs fixedWindowRollup example needed

Could someone show me how to use the pondjs timeSeries.fixedWindowRollup because I can’t figure out what I’m doing wrong.

I’d like to resample a dataset to have uniform timestamps, so here is the code I’m using based on doc and what I see in the source:

const data = res.map((data: any) => {
    return {
      timestamp: new Date(data.End).getTime(),
      value: data.Value,
    }
  })

  const ts = timeSeries({
    points: data.map((entry: any) => [entry.timestamp, entry.value]),
    columns: ["time", "value"],
    name: "data",
  })
  .fixedWindowRollup({
    window: window(duration("1day")),
    //aggregation: { value: { value: avg() } }, //ts compiler complains
    aggregation: {value: ["value", avg()]},
  })
  .eventList().map(e => {
    return {
      timestamp: e?.timestamp().getTime(), 
      value: e?.get("value")
    }
  });

but the fixedWindowRollup returns that error:

TypeError: Cannot read properties of undefined (reading 'mid')
     at Index.timestamp (project/node_modules/pondjs/src/index.ts:89:32)
     at Event.timestamp (project/node_modules/pondjs/src/event.ts:578:30)
     at project/node_modules/pondjs/src/collection.ts:839:23
     at List.__iterate (project/node_modules/immutable/dist/immutable.js:3370:13)
     at List.forEach (project/node_modules/immutable/dist/immutable.js:4899:19)
     at SortedCollection.forEach (project/node_modules/pondjs/src/collection.ts:425:29)
     at SortedCollection.isChronological (project/node_modules/pondjs/src/collection.ts:837:14)
     at new SortedCollection (project/node_modules/pondjs/src/sortedcollection.ts:43:20)
     at project/node_modules/pondjs/src/windowedcollection.ts:177:51
     at project/node_modules/immutable/dist/immutable.js:2488:31
     at project/node_modules/immutable/dist/immutable.js:2506:18
btw I'm using syntax from version 1.0.0-alpha.0 because latest version didn't work with my ts compiler ...

I also posted the question fixedWindowRollup example needed as an issue directly to the repo but no luck so far unfortunately…
Thanks for any hint!

React Remix UseActionData() Not Triggered by incoming Webhook POST request

I have the action setup in a Remix React project as below to handle both Form Data & a JSON POST request from a webhook.

Both are working as expected and output the data to the console when received. However only the Form request ends up within UseActionData() the JSON post data does not show within this hook.

Does UseActionData() only work with Form data and if so how could I trigger a function when the webhook is successful? Any help is much appreciated!

export async function action({ context, request }) {
  const type = request.headers.get("content-type") 
  console.log(type)

  if (type === "application/json") {
    // Got Data
    console.log("Webhook")
    let data = await request.json()
      
    return ({data})
  } else { 
    const formData = await request.formData();
    const SendParts = formData.get("Query") 
    if (SendParts !== null) {
      const id = await context.new.query(SendParts, {
        cache: CacheShort(),
      });
      return ({ id });
    }
  }
  return  null;
}
// Handle Result of each Action
const actionData =  useActionData();
useEffect(() => {
  if (actionData != null) {
    console.log("ACTION")
    console.log(actionData)
  }
}, [actionData]);

Array pop only works when not assigning to variable?

let channels_history = [0, 0, 1, 0];
let channel = 0;

// wrapped in some button click event handler >>>>>

channel = channels_history.pop();
console.log(channels_history);

\<<<<<

which outputs

[0, 0, 1, 0]

However, if I do

console.log(channels_history.pop());

it works, and I get the desired values.

React pdf viewer not showing the file in its original size and text is very small to read

I am trying to use react-pdf in my app and I have downloaded a code from github for integrating react-pdf in my project. This is working fine and showing the pdf but the size of the pdf is not the original size and it is showing the pdf with 50% decreased size. How can I fix the size problem

const PDFViewer3 = ({
  pdfUrl,
  fieldsToHighlights = [] // Default to empty array
}) => {
  const [numPages, setNumPages] = useState(null)
  const [scales, setScales] = useState([]) // Store scaling factors for each page
  const [pageHeights, setPageHeights] = useState([]) // Store viewport heights for each page

  // Ensure PDF.js worker is set
  pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`

  const onDocumentLoadSuccess = pdf => {
    setNumPages(pdf.numPages)
  }

  const handleRenderSuccess = (page, pageNumber, scale) => {
    const viewport = page.getViewport({ scale: 1 })

    setScales(prevScales => {
      const newScales = [...prevScales]
      newScales[pageNumber - 1] = scale // Save the scale for the page
      return newScales
    })

    setPageHeights(prevHeights => {
      const newHeights = [...prevHeights]
      newHeights[pageNumber - 1] = viewport.height // Save the viewport height for the page
      return newHeights
    })
  }

  const renderHighlights = (pageNumber, scale) => {
    const fieldsOnPage = fieldsToHighlights.filter(
      field => field.page === pageNumber
    )

    if (!fieldsOnPage.length) return null

    return fieldsOnPage.map((field, index) => (
      <div
        key={index}
        style={{
          position: "absolute",
          backgroundColor: "yellow",
          opacity: 0.4,
          left: `${field.x * scale}px`,
          // Adjust the y-coordinate by using the dynamically calculated page height
          top: `${(pageHeights[pageNumber - 1] - field.y - field.height) *
            scale}px`,
          width: `${field.width * scale}px`,
          height: `${field.height * scale}px`
        }}
      />
    ))
  }

  return (
    <div
      style={{ position: "relative", width: "98vw", height: "100vh", justifyItems:'center' }}
      className="pdf-view flex"
    >
      <Document
        file={pdfUrl}
        onLoadSuccess={onDocumentLoadSuccess}
        onContextMenu={e => e.preventDefault()}
      >
        {Array.from(new Array(numPages), (el, index) => (
          <div key={`page_${index + 1}`} style={{ position: "relative" }}>
            <Page 
              pageNumber={index + 1}
              onRenderSuccess={page => { 
                const viewport = page.getViewport({ scale: 1 })
                handleRenderSuccess(page, index + 1, viewport.scale)
              }} 
            />
            {scales[index] &&
              pageHeights[index] &&
              renderHighlights(index + 1, scales[index])}
          </div>
        ))}
      </Document>
    </div>
  )
}

export default PDFViewer3

How to execute the Node.js test runner via JavaScript API with multiple reporters?

The Node.js test runner supports using multiple reporters by specifying the command-line options --test-reporter and --test-reporter-destination multiple times.

For example, when executing the following command, the test runner will print the test results to standard output in spec format and write a JUnit-style XML report into the file junit.xml:

node --test --test-reporter spec --test-reporter-destination stdout --test-reporter junit --test-reporter-destination ./report.xml

The Node.js test runner can also be executed via JavaScript API, by using the function run:

import { join } from "node:path";
import { run } from "node:test";
import { spec } from "node:test/reporters";

run({ files: [join(import.meta.dirname, "test", "my.test.js")] })
  .compose(spec)
  .pipe(process.stdout);

Now, I have a scenario where I’m executing the run function from another script, and I want to execute it with two reporters, similar to the command-line example above. How can this be achieved?

Error implementing Google authentication in React Native app with Expo

Overview

I am developing an app in React Native using Expo, and I am trying to implement authentication with Google. However, when I try to log in, I get an error and cannot complete the authentication flow, Despite having configured google cloud with the Oauth2 and the consent screen and having made a build and run in an emulator the app with the command “npx expo run:android”

Things that i made:

  1. I set up the google play console, created the OAuth consent screen with the publication type in Test, some test users, and created OAuth 2.0 credentials.
  2. In the OAuth2.0 I added the package name that corresponds with my expo.android.package and the SHA-1 certificate Fingerprint, pulled it using eas credentials command
    ,then in the Custom URI scheme, I enabled the checkbox, otherwise it wouldn’t work directly for me.
  3. I implemented the google auth functionality with the library expo-auth-session with the provider providers/google
  4. I have created a build using the command npx expo run:android to run the app on an emulator, as I’ve seen in several videos

A small aside
Before I had the authentication working, but now it doesn’t work anymore, so I have generated new credentials with the “eas credentials” and added the new sha1key in the new OAuth2 credential, actually using (1), as Default.

enter image description here

Result:

Even though the browser opens, allows me to select a user, and provides the requested data,
Once it closes, I don’t receive the user’s information for some reason.

enter image description here
enter image description here

And the console.log “response” is always null…

My code of the log-in Page:

import React, {useContext, useEffect, useState} from 'react';
import {Form, H4, Spinner, Input, View, Text, H6} from 'tamagui'
import {Button} from "tamagui.config"
import {Pressable, SafeAreaView, Platform, Image, StyleSheet} from "react-native";
import {loadUser, login, register} from "~/services/AuthService";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import {getUserInfo} from "~/services/GoogleAuthService";
import {useAuth} from "~/contexts/NewAuthContext";
import {useRouter} from "expo-router";

WebBrowser.maybeCompleteAuthSession();

// @ts-ignore
const Login = () => {
  const { signIn } = useAuth();
  const router = useRouter()
  const [isLoadingLogin, setIsLoadingLogin] = useState(false)
  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [errors, setErrors] = useState({})
  // const {setUser} = useContext(AuthContext);

  const [request, response, promptAsync] = Google.useAuthRequest({
    androidClientId: "....CLIENT_ID.....",
  })

  useEffect(() => {
    handleSingInWithGoogle()
  }, [response])

  async function handleSingInWithGoogle(){
    // Here the response is always "null"....
    console.log("response", response)
    if(response?.type === "success"){
      // It never happens because it is always null...
      console.log("response success", response)
      const googleAccessToken = response.authentication.accessToken

      const googleUserData = await getUserInfo(googleAccessToken)

      try {
        await register({
          "email": googleUserData.email,
          "name": googleUserData.given_name,
          "surname": googleUserData.family_name,
          "picture": googleUserData.picture,
          "google_id": googleUserData.id,
          "register_type": "google_auth",
          "device_name": `${Platform.OS} - ${Platform.Version}`
        })
        const user = await loadUser();
        signIn(user)
      } catch (e) {
        console.error("error login-in with google")
      }
    }
  }

  function validateForm() {
    const newErrors = {};

    if (!email.trim()) {
      newErrors.email = "empty";
    }

    if (!password.trim()) {
      newErrors.password = "empty";
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  }

  async function submitLoginForm(){
    try {
      setIsLoadingLogin(true)

      // Solo continúa si la validación es exitosa
      if (!validateForm()) {
        return; // Detiene la ejecución si hay errores
      }

      await login({
        email,
        password,
        device_name: `${Platform.OS} - ${Platform.Version}`
      });

      const user = await loadUser();
      console.info("login function user : ", user)
      signIn(user)

    } catch(e){
      if (e.response.status === 422){
        setErrors({password: "credentials not found"});
      }
    } finally {
      setIsLoadingLogin(false)
    }
  }

  function redirectRegister() {
    setErrors({})
    router.push("/(auth)/register")
  }

  return (
    <SafeAreaView style={{flex: 1, backgroundColor: "#e3e3e3"}}>
        <Form
          display="flex"
          justifyContent="center"
          alignItems="center"
          gap="$2"
          height={550}
          onSubmit={() => submitLoginForm()}
          backgroundColor="#e3e3e3"
          padding="$10"
        >
          <H4>Log-in</H4>

          <View minWidth={350} marginVertical={12} flex={1} gap={10}>
            <View marginBottom={10}>
              <Input
                placeholder="Email"
                value={email}
                onChangeText={(text) => {
                  setEmail(text);
                  // Limpia el error cuando el usuario empieza a escribir
                  if (errors.email) {
                    setErrors(prev => ({ ...prev, email: null }));
                  }
                }}
                keyboardType="email-address"
                autoCapitalize="none"
              />
              {errors.email && <Text style={styles.errorText}>El email no puede estar vacio</Text>}
            </View>
            <View>
              <Input
                placeholder="Contraseña"
                value={password}
                onChangeText={setPassword}
                secureTextEntry={true}
                autoCapitalize="none"
              />
              {errors.password && errors.password !== 'credentials not found' && <Text style={styles.errorText}>La contraseña no puede estar vacía</Text>}
              {errors.password && errors.password === 'credentials not found' && <Text style={styles.errorText}>No existe ningun registro con ese email y contraseña</Text>}
            </View>

            <View>

              <Pressable
                onPress={() => promptAsync()}
                style={({ pressed }) => ({
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'center',
                  padding: 10,
                  borderRadius: 30,
                  backgroundColor: pressed ? '#f0f0f0' : '#ffffff',
                  borderWidth: 1,
                  borderColor: '#dcdcdc',
                })}
              >
                <Text paddingRight={9} fontWeight={600} fontSize={15.5}>
                  Entrar con Google
                </Text>
                <Image
                  source={require('~/assets/images/google-logo.png')}
                  style={{
                    width: 22,
                    height: 22,
                  }}
                />
              </Pressable>
            </View>

            <Form.Trigger asChild disabled={isLoadingLogin}>
              <Button theme="blue" icon={isLoadingLogin ? () => <Spinner /> : undefined}>
                {isLoadingLogin ? 'Iniciando sesión...' : 'Iniciar sesión'}
              </Button>
            </Form.Trigger>
          </View>

        </Form>
    </SafeAreaView>
  )
}


export default Login;

Can’t save notes in localStorage using JS

I tried saving the notes to local storage in different ways, but nothing worked. I also asked AI tools for help, but the solutions didn’t fix the problem or were too hard to follow. I’m still stuck and need clear, simple guidance to solve this.

let note_list=document.getElementById("note_list_container")


function addNote(){
  let input_note=document.getElementById("note").value
  if(input_note){

    let copyButton=document.createElement("button")
    copyButton.className="copy_button"
    copyButton.innerHTML=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="white"><path d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"/></svg>`
    copyButton.onclick=function copyContent(){
      navigator.clipboard.writeText(input_note) //creating copy paste button !
    }

    let deleteButton=document.createElement("button")
    deleteButton.className="delete_button"
    deleteButton.innerHTML=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="white"><path d="m791-55-91-91q-49 32-104.5 49T480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-60 17-115.5T146-700l-91-91 57-57 736 736-57 57ZM480-160q43 0 83.5-11t78.5-33L204-642q-22 38-33 78.5T160-480q0 133 93.5 226.5T480-160Zm334-100-58-58q22-38 33-78.5t11-83.5q0-133-93.5-226.5T480-800q-43 0-83.5 11T318-756l-58-58q49-32 104.5-49T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 60-17 115.5T814-260ZM537-537ZM423-423Z"/></svg>`
    deleteButton.onclick=function deleteNote(){
      display_note.style.display="none"  //creating delete note button, the delete button is created further down the page but its still working !
    }

    let editButton=document.createElement("button")
    editButton.innerHTML="edit"  

    let display_note=document.createElement("p") 

    display_note.className="note_info"    //appeding each button to our note 
    display_note.textContent=input_note
    note_list.appendChild(display_note)
    display_note.appendChild(deleteButton)
    display_note.appendChild(copyButton)
    document.getElementById("note").value=""
    display_note.appendChild(editButton);

    //creating a variable that will hold the localstorage
    //checks if there are any notes saved, if not it generates the localstorage
    

   
    editButton.onclick=function(){     //logic for editing the note and than saving the change 
      let edit_form=document.createElement("input")  
      edit_form.value=display_note.textContent
      edit_form.type="text"
      let save=document.createElement("button")
      save.textContent="save"     
      save.onclick=function(){
        display_note.textContent=edit_form.value
        display_note.appendChild(deleteButton)
        display_note.appendChild(copyButton)
        display_note.appendChild(editButton)
  }
      display_note.innerHTML=""  //emptying the html of the form so only the edit form and the save button appears
      display_note.appendChild(edit_form)
      display_note.appendChild(save) 
     
    }
  
  }

} 

Override console methods (log, warn, error) of an iframe

I want to override console methods (e.g. log, warn, error) of an iframe.

I get the error: webrtc/offer: stream not found in the console from the iframe.

I am trying to override console methods (log, warn, error) so that they does their original job in addition to storing all the method call arguments in a React State variable – consoleOutput.

But the data in consoleOutput is always empty. Any idea why I am unable to override those methods?

My code:

const iframeRef = useRef<HTMLIFrameElement | null>(null)
const [consoleOutput, setConsoleOutput] = useState<string[]>([])

useEffect(() => {
  if (iframeRef.current) {
    const iframeWindow = iframeRef.current.contentWindow as any;
    if (iframeWindow) {
      const originalConsole = iframeWindow.console;
      const newConsoleOutput: string[] = [];
      const wrapConsoleMethod = (method: keyof Console, prefix: string) => {
        return (...args: any[]) => {
          newConsoleOutput.push(`[${prefix}] ` + args.map(String).join(" "));
          setConsoleOutput([...newConsoleOutput]);
          originalConsole[method](...args);
        };
      };
      iframeWindow.console = {
        ...originalConsole,
        log: wrapConsoleMethod("log", "Log"),
        error: wrapConsoleMethod("error", "Error"),
        warn: wrapConsoleMethod("warn", "Warn"),
      };
    }
  }
}, []);


    <div>
        <h3>Console output from iframe::</h3>
        <pre>{consoleOutput.join('n')}</pre>
    </div>

    <iframe
        ref={iframeRef}
        src={iframeSrc}
        onLoad={() => console.warn('iframe loaded')}
    />

I am not able to redirect to my admin dashboard [closed]

I have created an Admin dashboard in my website using HTML CSS and JavaScript but when I try to login to my website with my admin account the website redirect me to the home page instead of admin dashboard

I have tried every possible fix for this and even use ai to fix this but still facing this issue and i am not getting any type of error

Not working console log input value by clicking Button [closed]

I am new at learning JS. I have a problem. I want to print input value by clicking button.

It is my code:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Price Tracker</title>
</head>
<body>
    <h1>Price Tracker</h1><br>
    <form>
        <input type="text" id="userInput" placeholder="Enter something">
        <button type="button" onclick="click()">Log Input</button>
    </form>
    <script src="script.js"></script>
</body>
</html>

and js code:

function click() {
    const inputValue = document.getElementById('userInput').value;
    console.log(inputValue);
}

Switching before and after image order in slider gallery

I’m working on a simple web gallery with two modes: standard (alternating) and before and after slider mode. Problem is that before and after images in slider mode should be switched but for the love of me I can’t figure it out, other than switching images in folders but that interferes with first mode but dealing with first mode might be simpler, ideally slider would work as it is intended. Doesn’t sound that hard but am new at this and I just don’t get it

Gallery, switch to slider mode by pressing W. To recrate just create two folders named “1 before” and “1 after” put two jpg images in each folder named “1” and “2” put them into the same folder as html.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dual Mode Gallery</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            overflow: hidden;
            background: #000;
            font-family: sans-serif;
            color: #fff;
        }

        .fullscreen-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: none; /* Default to transparent cursor */
        }

        .image-container {
            position: relative;
            width: 100%;
            height: 100%;
        }

        .gallery-image {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: contain;
        }

        .before-image,
        .after-image {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            object-fit: contain;
        }

        .after-image {
            clip-path: polygon(0 0, 0 100%, var(--clip-value) 100%, var(--clip-value) 0);
        }

        .slider {
            position: absolute;
            top: 0;
            bottom: 0;
            left: 100%;
            transform: translateX(-100%);
            width: 10px;
            background: transparent;
            cursor: none; /* Transparent cursor */
        }

        .slider-gallery {
            display: none; /* Initially hide slider mode */
        }

        .quick-menu {
            position: fixed;
            top: 10px;
            right: 10px;
            background: rgba(0, 0, 0, 0.8);
            padding: 5px;
            border-radius: 5px;
            font-size: 12px;
            display: none; /* Initially hidden */
        }

        .quick-menu h4 {
            margin: 0;
            font-size: 14px;
            text-align: center;
        }

        .quick-menu ul {
            padding: 0;
            list-style: none;
            margin: 5px 0 0;
        }

        .quick-menu li {
            margin: 0;
        }

    </style>
</head>
<body>

<div class="fullscreen-container alternating-gallery">
    <div class="image-container">
        <img class="gallery-image" src="">
    </div>
</div>

<div class="fullscreen-container slider-gallery">
    <div class="image-container">
        <img class="before-image" src="1 before/1.jpg">
        <img class="after-image" src="1 after/1.jpg" style="--clip-value: 100%;">
        <div class="slider"></div>
    </div>
</div>

<div class="quick-menu" id="quickMenu">
    <h4>Menu</h4>
    <ul>
        <li>Left-click: Next</li>
        <li>Right-click: Previous</li>
        <li>Arrow keys: Navigate</li>
        <li>W: Toggle mode</li>
        <li>R: Toggle menu</li>
    </ul>
</div>

<script>
    let mode = 'Alternating'; // Default mode
    let currentImageIndex = 0;
    let menuVisible = false;

    const alternatingContainer = document.querySelector('.alternating-gallery');
    const sliderContainer = document.querySelector('.slider-gallery');
    const quickMenu = document.getElementById('quickMenu');
    const fullscreenContainers = document.querySelectorAll('.fullscreen-container');

    // --- Alternating Gallery Mode Variables ---
    const alternatingGalleryImage = document.querySelector('.gallery-image');
    const alternatingImages = [
        { folder: '1 before', name: '1.jpg' },
        { folder: '1 after', name: '1.jpg' },
        { folder: '1 before', name: '2.jpg' },
        { folder: '1 after', name: '2.jpg' }
    ];

    function loadAlternatingImage() {
        const image = alternatingImages[currentImageIndex];
        alternatingGalleryImage.src = `${image.folder}/${image.name}`;
    }

    function nextAlternatingImage() {
        currentImageIndex = (currentImageIndex + 1) % alternatingImages.length;
        loadAlternatingImage();
    }

    function prevAlternatingImage() {
        currentImageIndex = (currentImageIndex - 1 + alternatingImages.length) % alternatingImages.length;
        loadAlternatingImage();
    }

    // --- Slider Gallery Mode Variables ---
    const sliderBeforeImage = document.querySelector('.before-image');
    const sliderAfterImage = document.querySelector('.after-image');
    const slider = document.querySelector('.slider');
    const sliderImages = ['1.jpg', '2.jpg'];

    function updateSliderPosition(x) {
        slider.style.left = `${x}px`;
        sliderAfterImage.style.setProperty('--clip-value', `${x}px`);
    }

    function nextSliderImage() {
        currentImageIndex = (currentImageIndex + 1) % sliderImages.length;
        sliderBeforeImage.src = `1 before/${sliderImages[currentImageIndex]}`;
        sliderAfterImage.src = `1 after/${sliderImages[currentImageIndex]}`;
        updateSliderPosition(sliderContainer.offsetWidth); // Reset slider to far right
    }

    function prevSliderImage() {
        currentImageIndex = (currentImageIndex - 1 + sliderImages.length) % sliderImages.length;
        sliderBeforeImage.src = `1 before/${sliderImages[currentImageIndex]}`;
        sliderAfterImage.src = `1 after/${sliderImages[currentImageIndex]}`;
        updateSliderPosition(sliderContainer.offsetWidth); // Reset slider to far right
    }

    sliderContainer.addEventListener('mousemove', (e) =>
        updateSliderPosition(e.clientX - sliderContainer.offsetLeft)
    );

    sliderContainer.addEventListener('click', () => nextSliderImage());

    // --- Mode Switching ---
    function toggleMode() {
        if (mode === 'Alternating') {
            mode = 'Slider';
            alternatingContainer.style.display = 'none';
            sliderContainer.style.display = 'flex';
            currentImageIndex = 0; // Reset index
            nextSliderImage(); // Load the first slider image
        } else {
            mode = 'Alternating';
            sliderContainer.style.display = 'none';
            alternatingContainer.style.display = 'flex';
            currentImageIndex = 0; // Reset index
            loadAlternatingImage(); // Load the first alternating image
        }
        console.log(`Mode switched to: ${mode}`);
    }

    // --- Toggle Menu Visibility ---
    function toggleMenu() {
        menuVisible = !menuVisible;
        quickMenu.style.display = menuVisible ? 'block' : 'none';
        fullscreenContainers.forEach(container => {
            container.style.cursor = menuVisible ? 'default' : 'none';
        });
    }

    document.addEventListener('keydown', (e) => {
        if (e.key === 'w') {
            toggleMode();
        } else if (e.key === 'ArrowRight') {
            mode === 'Alternating' ? nextAlternatingImage() : nextSliderImage();
        } else if (e.key === 'ArrowLeft') {
            mode === 'Alternating' ? prevAlternatingImage() : prevSliderImage();
        } else if (e.key === 'r') {
            toggleMenu();
        }
    });

    alternatingContainer.addEventListener('click', nextAlternatingImage);
    alternatingContainer.addEventListener('contextmenu', (e) => {
        e.preventDefault();
        prevAlternatingImage();
    });

    sliderContainer.addEventListener('contextmenu', (e) => {
        e.preventDefault();
        prevSliderImage();
    });

    // Initialize default mode
    loadAlternatingImage();
</script>

</body>
</html>