Next JS 13 routing, server actions and stale results

I have a basic todo app in next js 13 (13.12), I’m using server actions and the new App Router and am struggling to understand something.
My localhost:3000/ (HomePage) renders a list of todos by getting it from a database:

async function getTodos() {
    "use server";
    return await prisma.todo.findMany();
}

export default async Home() {
    const todos = await getTodos();
    
    return <ul className="pl-4">
                    {todos.map((todo) => (
                        <TodoItem
                            key={todo.id}
                            {...todo}
                        />
                    ))}
                </ul>
}

And I have a New page localhost:3000/new which is used to create a Todo:

async function createTodo(data: FormData) {
    "use server";
    const title = data.get("title")?.valueOf();
    if (typeof title !== "string" || title.length === 0) {
        throw new Error("title is required");
    }

    await prisma.todo.create({
        data: {
            title,
            complete: false,
        },
    });

    revalidatePath("/"); // my assumption is that this will tell next to regenerate the resource on this path
}

export default function HomePage() {
    return (
    <>
      <form action={createTodo}>...</form>
      <Link href="/">Go to todos</Link>
    </>
    )

}

Now we get to my question: by clicking the Link to go to "/", next performs client side routing, and navigates to my home page with the new todo not displayed until I do a full page refresh. My assumption was that saying revalidatePath("/") will tell next that I want a freshly generated Home page, but it is wrong. I could, instead of a link, use an anchor tag to force the browser to reload the page, but this feels wrong? What am i doing wrong here trying to understand routing in the AppRouter?

Note: I tried changing prefetch on the link but it only works once (i.e. after the first created todo and going back, it shows it, but every next form submission and back action does not show the new todo anymore)

Frontend To Backend [closed]

how to send data from the frontend to the backend so that the public cannot be accessed by the backend? and also how the folder structure.

I just want to make a simple website, So please just tell me the basics.

Jsjwjwheh

SVG filter not applied when using full screen

I use OpenSeaDragon for viewing images. In my HTML page I have got a checkbox. When it is it checked, a SVG filter is applied to the image. This works just fine, except when switching to full screen mode.

My question What should I do to have the filter also applied in full screen mode?

Run the snippet, check the checkbox, click on the ‘full page button’ and see what I mean.

