Am getting “Cannot set property .. which has only a getter” error (javascript canvas width)

More completely, I got:
“Cannot set property clientWidth of #<Element> which has only a getter”
(Obviously I could have had a HTML <canvas> element, but this is a minimized example of my problem.)

But I found a solution: Instead of creating elements and appending, write a string of the HTML I want and use innerHTML = string. Is there a disadvantage in doing this?
Change ‘true’ to ‘false’ in the code to demo the solution:

<html>
  <head>
    <meta charset="utf-8">
    <style>
canvas { outline:1px dotted black; } 
    </style>
  </head>
  <body>
    <script>
  "use strict";
  if (true) { // this code has the error
    let elt = document.createElement('canvas');
    elt.setAttribute('id','canvas');
    elt.clientWidth = 500;
    elt.clientHeight = 500;
    document.body.appendChild(elt);
  } else {    // this has the workaround/solution
    let s = '<canvas id="canvas" width="500" height="500"></canvas>';
    document.body.innerHTML = s;
  }
  let ctx = canvas.getContext("2d");
  ctx.arc(250,250,200, 0, 6.2832);
  ctx.stroke();
    </script>
  </body>
</html>

How to send this data to Database using Express and MongoDB and React Native ? Issue with Sending Data to Backend Endpoint in React Native

I’m encountering an issue with sending data from my React Native frontend to a backend endpoint. I’ve provided the relevant code snippets below.I’m encountering an issue with sending data from my React Native frontend to a backend endpoint (/onboarding/v3). Below, I’ve provided relevant code snippets and additional details about my setup.

enter image description here

User Model:

I’m using a MongoDB database with Mongoose to define my user schema. The schema includes fields for name, email, password, and various other user details. Of particular relevance to this issue is the areasOfInterest field, which is an array of objects containing title and items properties.

I have a React Native component AreasOfInterest where users select their areas of interest and rate their expertise. Upon pressing a “Next” button, I want to send this data to the backend.

I would appreciate any guidance on how to properly format the data and resolve the issue with sending it to the backend endpoint. I’ve included relevant code snippets below for reference.

Backend Endpoint:

I have a backend endpoint /onboarding/v3

Please fix my code
My User Model is below. after it

const mongoose = require("mongoose");

// Define schema for items within an area of interest
const InterestItemSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  stars: {
    type: Number,
    min: 1,
    max: 5,
    default: 1, // Default to 1 star
  },
});

// Define schema for areas of interest
const InterestSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  items: {
    type: [InterestItemSchema],
    default: [],
  },
});

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  email: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
  },
  image: {
    type: String,
    required: true,
  },
  friendRequests: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
  ],
  friends: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
  ],
  sentFriendRequests: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
  ],
  First_Name: {
    type: String,
    default: "",
  },
  Last_Name: {
    type: String,
    default: "",
  },
  Pronoun: {
    type: String,
    default: "",
  },
  Gender: {
    type: String,
    default: "",
  },
  Race: {
    type: String,
    default: "",
  },
  Country: {
    type: String,
    default: "",
  },
  State: {
    type: String,
    default: "",
  },
  City: {
    type: String,
    default: "",
  },
  Role: {
    type: String,
    default: "",
  },
  Student: {
    type: Boolean,
    default: false,
  },
  Mentor: {
    type: Boolean,
    default: false,
  },
  Affiliation: {
    type: String,
    default: "",
  },
  Headline: {
    type: String,
    default: "",
  },
  Education: {
    type: String,
    default: "",
  },
  Major: {
    type: String,
    default: "",
  },
  Degree: {
    type: String,
    default: "",
  },
  GradeYear: {
    type: String,
    default: "",
  },
  areasOfInterest: {
    type: [InterestSchema],
    default: [],
  },
  Career_Goals: {
    type: [String],
    default: [],
  },
  withOrgOnly: {
    type: Boolean,
    default: false,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
  updatedAt: {
    type: Date,
    default: Date.now,
  },
});

const User = mongoose.model("User", userSchema);

module.exports = User;

// Backend Endpoint (Working (not sure about onboarding/v3) )

const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const os = require("os");
const app = express();
const morgan = require("morgan");
const port = 8080;
const cors = require("cors");
const router = express.Router();

app.use(morgan("dev"));
app.use(cors());

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(passport.initialize());
const jwt = require("jsonwebtoken");

const User = require("./models/user");

// POST endpoint for onboarding/v3
app.post("/onboarding/v3", async (req, res) => {
  try {
    const { userId, areasOfInterest } = req.body;

    const user = await User.findById(userId);
    console.log(user.name);
    console.log(areasOfInterest);
    if (!user) {
      return res.status(404).json({ message: "User not found" });
    }

    user.areasOfInterest = areasOfInterest;

    await user.save();

    res.status(200).json({ message: "Areas of interest updated successfully" });
  } catch (err) {
    console.log("Error updating areas of interest", err);
    res.status(500).json({ message: "Error updating areas of interest" });
  }
});

// Frontend Main Page.

import React, { useState, useContext } from "react";
import {
  View,
  Text,
  SafeAreaView,
  TextInput,
  TouchableOpacity,
  FlatList,
} from "react-native";
import Icon from "react-native-vector-icons/FontAwesome5";
import { CheckBox } from "react-native-elements";
import { AntDesign } from "@expo/vector-icons";
import axios from "axios";
import { UserType } from "../../UserContext";

const NavigationLine = ({ active }) => (
  <View
    style={{
      flex: 1,
      height: 5,
      backgroundColor: active ? "#57D5DB" : "#DBD4D4",
      marginHorizontal: 5,
    }}
  />
);

