How do I make a simple password page within my one HTML file?

I’m a self-taught programmer and I’m planning on making a small puzzle website where the clues are on the pages available and to enter other pages, you have to first enter a password. I’m trying to make it like the happy meat farms employee portal:

  • press the link that should take you to the allocated page
  • redirects you to a password page first where you enter password
  • if it’s the correct password, you once again get redirected to the page

Each password required page (there’s 3) has a different password.
I have all the pages created and designed, so my only thing to do now is the password page.

Each page follows this format:

<div class="page">

    <header>

        <h1>header words</h1>

    </header>

    <p>blahblahblah</p>

</div>

and I have a changepage script:

    <script>

            var page = document.getElementsByClassName('page');

            function changePage(pageNum) {

                for (var i = 0; i < page.length; i++) {

                    page[i].style.display = 'none';

                    page[pageNum - 1].style.display = 'block';

                }



                menu.style.left = '-270px';

                closeBtn.style.top = '-270px';



                window.scroll(0, 0);

            }

            changePage(1);

        </script>

I do not want the pages to be separate html files.
Please help I have no idea how to do it :cc

the three places where once pressed currently redirect you to the pages:
https://i.sstatic.net/WivlW4gw.png
https://i.sstatic.net/QXdNu7nZ.png
https://i.sstatic.net/wiAeRWKY.png

If still unclear what I mean, maybe try going to this website:
https://www.happymeatfarms.com/employee-access
and click the “access employee portal” at the bottom. Basically what I’m aiming for, but with multiple links instead of just one.

Google extension: How to sendMessage on tab change?

Goal

Send message from my content script to my background script whenever the tab changes. The message includes text queried from DOM in content script

Heres what I have so far

Contentscript.js

 chrome.runtime.sendMessage(null, workspaceName); // heres where I send the name