(Bummer: switching to full screen mode does not seem to work here on Stackoverflow.
On Codepen the same code works: https://codepen.io/r-w-c/pen/bGQZMJb:

var filter_gs_mid_Checkbox1 = document.getElementById('openseadragon1-filter-gs-mid');

filter_gs_mid_Checkbox1.addEventListener('change', e => {
  var viewer = document.getElementById("openseadragon1");
  if (e.target.checked) {
    viewer.classList.add('filter-gs-mid'); // <----- The issue. This works, but it is not enough
  } else {
    viewer.classList.remove('filter-gs-mid');
  }
});

var viewer1 = OpenSeadragon({
  id: 'openseadragon1',
  prefixUrl: 'https://openseadragon.github.io/openseadragon/images/',
  tileSources: 'https://openseadragon.github.io/example-images/highsmith/highsmith.dzi',
  showNavigator: true,
});
.filter-gs-mid {
  filter: url(#grayscale-mid-filter);
}

#openseadragon1 {
border: 1px solid #000;
height:250px;
}
<script src="https://openseadragon.github.io/openseadragon/openseadragon.min.js"></script>

<!-- SVG used for image filter -->
<svg xmlns="http://www.w3.org/2000/svg">
        <filter id="grayscale-mid-filter"><feColorMatrix type="matrix" values="0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0"></feColorMatrix></filter>
     </svg>

<div>
  <div id="openseadragon-tools1" class="openseadragon-tools">
    <input type="checkbox" id="openseadragon1-filter-gs-mid" name="openseadragon1-filter-gs-mid" />
    <label for="openseadragon1-filter-gs-mid">Grayscale middle</label>
  </div>
  
  <div id="openseadragon-viewer1">
    <!--<div id="openseadragon1-bar" class="openseadragon-bar"></div>-->
    <div id="openseadragon1" class="openseadragon"></div>
  </div>
</div>

Having a Problem with Rendering MockMail Component After Correct Log In Credentials Entered on React Form

I am currently experiencing a problem whereby when I type the correct username and password credentials into the React Login form (which is initialized as user and pass) the MockMail component is not being rendered.

I have done console logs in the handleLogin function and the expected values are correct: Attempting login with: user pass
Logged in as: user – yet the mockmail still doesn’t render.
However the console logs in the MockmailContainer do not log, meaning there is a problem there?

I am wondering if it is my Router component not configured correctly?

Any help is greatly appreciated, thanks in advance.

import { BrowserRouter as Router, Routes, Route, Outlet } from 'react-router-dom';
import { StaticElementContainer } from "./containers/StaticElementContainer";
import { LoginFormContainer } from "./containers/LoginFormContainer";
import { MockMailContainer } from "./containers/MockMailContainer";
import { CreateAccountContainer } from "./containers/CreateAccountContainer";

function App() {
  const [loggedIn, setLoggedIn] = useState(false);
  const [users, setUsers] = useState([
    { id: 1, username: 'user', password: 'pass', email: '', phone: '' }
  ]);
  const [currentLoggedInUser, setCurrentLoggedInUser] = useState(null);

  const handleLogin = (username, password) => {
    console.log("Attempting login with:", username, password);
    const correctLoginCredentials = users.find(
      (user) => user.username === username && user.password === password
    );

    if (correctLoginCredentials) {
      setLoggedIn(true);
      setCurrentLoggedInUser(correctLoginCredentials.username);
      console.log("Logged in as:", correctLoginCredentials.username);
    } else {
      console.log("Invalid credentials");
    }
  };

  return (
    <Router>
      <Routes>
        <Route path="/" element={
          <StaticElementContainer>
            <LoginFormContainer 
              users={users}
              handleLogin={handleLogin}
            />
          </StaticElementContainer>
        } />
        <Route 
          path="/mockmail" 
          element={<MockMailContainer   
                    loggedIn={loggedIn}
                    currentLoggedInUser={currentLoggedInUser}
                   />} 
        />
        <Route path="/create-account" element={
          <StaticElementContainer>
            <CreateAccountContainer />
          </StaticElementContainer>
        } />
      </Routes>
    </Router>
  );
}

export default App;
import React, { useState } from 'react';
import { LoginForm } from '../components/LoginForm';

export const LoginFormContainer = ({ users, handleLogin }) => {

    const [username, setUsername] = useState("");
    const [password, setPassword] = useState("");
    const [usernamePlaceholder, setUsernamePlaceholder] = useState("Username...");
    const [passwordPlaceholder, setPasswordPlaceholder] = useState("Password...");

    const handleSubmit = (e) => {
        e.preventDefault();
        handleLogin(username, password);
      };

    const handleUsernameClick = () => {
        setUsernamePlaceholder("");
    };

    const handlePasswordClick = () => {
        setPasswordPlaceholder("");
    };

    const handleUsernameBlur = () => {
        if (username === "") {
            setUsernamePlaceholder("Username...");
        }
    };

    const handlePasswordBlur = () => {
        if (password === "") {
            setPasswordPlaceholder("Password...");
        }
    };

    const handleCreateAccountClick = () => {
        // navigate('/create-account');
    };

    return(
        <>
            <LoginForm
                username={username}
                setUsername={setUsername}
                password={password}
                setPassword={setPassword}
                handleSubmit={handleSubmit}
                handlePasswordClick={handlePasswordClick}
                handleUsernameClick={handleUsernameClick}
                usernamePlaceholder={usernamePlaceholder}
                passwordPlaceholder={passwordPlaceholder}
                handleUsernameBlur={handleUsernameBlur}
                handlePasswordBlur={handlePasswordBlur}
                handleCreateAccountClick={handleCreateAccountClick}
            />
        </>
    );
};
import React from "react";

export const LoginForm = ({ 
    username,
    setUsername,
    password,
    setPassword,
    handleSubmit,
    handlePasswordClick, 
    handleUsernameClick,
    usernamePlaceholder,
    passwordPlaceholder,
    handleUsernameBlur,
    handlePasswordBlur,
    handleCreateAccountClick
}) => {
    return (
        <form onSubmit={handleSubmit}>

            <h1 class="thin space">Sign In</h1>

            <h2 class='thin gap'>to continue to Gmail</h2>

            <label class="space line-height">
                <input 
                    class="input"
                    type='text' 
                    value={username} 
                    placeholder={usernamePlaceholder}
                    onFocus={handleUsernameClick}
                    onBlur={handleUsernameBlur}
                    onChange={(e) => setUsername(e.target.value)}
                />
            </label>
     
            <label class="space line-height">
                <input 
                    class="input disable-eye-icon"
                    type='password'
                    value={password}
                    placeholder={passwordPlaceholder}
                    onFocus={handlePasswordClick}
                    onBlur={handlePasswordBlur}
                    onChange={(e) => setPassword(e.target.value)}
                />
            </label>
            
            <button class="space blue-button" type='submit'>
                Login   
            </button>


            <p class="space hyper-link">Forgot Username?</p>
            <p class="space hyper-link">Forgot Password?</p>
            <button class="last grey-button" onClick={handleCreateAccountClick}>Create account</button>
        </form>
  );
}
import React from 'react';

export const MockMail = ({ loggedIn, currentLoggedInUser }) => {

    return (
        <>
            {loggedIn && currentLoggedInUser && (
                <h1>Welcome, {currentLoggedInUser}!</h1>
            )}
        </>
    )
}
import { MockMail } from '../components/MockMail';


export const MockMailContainer = ({ loggedIn, currentLoggedInUser }) => {
    console.log("loggedIn:", loggedIn);
    console.log("currentLoggedInUser:", currentLoggedInUser);
    

    return (
        <MockMail 
        loggedIn={loggedIn}
        currentLoggedInUser={currentLoggedInUser}
        />
    )
}

Jake

Issue with orbit controls after an gltf camera animation

I made/took this simple example ever for an easy debug, but what ever I did I end up to this. When the GLTF animation of my camera end, and I call the orbit controls, I get this jump effect

// PS: this example work locally
// Ps 2 : the bot tells my that my post is mostly code but i just try to provide all the data, so I add more details why I’m spamming this post scriptum 2 here sorry for the inconvenient

the testc.gltf file
https://file.io/ICJY4DjmcUmV

import * as THREE from 'three';

import Stats from 'three/addons/libs/stats.module.js';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';






let mixer;
let gltfObject;

const clock = new THREE.Clock();
const container = document.getElementById('container');

const stats = new Stats();
container.appendChild(stats.dom);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);