const InterestList = ({ data }) => {
  const [expanded, setExpanded] = useState(false);
  const [ratings, setRatings] = useState(Array(data.items.length).fill(0));
  const [selectedItems, setSelectedItems] = useState(
    Array(data.items.length).fill(false)
  );

  const handleRatingChange = (index, rating) => {
    const newRatings = [...ratings];
    newRatings[index] = rating;
    setRatings(newRatings);
  };

  const toggleCheckbox = (index) => {
    const newSelectedItems = [...selectedItems];
    newSelectedItems[index] = !selectedItems[index];
    setSelectedItems(newSelectedItems);
    // Reset rating to 0 when unchecking the checkbox
    if (!newSelectedItems[index]) {
      handleRatingChange(index, 0);
    }
  };
  return (
    <View>
      <TouchableOpacity
        onPress={() => setExpanded(!expanded)}
        style={{
          flexDirection: "row",
          alignItems: "center",
          backgroundColor: "#F1F1F3",
          width: "90%",
          height: 50,
          borderRadius: 20,
          marginTop: 15,
          paddingHorizontal: 20,
          borderColor: "#D9D9D9",
          borderWidth: 1,
          marginHorizontal: 15,
        }}
      >
        <Icon
          name={expanded ? "caret-down" : "caret-right"}
          size={15}
          color="#9C9C9C"
        />
        <Text style={{ flex: 1, marginLeft: 10 }}>{data.title}</Text>
      </TouchableOpacity>
      {expanded && (
        <FlatList
          data={data.items}
          keyExtractor={(item, index) => index.toString()}
          renderItem={({ item, index }) => (
            <View
              style={{
                flexDirection: "row",
                alignItems: "center",
                backgroundColor: "#F1F1F3",
                width: "90%",
                height: 50,
                borderRadius: 20,
                marginTop: 5,
                marginHorizontal: 15,
                borderWidth: 0.1,
              }}
            >
              <TouchableOpacity
                onPress={() => toggleCheckbox(index)}
                style={{ marginLeft: 20, marginRight: 10 }}
              >
                <Icon
                  name={selectedItems[index] ? "check-square" : "square"}
                  size={20}
                  color="#000"
                />
              </TouchableOpacity>
              <View style={{ flex: 1 }}>
                <Text style={{ fontSize: 13 }}>{item}</Text>
              </View>
              {selectedItems[index] && ( // Show stars only if checkbox is selected
                <View style={{ flexDirection: "row", marginRight: 20 }}>
                  {[1, 2, 3, 4, 5].map((star) => (
                    <TouchableOpacity
                      key={star}
                      onPress={() => handleRatingChange(index, star)}
                      style={{ marginRight: 4 }}
                    >
                      <AntDesign
                        name="star"
                        size={20}
                        color={ratings[index] >= star ? "#FFD700" : "#D3D3D3"}
                      />
                    </TouchableOpacity>
                  ))}
                </View>
              )}
            </View>
          )}
        />
      )}
    </View>
  );
};