background.js and `popUp.js

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
    workspaceName = msg;
    console.log(`Workpspace: ${msg}`);
});

This only runs on page load/refresh and when extension is open

How can I disable reverse animation for this effect?

https://jsfiddle.net/9Lbe8kcj/

#container {
  width: 100%;
  height: 100%;
  background-color: red;
  position: relative;
}

#scroll-container-one {
  width: 1000px;
  height: 500px;
  overflow-y: scroll;
  overflow-x: hidden;
  background: green;
}

.box-one {
  height: 600px;
  background-color: purple;
  font-size: 32px;
}

.box-two {
  height: 1400px;
  position: relative;
  background-color: orange;
}

.inside-box {
  height: 500px;
  position: sticky;
  top: 0;
  background-color: white;
  display: flex;
  justify-content: space-between;
  opacity: 1;
}

.inside-box div {
  width: 300px;
  height: 200px;
  background-color: blue;
  font-size: 40px;
  animation: appear linear forwards;
  animation-timeline: view(600px);
  opacity: 0;
}

#one {
  animation-range-start: 100px;
  animation-range-end: 400px;
}

#two {
  animation-range-start: 500px;
  animation-range-end: 800px;
}

#three {
  animation-range-start: 900px;
  animation-range-end: 1200px;
}

@keyframes appear {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.box-three {
  height: 1000px;
  background-color: yellow;
}
<div id="container">
  <div id="scroll-container-one">
    <div class="box-one">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit, assumenda quisquam. Minus culpa quo a esse nostrum, laborum aspernatur ipsa nisi cum blanditiis facilis, minima unde soluta quos, dolorum impedit!
    </div>
    <div class="box-two">
      <div class="inside-box">
        <div id="one">abooga</div>
        <div id="two">awooga</div>
        <div id="three">asooga</div>
      </div>
    </div>
    <div class="box-three">box 3</div>
  </div>
</div>

I created an example of what I basically want. The only thing is, I wanted it so that when the user scrolls back up, they wouldn’t have to go through all the animations reversing. As well as not have to go through the entire div that contains the sticky div which is only that height so that the effect of making elements appear with each scroll can be created.

I am almost 100% sure I’ve seen this effect (with no reverse animations when scrolling back up and everything) on some websites in the past but I can’t seem to find one now that I am actively looking for one.

If anyone can link a or multiple websites that uses this effect, that would be very helpful too

Run REST API call functions in order in a Node.js loop

I know this has been asked many times, but I’ve tried everything I can find with no success. Thank you for any patience as I am not a professional programmer. I simply like to automate my tasks when working in a CMS. The specific use case is to transform one row in a CSV file into a page in the CMS using the CMS’s REST API. Is anyone able to guide me in running this script, especially its functions in a loop, in order?

The parent function (main) is async because the library used to transform TSV to JSON (csvtojson) requires await. I also used await when calling the jq library to manipulate the JSON after using csvtojson.

The main issue lies with the two API call functions in the loop. In the iteration of the code below, the console showed that the second function ran 5 times, failing each time because it lacked the data piped to it by the first function/API call. Then the second function ran 6 times before I stopped execution.

Code:

var csv = require("csvtojson");
var jq = require('node-jq');

var parentFolder = 1234
var token = ""
var csvFilePath = 'licenses.tsv'
var parentPublicationId = 5678

async function main() {

  // Transform CSV/TSV to JSON
  json = '';
  await csv({
    delimiter: 't'
  })
    .fromFile(csvFilePath)
    .then((jsonObj) => {
      json = jsonObj
    })

  // Create an array of objects with certain keys
  jsonOutput = '';
  await jq.run('[.[] | {name: .sourceName}]', json, { input: 'json' })
    .then((output) => {
      jsonOutput = output
    })
    .catch((err) => {
      console.error(err)
    })

  parsed = JSON.parse(jsonOutput)

  // Create a page in the CMS for each CSV/TSV row
  for (var obj in parsed) {

    id = '';
    async function createDocument() {
      var name = parsed[obj].name;
      var content = `<title>${name}</title></section>`;
      var inputBody = {
        "parent": parentFolder,
        "name": name,
        "content": content,
        "subtype": "component"
      };
      var headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Basic ' + token,
      };

      fetch('https://thesite.com/api/v2/documents',
        {
          method: 'POST',
          body: JSON.stringify(inputBody),
          headers: headers
        })
        .then(function (res) {
          return res.json();
        }).then(function (body) {
          console.log(body);
          id = body.id;
          // Capture document ID from response
          console.log(id);
        });
      return
    }

    // Add the new page to an existing table of contents
    async function updatePublication() {
      await createDocument();

      var inputBody = {
        "parent": parentPublicationId,
        "document": id,
        "position": "null",
      };
      var headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Basic ' + token,
      };

      fetch('https://thesite.com/api/v2/forks',
        {
          method: 'POST',
          headers: headers,
          body: JSON.stringify(inputBody)
        })
        .then(function (res) {
          return res.json();
        }).then(function (body) {
          console.log(body);
        });
    }
    updatePublication();
  }
}
main()

If you would like me to provide more examples of what I’ve tried I am happy to – basically different iterations of async/await, promises and then, return, callbacks, and more. Over and over, things always run out of order. Thank you for any kind help.

What is the correct aria and role for a button/label that fills the value of an input?

If a set of buttons (or labels) set the value of an input with a different value each, what roles and arias should they possess?
In this scenario the input can also be inserted/edited by the user manually.

So they would work similar to a set of radio buttons with an “Other, insert below” option.

Here is an example:

$("label").on("click", (event) => {
  const text = event.target.textContent;
  $("#text").val(text);
});
label {
  display: block;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<form action="javascript:void(0)">
  <label for="text">Text A</label>
  <label for="text">Text B</label>
  <label for="text">Text C</label>
  <input type="text" id="text" />
</form>

I’ve used labels in this case, so that the user can make edits to the selected with the least amount of actions possible. Labels also signify the link between the elements.

Should I add aria-controls, should I use buttons, should I change the overwrite the roles?

Why does my large text have so much vertical padding, even after I’ve set padding for the element to 0?

I have a simple JavaScript game to teach my girlfriend the Hindi alphabet. However, it doesn’t look very good because the letter flashcard has some kind of vertical margin, padding or line height that I can’t get rid of. I coded the p#card for padding: 0 and margin: 0 and line-height for a few pixels more than the font-size but I still have this annoying extra space that shrinks but remains after I shrink the text. Any help would be greatly appreciated. Thank you.

https://codepen.io/Brian-O-the-solid/pen/mdZQeXN

const hindiAlphabet = [
  // Vowels
  {
    letter: "अ",
    pronunciation: "a",
    example: "अनार",
    exampleTranslation: "pomegranate"
  },
  {
    letter: "आ",
    pronunciation: "aa",
    example: "आम",
    exampleTranslation: "mango"
  },
  {
    letter: "इ",
    pronunciation: "i",
    example: "इमली",
    exampleTranslation: "tamarind"
  },
  {
    letter: "ई",
    pronunciation: "ee",
    example: "ईख",
    exampleTranslation: "sugarcane"
  },
  {
    letter: "उ",
    pronunciation: "u",
    example: "उल्लू",
    exampleTranslation: "owl"
  },
  {
    letter: "ऊ",
    pronunciation: "oo",
    example: "ऊंट",
    exampleTranslation: "camel"
  },
  {
    letter: "ऋ",
    pronunciation: "ri",
    example: "ऋषि",
    exampleTranslation: "sage"
  },
  {
    letter: "ए",
    pronunciation: "e",
    example: "एड़ी",
    exampleTranslation: "heel"
  },
  {
    letter: "ऐ",
    pronunciation: "ai",
    example: "ऐनक",
    exampleTranslation: "spectacles"
  },
  {
    letter: "ओ",
    pronunciation: "o",
    example: "ओस",
    exampleTranslation: "dew"
  },
  {
    letter: "औ",
    pronunciation: "au",
    example: "औरत",
    exampleTranslation: "woman"
  },
  {
    letter: "अं",
    pronunciation: "an",
    example: "अंगूर",
    exampleTranslation: "grapes"
  },
  {
    letter: "अः",
    pronunciation: "ah",
    example: "वह",
    exampleTranslation: "that"
  },
  // Consonants
  {
    letter: "क",
    pronunciation: "ka",
    example: "कमल",
    exampleTranslation: "lotus"
  },
  {
    letter: "ख",
    pronunciation: "kha",
    example: "खरगोश",
    exampleTranslation: "rabbit"
  },
  {
    letter: "ग",
    pronunciation: "ga",
    example: "गमला",
    exampleTranslation: "pot"
  },
  {
    letter: "घ",
    pronunciation: "gha",
    example: "घड़ी",
    exampleTranslation: "watch"
  },
  {
    letter: "ङ",
    pronunciation: "nga",
    example: "अंग",
    exampleTranslation: "part"
  },
  {
    letter: "च",
    pronunciation: "cha",
    example: "चमक",
    exampleTranslation: "shine"
  },
  {
    letter: "छ",
    pronunciation: "chha",
    example: "छाता",
    exampleTranslation: "umbrella"
  },
  {
    letter: "ज",
    pronunciation: "ja",
    example: "जहाज",
    exampleTranslation: "ship"
  },
  {
    letter: "झ",
    pronunciation: "jha",
    example: "झंडा",
    exampleTranslation: "flag"
  },
  {
    letter: "ञ",
    pronunciation: "nya",
    example: "ज्ञान",
    exampleTranslation: "knowledge"
  },
  {
    letter: "ट",
    pronunciation: "ṭa",
    example: "टोपी",
    exampleTranslation: "cap"
  },
  {
    letter: "ठ",
    pronunciation: "ṭha",
    example: "ठंडी",
    exampleTranslation: "cold"
  },
  {
    letter: "ड",
    pronunciation: "ḍa",
    example: "डमरू",
    exampleTranslation: "drum"
  },
  {
    letter: "ढ",
    pronunciation: "ḍha",
    example: "ढोल",
    exampleTranslation: "dhol"
  },
  {
    letter: "ण",
    pronunciation: "ṇa",
    example: "अर्णव",
    exampleTranslation: "ocean"
  },
  {
    letter: "त",
    pronunciation: "ta",
    example: "तारा",
    exampleTranslation: "star"
  },
  {
    letter: "थ",
    pronunciation: "tha",
    example: "थाली",
    exampleTranslation: "plate"
  },
  {
    letter: "द",
    pronunciation: "da",
    example: "दादी",
    exampleTranslation: "grandmother"
  },
  {
    letter: "ध",
    pronunciation: "dha",
    example: "धन",
    exampleTranslation: "wealth"
  },
  {
    letter: "न",
    pronunciation: "na",
    example: "नल",
    exampleTranslation: "tap"
  },
  {
    letter: "प",
    pronunciation: "pa",
    example: "पानी",
    exampleTranslation: "water"
  },
  {
    letter: "फ",
    pronunciation: "pha",
    example: "फल",
    exampleTranslation: "fruit"
  },
  {
    letter: "ब",
    pronunciation: "ba",
    example: "बकरी",
    exampleTranslation: "goat"
  },
  {
    letter: "भ",
    pronunciation: "bha",
    example: "भालू",
    exampleTranslation: "bear"
  },
  {
    letter: "म",
    pronunciation: "ma",
    example: "मकान",
    exampleTranslation: "house"
  },
  {
    letter: "य",
    pronunciation: "ya",
    example: "यात्रा",
    exampleTranslation: "journey"
  },
  {
    letter: "र",
    pronunciation: "ra",
    example: "रोटी",
    exampleTranslation: "bread"
  },
  {
    letter: "ल",
    pronunciation: "la",
    example: "लड़की",
    exampleTranslation: "girl"
  },
  {
    letter: "व",
    pronunciation: "va",
    example: "वृक्ष",
    exampleTranslation: "tree"
  },
  {
    letter: "श",
    pronunciation: "sha",
    example: "शेर",
    exampleTranslation: "lion"
  },
  {
    letter: "ष",
    pronunciation: "ṣha",
    example: "षट्कोण",
    exampleTranslation: "hexagon"
  },
  {
    letter: "स",
    pronunciation: "sa",
    example: "समुद्र",
    exampleTranslation: "ocean"
  },
  {
    letter: "ह",
    pronunciation: "ha",
    example: "हाथी",
    exampleTranslation: "elephant"
  },
  {
    letter: "क्ष",
    pronunciation: "kṣa",
    example: "क्षत्रिय",
    exampleTranslation: "warrior"
  },
  {
    letter: "त्र",
    pronunciation: "tra",
    example: "त्रिशूल",
    exampleTranslation: "trident"
  },
  {
    letter: "ज्ञ",
    pronunciation: "gya",
    example: "ज्ञान",
    exampleTranslation: "knowledge"
  }
];


card = document.getElementById("card");

index = 0;

hindi = hindiAlphabet[index].letter;
english = hindiAlphabet[index].pronunciation;

card.innerHTML = hindi;
side = "hindi";

function flip() {
  if (side == "hindi") {
    card.innerHTML = english;
    side = "english";
  } else {
    card.innerHTML = hindi;
    side = "hindi";
  }
}

function refresh() {
  hindi = hindiAlphabet[index].letter;
  english = hindiAlphabet[index].pronunciation;
  card.innerHTML = hindi;
  side = "hindi";
  console.log("index refreshed to " + index);
}

function backward() {
  if (index == 0) {
    index = 47;
    refresh();
  } else {
    index = index - 1;
    refresh();
  }
}

function forward() {
  if (index == 47) {
    console.log("index is 47");
    index = 0;
    refresh();
  } else {
    index = index + 1;
    refresh();
  }
}
/* Here is my css.It 's not complicated. There has been a lot of effort to get rid of the extra vertical padding on the flashcard. */

body {
  background-color: #FFD700;
}

.field {
  width: 90%;
  margins: 0 auto;
  padding: 0;
}

#card {
  width: 100%;
  font-size: 200px;
  padding: 0;
  margins: 0;
  text-align: center;
  vertical-align: middle;
  color: #FF5733;
}

.button-box {
  width: 90%;
  margins: 0 auto;
}

.button {
  font-size: 3em;
  color: blue;
  width: 46%;
  padding: 0;
  margin: 0;
  display: inline-block;
  text-align: center;
}
<!doctype html>
<html lang="hi">

<head>
  <link rel="stylesheet" type="text/css" href="hindi-styles.css">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Hindi Alphabet</title>
</head>

<body>
  Here is my html. It's just a simple empty box to insert the letter flashcards into using JavaScript.

  <div class="field" id="field" onclick="flip();">
    <p id="card"></p>
  </div>

  <div class="button-box">
    <div class="back button" onclick="backward();">
      <p>Back</p>
    </div>

    <div class="next button" onclick="forward();">
      <p>Next</p>
    </div>
    <div class="button-box">


      <script type="text/javascript" src="hindiAlphabet.js"></script>

Problem developing a smart contact in remix ethereum

Here`s my log.