const pmremGenerator = new THREE.PMREMGenerator(renderer);

const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbfe3dd);
scene.environment = pmremGenerator.fromScene(new RoomEnvironment(renderer), 0.04).texture;

let camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(5, 2, 8);

let controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0.5, 0);
controls.update();
controls.enablePan = false;
controls.enableDamping = true;

const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('jsm/libs/draco/gltf/');

const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
loader.load('models/gltf/testc.gltf', function (gltf) {
    camera = gltf.cameras['0']; //if you have one camera or you need the first
    const model = gltf.scene;


    gltfObject = gltf;
    model.position.set(1, 1, 0);
    model.scale.set(0.01, 0.01, 0.01);
    scene.add(model);



    mixer = new THREE.AnimationMixer(model);
    let action = mixer.clipAction(gltf.animations[1]);
    action.setLoop(THREE.LoopOnce);
    action.clampWhenFinished = true;
    action.play();
    mixer.addEventListener('finished', function () {
        controls = new OrbitControls(camera, renderer.domElement);
        console.log("mixer complete");

    })

    gltf.animations; // Array<THREE.AnimationClip>
    gltf.scene; // THREE.Group
    gltf.scenes; // Array<THREE.Group>
    gltf.cameras; // Array<THREE.Camera>
    gltf.asset; // Object
    onWindowResize()
    animate();
    console.log("loadfn done");

}, undefined, function (e) {

    console.error(e);

});


function onWindowResize() {
    // Camera frustum aspect ratio
    camera.aspect = window.innerWidth / window.innerHeight;
    // After making changes to aspect
    camera.updateProjectionMatrix();
    // Reset size
    renderer.setSize(window.innerWidth, window.innerHeight);
    console.log("resized");
}

window.addEventListener('resize', onWindowResize, false);