const AreasOfInterest = ({ navigation }) => {
  // Use userId to send backend
  const { userId, setUserId } = useContext(UserType);
  const interestData = [
    {
      title: "Accounting",
      items: [
        "Financial Accounting",
        "Cost Accounting",
        "Managerial Accounting",
        "Auditing",
        "Tax Accounting",
        "Forensic Accounting",
      ],
    },
    {
      title: "Finance",
      items: [
        "Investment Management",
        "Financial Risk Management",
        "Corporate Finance",
        "Public Finance",
        "Personal Finance",
      ],
    },
    {
      title: "Human Resources",
      items: [
        "Learning & Development",
        "Performance Management",
        "HR Information Systems",
        "Compensation & Benefits",
        "Recruiting & Staffing",
        "Organizational Structure",
        "Employee & Labor Relations",
        "Diversity Equity & Inclusion",
      ],
    },
    {
      title: "Information Technology",
      items: [
        "Systems Security",
        "Data Management",
        "IT Management",
        "Network Administration",
        "Software Development",
        "Web Development",
      ],
    },
    {
      title: "Legal",
      items: [
        "Litigation",
        "Risk Management",
        "Contract Law",
        "Import/Export Law",
        "Compliance Policies & Procedures",
        "Property Law",
        "Intellectual Property Law",
        "Employment Law",
        "Ethics",
        "Law Enforcement",
        "Criminal Justice",
      ],
    },
    {
      title: "Manufacturing",
      items: [
        "Plant Management",
        "Fabrication & Machining",
        "Reliability & Asset Management",
        "Procurement",
        "Distribution",
        "Production Installation",
      ],
    },
    {
      title: "Operations",
      items: [
        "Improve Processes",
        "LEAN & Six Sigma",
        "Production Planning & Control",
        "Quality Management",
        "Supply Chain Management",
        "Design Process",
      ],
    },
    {
      title: "Marketing & Communication",
      items: [
        "Sales Support",
        "Marketing Communications",
        "Advertising Strategy",
        "Pricing Strategy",
        "Market Research",
        "Social Media Strategy",
        "Brand Management",
        "Copy & Content Creation",
        "Imaging/Graphics",
      ],
    },
    {
      title: "Sales",
      items: [
        "Capture Management",
        "Building a Book of Business",
        "Channel Strategy",
        "Sales Forecasting",
        "Enterprise Sales",
        "Inside Sales",
        "Objection Handling",
        "Business Development",
      ],
    },
    {
      title: "Management",
      items: [
        "Delegation",
        "Emotional Intelligence",
        "Improve Processes",
        "Product Management",
        "Project Management",
        "Decision Making",
        "Negotiation Skills",
        "Develop Others",
        "Change Management",
        "Priority Management",
        "Effective Communication",
        "Conflict Management",
      ],
    },
    {
      title: "Leadership",
      items: [
        "Team Building",
        "Shaping Culture",
        "Setting Vision & Strategy",
        "Strategic Thinking",
        "Product Development",
        "Service Development",
        "Value Creation",
      ],
    },
    {
      title: "Healthcare",
      items: [
        "Dentistry",
        "Health Sciences",
        "Physician",
        "Veterinarian",
        "Pharmacist",
        "Healthcare Management",
        "Patient Care",
      ],
    },
    {
      title: "Education",
      items: [
        "Teaching",
        "Education Administration",
        "School Counseling",
        "Curriculum Development",
      ],
    },
    {
      title: "Consulting",
      items: [
        "Management Consulting",
        "Corporate Consulting",
        "Independent Consulting",
      ],
    },
    {
      title: "Government & Public Administration",
      items: [
        "Revenue & Taxation",
        "Law Enforcement",
        "Public Management & Administration",
        "Environmental & Resource Planning",
        "National Security",
        "Governance",
      ],
    },
    {
      title: "Customer Service",
      items: [
        "Customer Retention",
        "Customer Management",
        "Customer Support",
        "SaaS Customer Experience",
      ],
    },
    {
      title: "Engineering",
      items: [
        "Civil Engineering",
        "Chemical Engineering",
        "Mechanical Engineering",
        "Electrical Engineering",
        "Industrial Engineering",
        "Aerospace Engineering",
        "Biomedical Engineering",
        "Environmental Engineering",
        "Computer Engineering",
        "Materials/Textiles Engineering",
        "Nuclear Engineering",
        "Architecture",
      ],
    },
    {
      title: "Sciences",
      items: [
        "Agricultural Science",
        "Social Science",
        "Biology",
        "Chemistry",
        "Political Science",
        "Physics",
        "Psychology",
        "Mining & Petroleum",
      ],
    },
    {
      title: "Social Services",
      items: [
        "Therapists",
        "Probation Officer",
        "Rehabilitation Counselor",
        "Career Counselor",
        "Social Worker",
        "Substance Abuse Counselor",
        "Mental Health Counselor",
        "Clergy",
      ],
    },
    {
      title: "Creative / Design",
      items: [
        "Creative Arts",
        "Graphic Design",
        "Interior Design",
        "Product Design",
        "User Experience",
      ],
    },
  ];

  const [initialInterestData, setInitialInterestData] = useState([]);
  // Search Logic
  // TODO: Later Search Logic
  // Handle Next
  const handleNext = async () => {
    try {
      // Construct the data object to send
      const dataToSend = initialInterestData.map((interest) => ({
        title: interest.title,
        selectedItems: interest.items
          .filter((item, index) => selectedItems[index])
          .map((item, index) => ({
            name: item,
            rating: ratings[index],
          })),
      }));
      console.log(dataToSend);
      // Make the HTTP request to the backend API
      const response = await axios.post(
        "http://172.20.10.3:8080/onboarding/v3",
        dataToSend
      );

      // Handle response as needed (e.g., show success message, navigate to next screen)
      console.log("Response from backend:", response.data);
      navigation.navigate("Career"); // Navigate to the next screen
    } catch (error) {
      // Handle error (e.g., show error message)
      console.error("Error sending data to backend:", error);
    }
  };

  return (
    // Margin Top is missing in this. i want same level of margin as my previous pages.
    <SafeAreaView style={{ flex: 1, alignItems: "center", marginTop: 40 }}>
      <TouchableOpacity
        onPress={() => {
          navigation.goBack();
        }}
        style={{
          position: "absolute",
          top: 3,
          left: 20,
          justifyContent: "center",
          alignItems: "center",
          flexDirection: "row",
        }}
      >
        <Icon name="chevron-left" size={24} color="#000" />
      </TouchableOpacity>
      <Text style={{ fontWeight: "bold", fontSize: 20, marginBottom: 5 }}>
        Areas of Interest
      </Text>
      <View style={{ width: 400, height: 1.5, backgroundColor: "#DBD4D4" }} />

      <FlatList
        data={interestData}
        keyExtractor={(item, index) => index.toString()}
        renderItem={({ item }) => <InterestList data={item} />}
        ListHeaderComponent={() => (
          <>
            <Text
              style={{ fontSize: 17, marginTop: 10, paddingHorizontal: 15 }}
            >
              Select areas of interest and rate your expertise in each to
              receive personalized mentoring recommendations. Rate your
              expertise with the star system (1 - 5) to establish your
              proficiency.
            </Text>
            <Text
              style={{
                fontSize: 11,
                color: "#9C9C9C",
                textAlign: "left",
                marginTop: 10,
                paddingHorizontal: 15,
              }}
            >
              Your ratings are confidential and not displayed on your profile.
              We recommend selecting at least 3 options.
            </Text>

            <View
              style={{
                flexDirection: "row",
                alignItems: "center",
                backgroundColor: "#F1F1F3",
                width: "90%",
                height: 50,
                borderRadius: 20,
                marginTop: 15,
                paddingHorizontal: 20,
                borderColor: "#D9D9D9",
                borderWidth: 1,
                marginHorizontal: 15,
              }}
            >
              <Icon name="search" size={15} color="#9C9C9C" />
              <TextInput
                placeholder="Search Here"
                style={{ flex: 1, marginLeft: 10 }}
              />
            </View>
          </>
        )}
      />
      <View style={{ flexDirection: "row", height: 10, marginVertical: 10 }}>
        <NavigationLine active={true} />
        <NavigationLine active={true} />
        <NavigationLine active={true} />
        <NavigationLine active={false} />
        <NavigationLine active={false} />
      </View>
      <TouchableOpacity
        onPress={handleNext}
        style={{
          backgroundColor: "#09A1F6",
          padding: 10,
          borderRadius: 30,
          width: "90%",
          height: 50,
          justifyContent: "center",
          alignItems: "center",
          marginBottom: 10,
        }}
      >
        <Text style={{ color: "#fff", fontSize: 24, fontWeight: "bold" }}>
          Next
        </Text>
      </TouchableOpacity>
    </SafeAreaView>
  );
};