Ethereum is defined. Starting network switch…

Switching to Avalanche Fuji C-Chain with chainId 0xa869…

Attempting to switch to Avalanche Fuji C-Chain using RPC URL: https://api.avax-test.network/ext/bc/C/rpc...

Switched to Avalanche Fuji C-Chain successfully using RPC URL: http

access.js:51

s://api.avax-test.network/ext/bc/C/rpc.

Checking contract deployment… Contract is deployed. Requesting accounts…
Fetching accounts…

Accounts found. Fetching or registering username…

MetaMask RPC Error: Internal JSON-RPC error.

►(code: -32603, message: ‘Internal JSON-RPC error., data: {…}}

User is not registered. Proceeding with registration…

My log stops here.

My .js functions

import { ethers } from 'ethers';
import abi from './abi.json';

const checkContractDeployment = async (provider, address) => {
  const code = await provider.getCode(address);
  return code !== '0x';
};

const switchToAvalanche = async () => {
  const avalancheChainId = '0xa869'; // Avalanche Fuji C-Chain
  const avalancheChainName = 'Avalanche Fuji C-Chain';
  
  const avalancheRpcUrls = [
    'https://api.avax-test.network/ext/bc/C/rpc',
    'https://rpc.ankr.com/avalanche_fuji',
    'https://avalanche-fuji-c-chain.publicnode.com',
  ];
  const avalancheBlockExplorerUrl = 'https://testnet.snowtrace.io';

  console.log(`Switching to ${avalancheChainName} with chainId ${avalancheChainId}...`);

  let rpcUrlIndex = 0;
  let successfulSwitch = false;

  while (rpcUrlIndex < avalancheRpcUrls.length && !successfulSwitch) {
    const avalancheRpcUrl = avalancheRpcUrls[rpcUrlIndex];

    try {
      console.log(`Attempting to switch to ${avalancheChainName} using RPC URL: ${avalancheRpcUrl}...`);
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: avalancheChainId }],
      });
      console.log(`Switched to ${avalancheChainName} successfully using RPC URL: ${avalancheRpcUrl}.`);
      successfulSwitch = true;
    } catch (switchError) {
      console.error(`Error switching to ${avalancheChainName} using RPC URL: ${avalancheRpcUrl}:`, switchError);

      if (switchError.code === 4902) {
        try {
          console.log(`Adding ${avalancheChainName} with RPC URL: ${avalancheRpcUrl}...`);
          await window.ethereum.request({
            method: 'wallet_addEthereumChain',
            params: [{
              chainId: avalancheChainId,
              chainName: avalancheChainName,
              rpcUrls: [avalancheRpcUrl],
              blockExplorerUrls: [avalancheBlockExplorerUrl],
            }],
          });
          console.log(`Added ${avalancheChainName} successfully using RPC URL: ${avalancheRpcUrl}.`);
          successfulSwitch = true;
        } catch (addError) {
          console.error(`Failed to add ${avalancheChainName} to MetaMask using RPC URL: ${avalancheRpcUrl}:`, addError);
        }
      } else if (switchError.code === -32002) {
        console.error(`A request to add or switch to ${avalancheChainName} is already pending. Please check MetaMask.`);
        alert(`A request to add or switch to ${avalancheChainName} is already pending in MetaMask. Please open MetaMask and complete the request.`);
        return;
      }
    }

    rpcUrlIndex++;
  }

  if (!successfulSwitch) {
    alert(`Failed to switch to ${avalancheChainName}. Please try again.`);
  }
};