function animate() {

    requestAnimationFrame(animate);

    const delta = clock.getDelta();

    mixer.update(delta);

    controls.update();

    stats.update();

    renderer.render(scene, camera);

}

Better method to replace a matched string with $1(or similar) but with a different return

i have
/b(Bobb |Boby |Bob )?momb/g

i would like to know if there is a simple method like this (it is invented js syntax, it is just my idea of “simple” and i am looking for a real way as simple as that):


.replace(/b(Bobb |Boby |Bob )?momb/g, '$1{Bobby }mom');

I know i could do this:

string.replace(/(Bobb |Boby |Bob )?mom/g, function(match, p1) {
  return "Bobby";
});

BUT it is too long.
I am looking for an easier method (like the one with invented syntax)

Is there a way to detect the scrolling direction in ReactJS with Framer Motion when the div is not scrollable?

I am attempting to replicate the effect that buttons are achieving when users scroll the mouse in the given program

import {useState, useEffect} from 'react';
import {motion} from 'framer-motion'

function Page({bgColor="red", isVisible, isDown}){
  return(
    <motion.div
      style={{ 
        height: '90vh',
        width: "100%",
        backgroundColor: bgColor,
        position: 'absolute',
      }}
      animate={{opacity: isVisible ? 1 : [1,0,0], y: isVisible ? 0 : isDown?[0,90, 180, 0]:[0,-90,-180, 0]}}
      transition={{delay: isVisible ? 0.15 : 0, duration: 0.5}}
    >
    </motion.div>
  )
}

function App(){
  const [currentPage, setCurrentPage] = useState(0);
  const [isScrollDirectionUp, setIsScrollDirectionUp] = useState(true)
  
  

  const pagesArr = [
    <Page bgColor={'blue'} isVisible={currentPage===0} isDown={isScrollDirectionUp}/>,
    <Page bgColor={'orange'} isVisible={currentPage===1} isDown={isScrollDirectionUp}/>,
    <Page bgColor={'green'} isVisible={currentPage===2} isDown={isScrollDirectionUp}/>,
    <Page bgColor={'red'} isVisible={currentPage===3} isDown={isScrollDirectionUp}/>
  ]

  function nextPageButtonHandler(){
    var newPageno = (+(currentPage)+1)%pagesArr.length;
    setIsScrollDirectionUp(false)
    setCurrentPage(newPageno);
  }

  function prevPageButtonHandler(){
    var newPageno = +(currentPage) - 1;
    if(newPageno<0){
      newPageno = pagesArr.length - 1;
    }
    setIsScrollDirectionUp(true)
    setCurrentPage(newPageno);
  }

  return (
    <div>
      <div style={{position:"fixed",zIndex:"3"}}>
        <button onClick={prevPageButtonHandler} >prev page</button>
        <button onClick={nextPageButtonHandler} >next page</button>
      </div>

      {pagesArr.map((Page)=>{
        return Page
      })}
      
    </div>
  );
}
export default App;

In this program there are four divs(3 transparent and 1 visible) stacked on top of each other. when “prev page” or “next page” button is click the page appearing to the user changes with an animation. the page that was first visible starts moving up and getting transparent, side by side other page start appearing, then the page that was moving up, after getting transparent, moves down back to the original position. This results in effect of moving to the next page.

I attempted to implement the described animation using “scroll” event listener in javascript, but unfortunately, it does not work for the unscrollable div elements(elements will be unscrollable).

function handleScrolling(event){
    console.log(event);
  }
  
  useEffect(()=>{
    window.addEventListener('scroll', handleScrolling);
    return(()=>{
      window.removeEventListener('scroll', handleScrolling)
    })
  },[])

The program should detect the scroll and change the states: setCurrentPage and setIsScrollDirectionUp.

I would appreciate any guidance or suggestions on how to address this issue and make the animation work when mouse is scrolled

Discord Guild Commands not register

I programmed a context menu handler a few days ago, but I made an error. Namely, the context menus overwrote all guild commands because they weren’t exported at the same time.

Now my guild commands don’t work anymore or just not for the guild on which I also loaded the context menus.

I’ve already tried to kick the bot but it doesn’t help.

The order to upload the Guild Slash Commands is permanently on pending.

My Slash Command handler:

const fs = require('fs');
const chalk = require('chalk');

const { PermissionsBitField } = require('discord.js');
const { Routes } = require('discord-api-types/v10');
const { REST } = require('@discordjs/rest')

const AsciiTable = require('ascii-table');
const table = new AsciiTable().setHeading('Slash Commands', 'Stats').setBorder('|', '=', "0", "0")

const TOKEN = "";
const CLIENT_ID = "1034931814717980682";
const GUILD_ID = "921103666818191440";

const rest = new REST({ version: '10' }).setToken(TOKEN);

module.exports = (client) => {
    const GUILD = client.guilds.cache.get(GUILD_ID)
    const slashCommands = [];

    fs.readdirSync('./slashCommands/').forEach(async dir => {
        const files = fs.readdirSync(`./slashCommands/${dir}/`).filter(file => file.endsWith('.js'));

        for(const file of files) {
                const slashCommand = require(`../slashCommands/${dir}/${file}`);
                slashCommands.push({
                    name: slashCommand.name,
                    description: slashCommand.description,
                    type: slashCommand.type,
                    options: slashCommand.options ? slashCommand.options : null,
                    default_permission: slashCommand.default_permission ? slashCommand.default_permission : null,
                    default_member_permissions: slashCommand.default_member_permissions ? PermissionsBitField.resolve(slashCommand.default_member_permissions).toString() : null
                });
            
                if(slashCommand.name) {
                    client.slashCommands.set(slashCommand.name, slashCommand)
                        table.addRow(file.split('.js')[0], '✅')
                } else {
                        table.addRow(file.split('.js')[0], '⛔')
                }
        }
        
    });
    console.log(chalk.red(table.toString()));

    (async () => {
            try {
                await rest.put(
    GUILD_ID ?
    Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID) :
    Routes.applicationCommands(CLIENT_ID), 
    { body: slashCommands }
);

                console.log(chalk.yellow('Slash Commands • Registered'))
            } catch (error) {
                console.log(error);
            }
    })();
};

The lines which always on pending:

await rest.put(
GUILD_ID ? Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID) : Routes.applicationCommands(CLIENT_ID),
{body: slashCommands}
);

adding image in between v-for in vuetify

I want to add images later, but I am using v-for, and I don’t know what to do to add the image in between without breaking the loop.

<template>
  <v-card>
    <p v-for="item in texts" :key="item.id" class="bm-1">{{ item.text }}</p>
  </v-card>
</template>

<script lang="ts">
import { Vue } from "nuxt-property-decorator";

export default class QuickStart extends Vue {
  texts: any[] = [
    {
      id: 0,
      text: "Text A",
    },
    {
      id: 1,
      text: "Text B",
    },
    {
      id: 2,
      text: "Text C",
    },
  ];
}
</script>

For example, in the code above, I want to add an image between id 1 and 2, but how? (And I want to use the v-for too. If that wasn’t the case, I know I could have just added numbers or p tags.)

I tried to put an image with an id and text, but as expected, it didn’t work.

How does echarts fill the width of the parent element?

I have encapsulated an electrocharts component in Vue to display charts.

It receives three parameters from the parent component: chartWidth, chartHeight, and options.

When the chart is wrapped in a b-tab (bootstrap), I use “1000px” for the height of the chart, and it performs normally. When I use ‘100%‘, it does not occupy the entire width of the parent element.

<div class="carousel-slide">
<ChartView :options="buildingEnergyConsumption"
       :chartWidth="'100%'"
       :chartHeight="'550px'"></ChartView>
</div>

And the browser gives an warn:
Can’t get DOM width or height Please check dom. clientWidth and dom. clientHeight. They should not be 0. For example, you may need to call this in the callback of window. onload

I think it’s because the b-tab has not been rendered yet, which prevents the component from obtaining the width of the parent element.

The code is here:

<template>
    <div ref="chart" :style="{ width: chartWidth, height: chartHeight }"></div>
</template>