export default AreasOfInterest;

Trying to use swiper js with npm but I can not( Pure JS

I want to use swiper js for my project and I want to install it using npm. Many times there were errors with the installation, but after fixing the errors there were no errors, but the slider did not work. Before this I installed it using a cdn file and everything worked, but I want to use npm. Help please, I’ve been sitting all day trying to do this.

Here’s my code:

import Swiper from "swiper";
import "../node_modules/swiper/swiper.css";
import "../node_modules/swiper/modules/navigation.css";
import { Navigation } from "swiper/modules";
const controlMain = async function () {
  await model.setDefault();
  document.querySelector(".main-spinner").classList.add("active");

  const topAuthorsMarkup = `
  <section class="top-authors">
  <h2 class="heading-secondary">Top authors</h2>
  <!-- Список слайдов -->
  <div class="swiper top-authors__list">
    <div class="swiper-wrapper">
      ${model.state.default.topAuthorsNames
        .map((authorName, i) => {
          return `
        <div class="swiper-slide top-authors__item">
          <figure class="top-authors__author">
            <img class="top-authors__img"
                 src="${model.state.default.topAuthorsImgs[i]}"
                 alt="${authorName} image" />
            <figcaption class="top-authors__description">
              <h3 class="top-authors__name">${authorName}</h3>
              <p class="top-authors__text">
                ${model.state.default.topAuthorsDescription[i]}
              </p>
            </figcaption>
            <a class="top-authors__link" href="#"></a>
          </figure>
        </div>
      `;
        })
        .join("")}
    </div>
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
  </div>
</section>
`

Here’s video

I want to make an exstntion that will paste text from a random list. but i cant get it to work

i cant seem to get the text to acctally paste into any text box or doc
i have tiend a lot of diffrent things but nothing seems to be working.
if there is something im missing im not sure.
is there a way to do so?
could i get some help?

manifest.json

{
    "manifest_version": 3,
    "name": "Random Word Inserter",
    "version": "1.0",
    "description": "Inserts a randomly chosen word into text boxes when the tab key is pressed.",
    "permissions": ["activeTab"],
    "background": {
      "service_worker": "background.js"
    },
    "action": {
      "default_popup": "popup.html",
      "default_icon": {
        "16": "icon.png",
        "48": "icon.png",
        "128": "icon.png"
      }
    },
    "content_scripts": [
      {
        "matches": ["<all_urls>"],
        "js": ["content.js"]
      }
    ]
  }
  

Contents.js

const words = ["apple", "banana", "orange", "grape", "pineapple"];

document.addEventListener("keydown", function (event) {
  if (event.key === "Tab") {
    const inputFields = document.querySelectorAll("input[type='text']");
    inputFields.forEach(function (input) {
      const randomIndex = Math.floor(Math.random() * words.length);
      const randomWord = words[randomIndex];
      input.value += randomWord;
    });
  }
});

popup.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Random Word Inserter Settings</title>
</head>
<body>
  <h1>Random Word Inserter Settings</h1>
  <p>No settings available yet.</p>
</body>
</html>

Issue with Animated Counter Functionality on Mobile Devices

I’m encountering an issue with an animated counter on my website. The counter is intended to simulate a statistic and works perfectly on desktop browsers. However, when accessed on mobile devices in a production environment, there seems to be a problem with parsing or conversion that resets any number above 999, consequently resetting the initial number.

Here’s the relevant HTML code snippet:

<span id="counter">4898988</span><br />

Here’s the relevant JavaScript code snippet:

document.addEventListener('DOMContentLoaded', (event) => {
  const counterElement = document.getElementById('counter');
  console.log('counterElement:', counterElement); // log the counterElement
  counterElement.textContent = `${parseInt(counterElement.textContent, 10).toLocaleString()} USD`; // format the initial number
  console.log('counterElement.textContent after formatting:', counterElement.textContent); // log the textContent after formatting
  animateCount(counterElement);
  
  // Animate the counter
  function animateCount(targetElement) {
    console.log('targetElement in animateCount:', targetElement); // log the targetElement in animateCount
    let count = parseInt(targetElement.textContent.replace(/,/g, ''), 10);
    console.log('count after parsing:', count); // log the count after parsing
    const finalCount = count + Math.floor(Math.random() * 31); // generate a random number between 0 and 30
    const interval = setInterval(() => {
      if (count < finalCount) {
        count++;
        targetElement.textContent = `${count.toLocaleString()} USD`;
      } else {
        clearInterval(interval);
        setTimeout(() => animateCount(targetElement), Math.random() * 9000 + 5000); // wait for a random period between 5 and 14 seconds before starting the next cycle
      }
    }, 100);
  }
});

Console log:

[Log] counterElement:
<span id="counter">4 898 988 USD</span>
[Log] after formatting: – "4 898 988 USD"
[Log] animateCount: 
<span id="counter">4 898 988 USD</span>
[Log] count after parsing: – 4 

As you can see, the ‘let count =’ line seems to not parse correctly a number above 999.

How to include external css in Svelte Custom Element?

I’m new to Svelte and I’m trying to create a custom element that relies on font-awesome fonts. However, when I build the component and try to use it — none of my styling (including the font-awesome css) gets applied.

I really don’t want the user of my element to have to include font-awesome on their own — I want it to just be included as part of my custom element.

Just curious what I need to do to get this to work?

Here’s what I have:

App.js

<svelte:options customElement="my-custom-element"></svelte:options> 

<script>
   export let overrideCss = null;  //Give user of element chance to override css
   ...
</script>

<!-- Css below is applied when running dev server, but doesn't get applied after build -->
<link rel="stylesheet" href="/src/app.css">
<link href="./../node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet"> 
{#if overrideCss}
    <link rel="stylesheet" href={overrideCss}/>
{/if}

<div id="my-app-container">
  ...
  <i class="fas fa-thumbs-{approved ? 'up' : 'down'}"></i>
</div>

Vanilla JavaScript to show scroll progress bar that fills only while scrolling the element?

I’m trying to create a scroll progress bar that fills from 0-100% when scrolling the element only, but i can’t get it to work. I’ve got it working to show the whole page scrolling progress when scrolling the element, but I need it to only show 0-100% on the element, and only while that element is being scrolled. I also need to create it using vanilla javascript.

Here’s what i have that isn’t working:

HTML

<body>
    <header>
        <section>
        </section>
    </header>
    <nav>
        <div class="nav"></div>
        <div class="scroll">
                <div class="scroll-bar" id="scroll-progress"></div>
        </div>
    </nav>
    <main>
        <section>
            <p>some content</p>
        </section>
        <section>
            <p>some content</p>
        </section>
    </main>
    <section>
        <p>some content</p>
    </section>
    <section>
        <p>some content</p>
    </section>
    
</body>

CSS

.nav {
    background-color: black;
    height:50px;
}
section {
    height: 400px;
}

.scroll {
    width: 100%;
    height: 4px;
    background-color: lightgray;
}

#scroll-progress {
    width: 0%;
    height: 4px;
    background-color: green;
}

JS

const main = document.querySelector('main');
const progress = () => {
    const scroll = main.scrollTop;
    const height = main.scrollHeight - main.clientHeight;
    const scrollProgress = (scroll / height) * 100;
    document.getElementById('scroll-progress').style.width = scrollProgress + "%";
}

window.addEventListener('scroll', progress);

This, however, works as expected, but shows the progress through the whole page, while scrolling the element, I’m just not sure how to get from this to what i need.

const main = document.querySelector('main');
const progress = () => {
    let scroll = document.documentElement.scrollTop;
    let height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
    let scrollProgress = (scroll / height) * 100;
    document.getElementById("scroll-progress").style.width = scrollProgress + "%";
}

window.addEventListener('scroll', progress);

Any help greatly appreciated

How do I fix the following issues with my port of a manifest v2 browser extension to manifest v3?

I am in the process of transitioning a manifest v2 Chrome extension to manifest v3 and while converting my background script background.js to a service worker, and I am getting error messages in Google Chrome. I am somewhat familiar with Manifest v3, however the concept of service workers is still very confusing to me. Here is the error message. Note: Keep in mind, despite the single error message, I believe there may be some logical errors rather than syntax errors in my source code that may present undesired or unexpected behavior in the browser extension.

Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.

To put this error into context, I have included the code of my service worker called service-worker.js, content-script.js, and manifest.json. I think I did most of the “heavy lifting” porting my MV2 extension to MV3, but there seems to be some minor issues.

service-worker.js

"use strict";

function sendAudioMessage(actionType, audioFile) {
  chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
    tabs.forEach(tab => {
      chrome.tabs.sendMessage(tab.id, { action: actionType });
    });
  });
}