export const validation = async (router, username, setError) => {
  validateUsername(username, setError);
  if (document.querySelector("#errorAccess").innerHTML !== "") {
    return;
  }

  console.log('Starting validation...');

  if (typeof window.ethereum !== 'undefined') {
    console.log('Ethereum is defined. Starting network switch...');
    await switchToAvalanche();

    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();
    const contractAddress = "0xf97d82fd7203d74Aa4a169F933992e350445D8fd"; // Update with your new contract address
    const userAuthContract = new ethers.Contract(contractAddress, abi, signer);

    console.log('Checking contract deployment...');
    try {
      const isContractDeployed = await checkContractDeployment(provider, contractAddress);
      if (!isContractDeployed) {
        console.error('Contract not deployed at this address.');
        await router.push('/access?error=Contract not deployed at this address.');
        return;
      }
    } catch (error) {
      console.error('Error during contract deployment check:', error);
      await router.push('/access?error=' + encodeURIComponent(error.message));
      return;
    }

    console.log('Contract is deployed. Requesting accounts...');
    try {
      await provider.send('eth_requestAccounts', []);
      
      console.log('Fetching accounts...');
      const accounts = await provider.listAccounts();
      if (!accounts || accounts.length === 0) {
        await router.push('/access?error=No accounts found. Please login to MetaMask.');
        return;
      }

      console.log('Accounts found. Fetching or registering username...');
      let registeredUsername;

      try {
        registeredUsername = await userAuthContract.getUser(); // No argument needed
        console.log('Registered username:', registeredUsername);
      } catch (error) {
        if (error.data && error.data.message.includes('User not registered')) {
          console.log('User is not registered. Proceeding with registration...');
          if (confirm('You are about to create a new account. Is this what you would like?')) {
            const tx = await userAuthContract.register(username);
            await tx.wait();
            console.log('User registered successfully.');

            const logged = await makeLog(username);
            if (logged === 200) {
              await router.push('/');
            } else {
              await router.push('/access?error=' + encodeURIComponent(logged));
            }
          } else {
            setusernameError('Invalid user.', setError);
          }
        } else {
          throw error; // Re-throw if it's a different error
        }
      }
    } catch (providerError) {
      console.error('Error requesting accounts:', providerError);
      await router.push('/access?error=' + encodeURIComponent(providerError.message));
    }
  } else {
    document.querySelector(".overlay").style.display = "flex";
  }
};