<script>
    import * as echarts from 'echarts';

    export default {
        name: 'ChartView',
        props: {
            chartWidth: {
                type: String,
                default: '100%'
            },
         
            chartHeight: {
                type: String,
                default: '100%'
            },
            options: {
                type: Object,
                required: true,
            }
        },
        methods: {
           
            initChart() {
                this.chart = echarts.init(this.$refs.chart);
                this.chart.setOption(this.options);
 
                window.addEventListener('resize', this.resizeChart);
            },
 
            resizeChart() {
                if (this.chart) {
                    this.chart.resize();
                }
            },
        },
        mounted() {
            this.initChart();
        },
        watch: {
           
            options: {
                handler(newVal) {
                    this.chart.clear();
                    this.chart.setOption(newVal);
                },
                deep: true
            }
        },
        beforeDestroy() {

            this.chart.dispose();

            window.removeEventListener('resize', this.resizeChart);
        }
    };
</script>

<style scoped>
</style>

So how should this situation be resolved?

Looking forward to everyone’s help, thank you!

Search suggestions popup not closing in react

I am trying to build an input box where the user will type inputs and based on the input there will be an suggestions popup under the input box where suggestions will be shown. In my code the suggestions are showing perfectly but when I give more inputs the previous popover doesn’t close.

return <div className="border border-gray-400 rounded-md mx-10 my-10 h-10 relative">
      <input
        value={value}
        onChange={(e) => setValue(e.target.value)}
        className="w-full border-none absolute inset-0 z-10 outline-none px-2 text-sm bg-transparent"
        style={{ WebkitTextFillColor: "transparent" }}
        maxLength={maxLength}
      />
      <div className="text-sm absolute inset-0 flex items-center px-2 whitespace-pre">
        {value.split(" ").map((word, i) => {
          const isHighlighted = word.toLowerCase().includes(suggestions[0]);
          return (
            <div className="relative" key={i}>
              {isHighlighted ? (
                <>{getHighlightedSyntex(word, i)}</>
              ) : (
                getSyntex(word, i)
              )}
              {getSuggestions(word)}
            </div>
          );
        })}
      </div>
    </div>

This is where I am showing my renders. That getSuggestions function is,

 const getSuggestions = (word) => {
    const matchedPartialSuggestions = suggestions.filter(
      (item) => word !== "" && item.toLowerCase().startsWith(word.toLowerCase())
    );
    console.log('va', word, matchedPartialSuggestions)
    return (
      <>
        {matchedPartialSuggestions.length > 0 && (
          <div className="absolute z-10 p-2 bg-white border rounded shadow-lg">
            {matchedPartialSuggestions?.map((item, i) => {
            return <p key={i}>{highlightMatching(word, item)}</p>;
            })}
          </div>
        )}
      </>
    );
  };

Here in the functions, I am showing that popup that contains search suggestions. I know why the popup doesn’t close it’s because when I type something that matches the data from suggestions, the variable from getSuggestions functions got the data as filtered value. That’s why the popup doesn’t close. But i need to the search suggestions only when any inputted value matches the search suggestions data, otherwise the popup will be always hidden.

How to separate array into 4 columns and pass to each column 10 items from array?

Lets say there is an dynamic array containing 40 elements (array doesn’t change over time, but changes on every render). What I want to do is, loop through this array and return 4 elements, each containing 10 li elements (which are objects from my array), where none object from array is repeated. How to achieve that with JavaScript ?

I wanted to style objects from array with one parent flex container, containing 4 div elements with flex: 25%, and li elements being children of that 4 divs. Like in this example: w3c.
But my images are not static so I can’t define each element with typing

chess.js – unable to make a move using the permissive parser

I can only make moves using the SAN and object notations. The permissive parser doesn’t work. I tried using the { permissive: true } option but it doesn’t seem to do anything. Did I miss something?

const game = new Chess();
game.move('e2-e4');
game.fen();

Returns rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1.

const game = new Chess();
game.move('e4'); // Or game.move({ from: 'e2', to: 'e4' });
game.fen();

Returns rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1.
And by the way, ‘e4’ looks more permissive than ‘e2-e4’ to me…

Auto Dial a phone number from web application on mobile browser [Without going to dialpad]

i want to create a link or something on which if a user clicks on “Call” button, it’ll directly dial the call rather than taking it to dialer-pad. Now but in mobile browsers, clicking on such link will open the dialer-pad, is there any way to directly call from web browser [Mobile]

Asked a question on mobile browser capability, and expecting a right response based on that.