chrome.webNavigation.onCreatedNavigationTarget.addListener(onNav);
chrome.webNavigation.onBeforeNavigate.addListener(onNav);
chrome.webNavigation.onReferenceFragmentUpdated.addListener(onNav);
chrome.webNavigation.onHistoryStateUpdated.addListener(onNav);

function onNav({frameId}) {
  if(frameId > 0) return;
  sendAudioMessage('playNavigationSound');
}

chrome.downloads.onChanged.addListener(delta => {
  if(delta.state && delta.state.current === "complete") {
    sendAudioMessage('playDownloadCompleteSound');
  }
  if(delta.error && delta.error.current) {
    sendAudioMessage('playDownloadErrorSound');
  }
});

chrome.tabs.onUpdated.addListener((tabId, {mutedInfo}) => {
  if(mutedInfo && mutedInfo.reason === "user") {
    sendAudioMessage('playMuteWarningSound'); 
  }
});

function changeVolume(volumeLevel) {
  chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
    tabs.forEach(tab => {
      chrome.tabs.sendMessage(tab.id, { action: 'changeVolume', volume: volumeLevel });
    });
  });
}

// *** Message Handler ***
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  switch (message.action) {
    case 'playNavigationSound':
      sendAudioMessage('playNavigationSound');
      break;
    case 'playDownloadCompleteSound':
      sendAudioMessage('playDownloadCompleteSound');
      break;
    case 'playDownloadErrorSound':
      sendAudioMessage('playDownloadErrorSound');
      break;
    case 'playMuteWarningSound':
      sendAudioMessage('playMuteWarningSound');
      break;
    case 'changeVolume':
      changeVolume(0.75); 
      break;
    default:
      console.log('Unknown message action:', message.action);
  }
});

content-script.js

// Helper function to play audio
function playAudio(audioFile) {
  const audio = new Audio(chrome.runtime.getURL(audioFile)); // Use chrome.runtime.getURL for packaged extension resources
  audio.play();
}

// Helper function for setting volume
function setAudioVolume(volumeLevel) {
  const audioElements = document.querySelectorAll('audio');
  audioElements.forEach(audio => {
      audio.volume = volumeLevel;
  });
}

// Receive messages from your service worker
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  switch (message.action) {
      case 'playNavigationSound':
          playAudio('nav.ogg');
          break;
      case 'playDownloadCompleteSound':
          playAudio('done.ogg');
          break;
      case 'playDownloadErrorSound':
          playAudio('error.ogg');
          break;
      case 'playMuteWarningSound':
          playAudio('unlock.ogg');
          break;
      case 'changeVolme':
          setAudioVolume(0.75);
          break;
      default:
          console.log('Unknown message action:', message.action);
  }
});
  