My .sol code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

contract UserAuth {
    struct User {
        string username;
        address userAddress;
    }

    mapping(address => User) private users;
    mapping(string => address) private usernames;

    event UserRegistered(address indexed userAddress, string username);

    function register(string memory _username) public {
        require(bytes(_username).length > 0, "Username cannot be empty");
        require(users[msg.sender].userAddress == address(0), "User already registered");
        require(usernames[_username] == address(0), "Username already taken");

        // Register the new user
        users[msg.sender] = User(_username, msg.sender);
        usernames[_username] = msg.sender;

        emit UserRegistered(msg.sender, _username);
    }

    function getUser() public view returns (string memory) {
        require(users[msg.sender].userAddress != address(0), "User not registered");
        return users[msg.sender].username;
    }
}

Can you figure out what is causing the code to stop here?
const tx = await userAuthContract.register(username);

The last thing that happens is select yes in this if.
if (confirm('You are about to create a new account. Is this what you would like?')) {

Chrome.tabgroup title returns “undefined” on first page load

Goal

  1. Query the DOM for workspaceName via contentscript
  2. Send workspaceNamevia Sendmessage from contentscript.js to popup.js
  3. Click button to create tabgroup and Populate tabgroup title with workspaceName

Expected behaviour

For the queried workspaceName to successfully populate in tabGroup title when tabgroup is created

Current behaviour

On first page load, the sendmessage event does not send (I can observe this in the console) and when I click button to create tabgroup the title is populated with undefined

Set-up

HTML

<button id="createTab">Click me</button>

Contentscript.js – I have to use MutationObserver as target element loads pretty late

let workspaceName;

const target = '.db-space';

const observer = new MutationObserver((mutationsList, observer) => {
    if (document.querySelector(target)) {
        let name = getWorkspaceDetails();
        observer.disconnect();
        chrome.runtime.sendMessage(null, name); // heres where I send the name
    }
});

observer.observe(document.body, { childList: true, subtree: true });

function getWorkspaceDetails() {
    workspaceName = document.querySelector(target);
    console.log(workspaceName.textContent);
    return workspaceName.textContent;
}

// Initial check in case the element is already present
if (document.querySelector(target)) {
    getWorkspaceDetails();
    observer.disconnect();
}

Popup.js

const createBtn = document.queryselector('#createTab');
createBtn.addEventListener('click', createTabs)
let workspaceName;

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
    workspaceName = msg;
    console.log(`Workpspace: ${msg}`);
});

function createTabs() {
    chrome.tabs.query({ active: true, lastFocusedWindow: true }, async (tabs) => {
        await chrome.tabs
            .create({ url: `https://example1.com`, active: false })
            .then((tab) => tabsToGroup.push(tab.id));

        await chrome.tabs
            .create({ url: `https://example2.com`, active: false })
            .then((tab) => tabsToGroup.push(tab.id));

        await chrome.tabGroups.update(groupId, {
            collapsed: true,
            title: `${workspaceName}`,
            color: 'red'
        });
    });
}

Below is how the tab group looks on the first run. After a few pages refreshes it begins to populate

tabgroup showing undefined

How to authenticate with Anypoint Mulesoft API and retrieve a token with react

I am trying to retrieve a token from Anypoint Mulesoft API, but I am not sure which link to use,I have used both links and they are not working.

The info provided was:
Client ID
Client Secret
Grant Types

Redirect URLS :
https://api-notebook.anypoint.mulesoft.com/authenticate/oauth.html, https://anypoint.mulesoft.com/exchange/oauthCallback.html

Frontend

useEffect(() => {
    getToken();
  }, []); // <- add empty brackets here. Runs only on the first render

  const bodyConfig = {
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    grant_type: process.env.GRANT_TYPE,
  };


  async function getToken() {
    try {
      const response = await fetch(
        "https://api-notebook.anypoint.mulesoft.com/authenticate/oauth.html",
        {
          method: "POST",
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
          },
          body: JSON.stringify(bodyConfig),
        }
      );
      if (!response) {
        throw new Error("Authentication failed");
      }
      const result = await response.json();
      console.log(result.token);
    } catch (error) {
      console.log(error);
    }

I tried both URLS for the POST

https://api-notebook.anypoint.mulesoft.com/authenticate/oauth.html, https://anypoint.mulesoft.com/exchange/oauthCallback.html

I tried to use
fetch and axios

 async function getToken() {
    axios
      .post(
        "https://api-notebook.anypoint.mulesoft.com/authenticate/oauth.html",
        {
          client_id: process.env.NZ_POST_CLIENT_ID,
          client_secret: process.env.NZ_POST_CLIENT_SECRET,
          grant_type: process.env.NZ_POST_GRANT_TYPE,
        }
      )
      .then((response) => {
        console.log(response.token);
      })
      .catch((error) => {
        console.log("something went wrong :(");
        console.log(error);
      });
  }

D3 Circle Packing with Zooming Consistent End Node Size

I’m building a hierarchical data visualization using D3’s circle packing. The library arranges the nodes well, but I’m having trouble with zooming. Specifically, the leaf nodes (circles without children) appear too small when zoomed out and too large when zoomed in. I want these leaf nodes to remain a consistent size on the screen, regardless of the zoom level.

import { Component, OnInit, ElementRef, Input } from '@angular/core';
import * as d3 from 'd3';

@Component({
  selector: 'app-circle-view',
  templateUrl: './circle-view.component.html',
  styleUrls: ['./circle-view.component.css']
})
export class CircleViewComponent implements OnInit {
  @Input() canvas: number = 0;

  constructor(private elRef: ElementRef) {}

  ngOnInit(): void {
    this.createVisualization();
  }