manifest.json

{
  "manifest_version": 3,
  "name": "PopupSound",
  "description": "Plays a click sound when you click on a link. Also plays a trumpet sound when you finish downloading a file.",
  "author": "Michael Gunter",
  "version": "3.0",
  "default_locale": "en",
  "offline_enabled": true,
  "icons": {
    "32": "icon_32.png",
    "96": "icon_96.png",
    "128": "icon_128.png"
  },
  "background": {
    "service_worker": "service-worker.js"
  },
  "permissions": [
    "webNavigation",
    "downloads",
    "tabs"
  ],

  "content_scripts": [
    {
      "matches": ["<all_urls>"], 
      "js": ["content-script.js"],
      "run_at": "document_start"
    }
  ],

  "content_security_policy": {}
}

Edit: While I no longer get the error message when the extension runs, I now get two error messages when audio is expected to be played from the browser extension.

Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.

Uncaught (in promise) NotAllowedError: play() can only be initiated by a user gesture.

I hope this helps.

How to Update Input Value without onChange in React?

I’ve been working on a React component where I have implemented handleStepUp and handleStepDown functions for incrementing and decrementing values. However, I’m facing a challenge with updating the input value within these functions since they don’t have access to an event like onChange. The onChange event is crucial for updating the input value in React, but I can’t directly use it within handleStepUp or handleStepDown.

import * as React from 'react';

import { Input } from '@/components/shadcnui/input';

export interface InputProps
  extends React.InputHTMLAttributes<HTMLInputElement> {
  onChange?: (event: ChangeEventExtendedProps) => void;
  defaultValue?: string;
  step?: number;
  onStepUp?: () => void; // Menambah properti onStepUp
  onStepDown?: () => void; // Menambah properti onStepDown
}

export interface CustomChangeEvent {
  target: { floatValue: number; formattedValue: string; value: string };
}
export interface ChangeEventExtendedProps
  extends React.ChangeEvent<HTMLInputElement> {
  target: HTMLInputElement & {
    floatValue: number | undefined;
    formattedValue: string | undefined;
  };
}

function formatNumber(number: number): string {
  const converted = number.toLocaleString(); // returns a number as a string, using local language format. 1000 => 1,000
  return converted;
}

export const NumberInputFormat = React.forwardRef<HTMLInputElement, InputProps>(
  (props, ref) => {
    const {
      onChange,
      defaultValue = 0,
      step = 1,
      onStepUp,
      onStepDown,
      min,
      max = 10,
    } = props;

    const [formattedValue, setFormattedValue] = React.useState<string>(
      defaultValue.toString()
    );

    // ketika kita mempassing sebuah fungsi ke dalam sebuah props,
    // ada baiknya kita buatkan dia useCallback sehingga fungsi
    // itu tidak dibuat kembali ketika proses re-render
    const handleChange = React.useCallback(
      (event: ChangeEventExtendedProps) => {
        const stringValue = event.target.value;

        const numericValue = stringValue
          ? parseFloat(stringValue.replace(/,/g, ''))
          : 0;

        const formattedStringValue = formatNumber(numericValue);
        setFormattedValue(formattedStringValue);
        onChange?.({
          ...event,
          target: {
            ...event.target,
            floatValue: numericValue,
            formattedValue: formattedStringValue,
            value: stringValue,
          },
        });
      },
      [onChange]
    );

    const handleStepUp = () => {
      const stringValue = formattedValue.replace(/,/g, '');
      const floatValue = parseFloat(stringValue) + step;
      const formattedStringValue = formatNumber(floatValue);
      setFormattedValue(formattedStringValue);

      onStepUp?.(); // Memanggil onStepUp jika diberikan
    };

    const handleStepDown = () => {
      const stringValue = formattedValue.replace(/,/g, '');
      const floatValue = parseFloat(stringValue) - step;
      const formattedStringValue = formatNumber(floatValue);
      setFormattedValue(formattedStringValue);

      onStepDown?.(); // Memanggil onStepUp jika diberikan
    };

    return (
      <>
        <button type="button" onClick={handleStepUp}>
          +
        </button>
        <button type="button" onClick={handleStepDown}>
          -
        </button>
        <Input
          {...props}
          value={formattedValue}
          onChange={handleChange}
          ref={ref}
          type="text"
        />
      </>
    );
  }
);

NumberInputFormat.displayName = 'NumberInputFormat';

What would be the best approach to update the input value without relying on the onChange event? Is there a way to achieve this while maintaining the React best practices? Any insights or alternative methods would be greatly appreciated. Thank you!

window.open can’t attach params to a url ends with .html

while I’m using

window.open(‘/a.html?title=666’)

there is no title = 666 in the new window’s url

but

window.open(‘/a?title=666’)

works fine.

it’s really confused me.

by the way, I’m using node’s ‘serve’ npm package to test in localhost.

during the research of documents, it is supposed to be the same.

How to add spacing between Legend and Chart in Recharts with absolute positioning?

I’m using Recharts for the first time in my React project
I’ve positioned the legend of my BarChart component to the top right corner.
However, I’m struggling to add spacing between the legend and the chart itself. Since the legend is positioned absolutely, I can’t set any margin directly on it.

When attempting to change the legend’s style to relative positioning, the legend gets displayed under the chart, ignoring the align and verticalAlign properties

Here’s a snippet of my code:

<BarChart data={data}
          barGap={8}>
    <CartesianGrid strokeDasharray="3 3" vertical={false}/>
    <XAxis tickFormatter={(index) => index + 1} tickMargin={16} tickLine={false}/>
    <YAxis orientation={"right"} tickMargin={16} axisLine={false} tickLine={false}/>
    <Tooltip content={<CustomTooltip/>}/>
    <Legend
        align="right" verticalAlign="top"
        iconType="circle" iconSize={12}
        formatter={(value, entry) => {
            return <LegendText>{value} ({entry.payload.unit})</LegendText>
        }}/>
    <Bar name="Poids" unit="kg" dataKey="kilogram" fill="#282D30" barSize={7}
         radius={[10, 10, 0, 0]}/>
    <Bar name="Calories brûlées" unit="kCal" dataKey="calories" fill="#E60000" barSize={7}
         radius={[10, 10, 0, 0]}/>
</BarChart>

How can I add a specific amount of spacing (e.g., 65px) between the legend and the chart in this setup?

Thank you!

Bar chart not displaying axes and legend values correctly

I am working on a page that uses datatables to retrieve highcharts. Charts for Buttons one and three are fine. The problem I am facing is with Button two – Bar chart. For the chart, I am trying to display the values from column 2022 as Y axis and Percent column as X axis. The legend should also display Y axis columns. What am I missing? Here is my code.

// Function to initialize Highcharts charts
function initializeChart(chartId, chartTitle, chartData, chartType) {
    Highcharts.chart(chartId, {
        chart: {
            type: chartType,
            styledMode: false
        },
        title: {
            text: chartTitle
        },
        colors: ['#1a4480', '#e52207', '#e66f0e', '#ffbe2e', '#fee685', '#538200', '#04c585', '#97d4ea', '#009ec1', '#0076d6', '#adadad', '#8168b3', '#d72d79', '#f2938c'],
        tooltip: {
            pointFormat: '</b> {point.y:.1f}%'
        },
        plotOptions: {
            bar: {
                dataLabels: {
                    enabled: true,
                    format: '{point.y:.1f}%',
                    style: {
                        fontSize: "12px"
                    }
                },
                showInLegend: true
            },
            pie: {
                dataLabels: {
                    enabled: true,
                    format: '{point.y:.1f}%',
                    style: {
                        fontSize: "12px"
                    }
                },
                showInLegend: true
            }
        },
        legend: {
            symbolRadius: 0,
            itemStyle: {
                color: '#000000',
                fontSize: '16px'
            }
        },
        series: [{
            data: chartData
        }]
    });
}

// Function to retrieve chart data from DataTable
function getChartData(table) {
    const data = [];
    table.rows().every(function () {
        const row = this.data();
        data.push({
            name: row[0],
            y: parseFloat(row[1])
        });
    });
    return data;
}

// Check if DataTable and Highcharts are defined before calling the function
if (typeof DataTable !== 'undefined' && typeof Highcharts !== 'undefined') {
    initializeCharts();
}