  private createVisualization(): void {
    const width = this.canvas;
    const height = this.canvas;

    const canvas = d3.select(this.elRef.nativeElement.querySelector('svg'))
      .attr("viewBox", `-${width / 2} -${height / 2} ${width} ${height}`)
      .attr("width", width)
      .attr("height", height);

    const pack = d3.pack().size([width, height]).padding(3);
    const root = pack(d3.hierarchy(this.buildHierarchy()).sum(() => 1));

    const node = canvas.append("g")
      .selectAll("circle")
      .data(root.descendants())
      .join("circle")
      .attr("fill", d => d.children ? 'rgba(0, 174, 207, 0.4)' : 'rgb(107, 209, 112)')
      .on('click', (event, d) => {
        zoom(event, d);
        event.stopPropagation();
      });

    canvas.on("click", (event) => zoom(event, root));
    let view: [number, number, number];
    zoomTo([root.x, root.y, root.r * 2]);

    function zoomTo(v: [number, number, number]) {
      const k = width / v[2];
      view = v;
      node.attr("transform", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`)
          .attr("r", d => d.r * k);
    }

    function zoom(event: any, d: d3.HierarchyCircularNode<any>) {
      const transition = canvas.transition()
        .duration(750)
        .tween("zoom", () => {
          const i = d3.interpolateZoom(view, [d.x, d.y, d.r * 2]);
          return t => zoomTo(i(t));
        });
    }
  }

  private buildHierarchy() {
    // Sample hierarchical data structure
    return {
      id: 1,
      name: 'Root Circle',
      children: [
        { id: 2, name: 'Circle 1', children: [{ id: 3, name: 'Circle 1.1' }] },
        { id: 4, name: 'Circle 2' }
      ]
    };
  }
}

I’ve tried assigning size values directly to the data in an attempt to control the node sizes, but this didn’t give me the desired result because the size values aren’t directly linked to the radius of the circles.

const root = d3.hierarchy(data)
  .sum(function(d) { return d.value || 0; });

Please help me I’m only a student. Nobody taught me D3 ):

react-map-gl Popup above polygon – Invalid LngLat object: (NaN, NaN)

I have an interactive Mapbox map using react-map-gl. It is displaying a GEOJSON with polygons and I would like to show a popup on hover at the center of the polygon. Each feature has a “properties” of “center” which contains the center coordinates of the polygon.

This is a sample of the GEOJSON:


{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            -73.971451,
                            40.757749
                        ],
                        [
                            -73.970993,
                            40.758373
                        ],
                        [
                            -73.972613,
                            40.759059
                        ],
                        [
                            -73.973068,
                            40.758432
                        ]
                    ]
                ]
            },
            "properties": {
                "center": [
                    -73.97203144204987,
                    40.75840349835226
                ]
            }
        },

This is a sample of what my code looks like:

import React, { useState, useCallback } from 'react';
import Map, { Source, Layer, Popup } from 'react-map-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

import SAMPLE_DATA from '../assets/sample.geojson';

// ...

const BgMap = ({ showLayer }) => {
    const [hoverPopupInfo, setHoverPopupInfo] = useState(null);

    const handleMouseEnter = useCallback((event) => {
        const { features } = event;
        if (features.length > 0) {
            const feature = features[0];
            const center = feature.properties.center;
            setHoverPopupInfo({ center });
        }
    });

    return (
        <div className="map-container">
            <Map
                // ...
                interactiveLayerIds={['aggregated-layer']}
                onMouseEnter={handleMouseEnter}
            >
                <Source id="aggregated-data" type="geojson" data={AGGREGATED_DATA}>
                    <Layer
                        id="aggregated-layer"
                        type="fill"
                        paint={{
                            'fill-color': '#fff',
                        }}
                    />
                </Source>
                {hoverPopupInfo && (
                    <Popup
                        latitude={hoverPopupInfo.center[1]}
                        longitude={hoverPopupInfo.center[0]}
                        closeButton={false}
                        anchor="bottom"
                    >
                        <div>This is a popup</div>
                    </Popup>
                )}

            </Map>
        </div>
    );
};

But I get an error like this:

Invalid LngLat object: (NaN, NaN)

React app still stuck on loading page despite having an active session on my local Keycloak server

I am developing a react app locally and using Keycloak to manage authentication. I used the keycloak.js package and the react-keycloak package to access the Keycloak server from the react app.

When the user isn’t logged in, the only accessible routes should be “/” and “/login”. The “/” route renders a landing page whilst the “/login” route redirects to the Keycloak login page. These routes are stored in the PublicView object.

If the user is logged in more routes should be accessible, such as “/collections”. For example, after log the user should be redirected to the “/” route, which then redirects to the “/collections” page instead of rendering the landing page.

Currently the react app functions as described for when the user isn’t logged in. Additionally, after login the user is properly redirected to the “/” route which then redirects to the “/collections” route and displays the relevant content.

However if I manually type any PrivateView route into the browser (i.e reload the single page app) it just shows the “authorising…” loading message. What it should be doing is serving the URI according to the PrivateView object.

Although this suggest that the client hasn’t been initialised yet, I know that the authentication must have succeeded since the line {console.log("rendering:", isAuth)}, in the return statement of the app, executes properly:
[console after accessing any URI whilst being logged in]
However as seen in the image, a 404 error is thrown as if the page for the URI couldn’t be found. I have traced the 404 error back to the <NotFound errorMessage={new Error("404 not found")}/> component in the SharedView object. This is unexpected since all of the routes I am reloading/accessing are specified in the PrivateView object.

Does anyone have ideas how I could correct this behaviour?

Below is all the relevant code:

App.js:

import { Routes, Route, Navigate } from "react-router-dom"
import { useKeycloak } from "@react-keycloak/web"

// Components
import PrimaryLayout from "./components/layouts/PrimaryLayout"

// Pages
import About from "./pages/About/index"
import Collections from "./pages/Collections/index"
import Artworks from "./pages/Artworks/index"
import ArtworkPopup from "./pages/ArtworkPopup"
import Contact from "./pages/Contact/index"
import Login from "./pages/Login/index"
import Logout from "./pages/Logout/index"
import Landing from "./pages/Landing/index"
import NotFound from "./pages/NotFound/index"
import Tests from "./pages/__tests__/index"

// Styles
import './global.css'

function App() {
    const { keycloak, initialized } = useKeycloak()
    const isAuth = keycloak.authenticated

    const PrivateView = (
        <>
            <Route element={ <PrimaryLayout /> } >
                <Route path="about" element={ <About /> } />

                <Route path="collections" >
                    <Route index element={ <Collections /> } />
                    <Route path=":collectionId" element={ <Navigate replace to="a" /> } />

                    <Route path=":collectionId/a" element={ <Artworks /> } >
                    <Route path=":artworkId" element={ <ArtworkPopup />} />
                    </Route>
                </Route>

                <Route path="contact" element={ <Contact /> } />
                <Route path="logout" element={ <Logout /> } />
            </Route>

            <Route path="/" element={ <Navigate replace to="collections" /> } />
        </> 
    )

    const PublicView = (
        <>
            <Route path="/" element={ <Landing /> } />
            <Route path="login" element={ <Login /> } />
        </>
    )

    const SharedView = (
        <>
            <Route path="tests" element={ <Tests /> } />
            <Route path="*" element={ <NotFound errorMessage={new Error("404 not found")}/> } />
        </>
    )

    if (!initialized) {
        console.log("Still loading")
        return <div>Authenticating...</div>
    }

    return (
        <Routes>
            {console.log("rendering:", isAuth)}
            {isAuth ? PrivateView : PublicView}
            {SharedView}
        </Routes>
    )
}

export default App

Login.js:

import { useKeycloak } from "@react-keycloak/web"
import keycloakLogin from "../../data/keycloakLogin"

function Login() {
    const { keycloak } = useKeycloak()

    keycloak.login({redirectUri: "http://localhost:3001/")

    return (
        <main className="main">
            <div className="page-description">
                <h1 className="page-description__name">Login</h1>
            </div>
            <div>Redirecting to login...</div>
        </main>
    )
}

export default Login

index.js:

import React from "react"
import ReactDOM from 'react-dom/client'
import { ReactKeycloakProvider } from "@react-keycloak/web"
import { BrowserRouter } from "react-router-dom"
import './index.css'

// APP
import App from './App'

// Config
import keycloakClient from "./data/keycloakClient"
import keycloakInit from "./data/keycloakInit"

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(

    /* IMPORTANT

    I wrapped the ReactKeycloakProvider around the React.StrictMode component to prevent double initialisation of the Keycloak client.

    */
    <ReactKeycloakProvider authClient={keycloakClient} initOptions={
        onLoad: 'check-sso',
        silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
        pkceMethod: "S256"
    }>
        <React.StrictMode>
            <BrowserRouter>
                <App />
            </BrowserRouter>
        </React.StrictMode>
    </ReactKeycloakProvider>
);

Map.set really really slow

Map.set is really slow for me. Taking 14.677 seconds to set 300-400 items. I’m using Chrome for testing.

I’ve created a custom Map object:

export class DataMap<T> extends Map<string, T> {
  constructor(...args:MapConstructorParameters){
    super(...(args as []))
  }
  updateFromList(values:any[], {key='id', sortKey=null} : UpdateFromListOptions){
    // const self = this;

    let _values:any[];
    if (sortKey){
      console.log('Sorting')
      _values = this._sortValues(values, sortKey) // implementation not shown for brevity
      console.log('Sorting Finished')
    } else {
      _values = []
    }

    console.log('Setting')
    _values.forEach((_:any)=>{
      this.set(_[key], _ as T)
    })
    console.log('Setting finished')

  }
}

The idea of updateFromList is a little bit of syntax sugar, to allow passing of a list of objects and append them by a ‘key’ to the map. The part that is really slow is this:

    console.log('Setting')
    _values.forEach((_:any)=>{
      this.set(_[key], _ as T)
    })
    console.log('Setting finished')

Is this use of the Map a no go or am doing something stupid here?