function initializeCharts() {
    const table1 = new DataTable('#example1', {
        searching: false,
        info: true,
        paging: false,
        sort: false
    });
    const table2 = new DataTable('#example', {
        searching: false,
        info: true,
        paging: false,
        sort: false
    });

    const chartData1 = getChartData(table1);
    const chartData2 = getChartData(table2);

    initializeChart('demo-output', 'FY 2023', chartData1, 'pie');
    initializeChart('demo-output2', 'FY 2022', chartData2, 'bar');

    var categories = [];
    var allSeriesData = [];

    var table = $("#example2").DataTable({
        searching: false,
        responsive: true,
        lengthChange: false,
        ordering: false,
        info: false,
        paging: false,
        initComplete: function (settings, json) {
            let api = new $.fn.dataTable.Api(settings);

            var headers = api.columns().header().toArray();
            headers.forEach(function (heading, index) {
                if (index > 0 && index < headers.length) {
                    categories.push($(heading).html());
                }
            });

            let rows = api.rows().data().toArray();
            rows.forEach(function (row) {
                group = {
                    name: '',
                    data: []
                };
                row.forEach(function (cell, idx) {
                    if (idx == 0) {
                        group.name = cell;
                    } else if (idx < row.length) {
                        group.data.push(parseFloat(cell.replace(/,/g, '')));
                    }
                });
                allSeriesData.push(group);
            });
        }
    });

    Highcharts.setOptions({
        lang: {
            thousandsSep: ','
        }
    });

    var myChart = Highcharts.chart("chart-A", {
        chart: {
            type: "column",
            borderColor: 'lightgray',
            borderWidth: 1,
            marginTop: 50
        },
        tooltip: {
            headerFormat: '{point.key}<br/>',
            pointFormat: '{series.name}: <b>{point.y:.1f}%</b>'
        },
        legend: {
            symbolRadius: 0,
            itemStyle: {
                color: '#000000',
                fontSize: '16px'
            }
        },
        colors: ['#003489', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5'],
        credits: {
            enabled: false
        },
        title: {
            text: "Trends"
        },
        xAxis: {
            categories: categories,
            labels: {
                style: {
                    fontWeight: '600',
                    fontSize: '16px',
                    color: '#000000'
                }
            }
        },
        yAxis: {
            title: false,
            tickInterval: 10,
            max: 60,
            labels: {
                formatter: function () {
                    return Highcharts.numberFormat(this.value, 0);
                },
                style: {
                    fontWeight: '600',
                    fontSize: '16px',
                    color: '#000000'
                }
            }
        },
        series: allSeriesData
    });

    $('.usa-button').on('click', function () {
        var buttonId = $(this).attr('id');

        if (buttonId === 'previous') {
            $('#chart2').show();
            $('#chart1').hide();
            $('#chart3').hide();
        } else if (buttonId === 'trend') {
            $('#chart2').hide();
            $('#chart1').hide();
            $('#chart3').show();
        } else {
            $('#chart2').hide();
            $('#chart1').show();
            $('#chart3').hide();
        }

        $('.usa-button').removeClass('active');
        $(this).addClass('active');
    });

    $('#current').addClass('active');
}
<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

    <link href="https://nightly.datatables.net/css/dataTables.dataTables.css" rel="stylesheet" type="text/css" />
    <script src="https://nightly.datatables.net/js/dataTables.js"></script>

 <script src="https://code.highcharts.com/highcharts.js"></script>

  </head>
  <body>




<div class="ar-controls grid-row tablet:flex-justify-start">
<div class="tablet:grid-col-auto margin-bottom-205"><button id="current" class="usa-button usa-button--outline" title="Select to see related information below">one</button> <button id="previous" class="usa-button usa-button--outline" title="Select to see related information below">two</button> <button id="trend" class="usa-button usa-button--outline" title="Select to see related information below">three</button></div>
</div>

<div id="chart1">
<div id="demo-output" class="chart-display" style=" margin-bottom: 2em; height: 500px; border: solid 1px lightgray;"></div>

<table id="example1" class="display" style=" width: 100%;"><thead>
<tr>
<th scope="col">2023</th>
<th scope="col">Percent</th>
</tr>

</thead>
<tr>
<td scope="row">ABC</td>
<td>45.9%</td>
</tr>

<tr>
<td scope="row">DEF</td>
<td>22.0%</td>
</tr>

<tr>
<td scope="row">GHI</td>
<td>13.6%</td>
</tr>

</table>
</div>

<div id="chart2" style=" display: none;">
<div id="demo-output2" class="chart-display2" style=" margin-bottom: 2em; height: 680px; border: solid 1px lightgray;"></div>

<table id="example" class="display" style=" width: 100%;"><thead>
<tr>
<th scope="col">2022</th>
<th scope="col">Percent</th>
</tr>

</thead>
<tr>
<td>123</td>
<td>51.90%</td>
</tr>

<tr>
<td>456</td>
<td>18.60%</td>
</tr>

</table>
</div>

<div id="chart3" style=" display: none;">
<div id="chart-A" style=" width: 100%; height: 500px;"></div>

<table class="row-border stripe no-footer cell-border padding-top-5" id="example2" style=" width: 100%;"><thead>
<tr>
<th>Year</th>
<th>column1</th>
<th>column2</th>
<th>column3</th>

</tr>

</thead>
<tr>
<td scope="row" style=" text-align: left; white-space: nowrap;">FY19</td>
<td style=" text-align: left;">42.7%</td>
<td style=" text-align: left;">17.3%</td>
<td style=" text-align: left;">9.5%</td>

</tr>

<tr>
<td scope="row" style=" text-align: left;">FY20</td>
<td style=" text-align: left;">49.5%</td>
<td style=" text-align: left;">16.3%</td>
<td style=" text-align: left;">3.4%</td>

</tr>


</table>
</div>
</div>

Chart.js is not visible, but does show up on HTML

I am creating a dashboard, on this dashboard i make a call to some charts using htmx, but the chart is not rendering properly, when i inspect the element i can see the script, canvas and code but not the visual of the graph. I am using flask and python and this is my code pre the dashboard that calls the chart:

<div>
    <div class="toolbox">
        <h1>Budget</h1>
        <div>
            <div hx-get="/auth/budget/expense_form" hx-swap="innerHTML" hx-trigger="load once" id="expense_form_field">
            </div>
            <div hx-get="/auth/budget/dashboard" hx-swap="outerHTML" id="dashboard" hx-target="#dashboard"
                hx-trigger="load once">
            </div>
        </div>
    </div> </div> </div>

And this is what html is returned:

<div>
    <canvas id="myChart"></canvas>
</div>

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    const ctx = document.getElementById('myChart');

    const chart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
            datasets: [{
                label: '# of Votes',
                data: [12, 19, 3, 5, 2, 3],
                borderWidth: 1
            }]
        },
        options: {
            scales: {
                y: {
                    beginAtZero: true
                }
            }
        }
    });</script>

I have looked to the following similar questions, but i have not found any of their fixes useful: enter link description here, enter link description here,enter link description here

When i check the console errors i am noticing this:

Uncaught ReferenceError: Chart is not defined
    at <anonymous>:4:19
    at At ([email protected]:1:22924)
    at Nt ([email protected]:1:23051)
    at [email protected]:1:10309
    at [email protected]:1:44741
    at oe ([email protected]:1:4604)
    at s ([email protected]:1:44716)

my thinking is that HTMX is affecting the script? Also when i inspect the chart element in browser it has an htmx class tag, could this be interfering with the script?

<script class="htmx-settling">
    const ctx = document.getElementById('myChart');

    const chart = new Chart(ctx, {
        type: 'bar',
        data: {
            labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
            datasets: [{
                label: '# of Votes',
                data: [12, 19, 3, 5, 2, 3],
                borderWidth: 1
            }]
        },
        options: {
            scales: {
                y: {
                    beginAtZero: true
                }
            }
        }
    });</script>

How can I remove one of the clicks from hide/show?

I’m trying to show/hide more info about names on click, but don’t know how to make it work of a single click.

I’m creating a div with JS like so:

const newDiv = document.createElement("div");
newDiv.className = "game-info";
newDiv.innerHTML = `
<p onclick="toggler()";>${game.Name}</p>
<div class="info">
<img src="${game.Thumbnail}">
<p>${game.Description}</p>
</div>
`;
document.body.appendChild(newDiv);

The toggler function is written like this:

function toggler(){
    $('div.game-info').click(function(e){
        $(this).children('.info').toggle();
    });
}

It kinda works, but it takes one or more clicks to view the additional info. I know the problem is due to multiple onclick calls, but don’t know how to make it with a single click. I tried using jQuery without the toggler function, but then it opens info on all the names and not just the one which was clicked. So if someone could either tell me how to get rid of that secondary onclick or how to properly target the info which I clicked in the innerHTML section that’d be great!