A ServerEndpoint works locally but not in Heroku

I have this Java WebSocket application here. My code for constructing the URL for the server endpoint is:

function constructWebSocket(endpoint, onMessageCallback) {

    const url = constructWebSocketUrl(endpoint);
    const socket = new WebSocket(url);

    socket.onopen = (event) => {
        console.log("onopen. Event: ", event);
    };

    socket.onmessage = onMessageCallback;
    socket.onclose = (event) => {
        console.log("onclose. Event: ", event);
    };

    socket.onerror = (event) => {
        console.log("onerror. Event: ", event);
    };

    return socket;
}

function constructWebSocketUrl(endpoint) {
    const host = document.location.host;
    const path = document.location.pathname;
    const protocol = document.location.protocol;
    
    if (protocol.startsWith("https")) {
        return `wss://${host}${path}${endpoint}`;
    } else if (protocol.startsWith("http")) {
        return `ws://${host}${path}${endpoint}`;
    } else {
        throw `Unknown protocol: ${protocol}.`;
    }
}

(The app is deployed on Heroku.)

While the above snippet returns a valid WebSocket when I run the web app on local Tomcat, on Heroku it returns 404 Not Found. What am I missing here?

value at env prod not working vite project

I need to use value of my .env at my vite.config.js. Locale I get the value and view at console.log, but in production I dont get the value and dont see the console.log.

vite.config.js at root

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";
import { VitePWA } from "vite-plugin-pwa";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd());

  console.log('## baseURL vite.config', env.VITE_APP_API_URL);
  return {
    server: {
      port: 3001,
      proxy: {
        "/api/socket": process.env.VITE_APP_API_URL_WS  || "http://localhost:8082",
        "/api": process.env.VITE_APP_API_URL || "http://localhost:8082", 

My .yml


name: CI

on:
  push:
    branches: [ main ]

env:
  BUCKET: my.bucket.com.br
  VITE_APP_API_URL: ${{ secrets.VITE_APP_API_URL }}
  VITE_APP_API_URL_WS: ${{ secrets.VITE_APP_API_URL_WS }}

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Setup Node.js
      uses: actions/setup-node@v1
      with:
        node-version: 16.x

    - name: Install dependencies
      run: npm install --force

    - name: Build
      run: npm run build
      env:
        VITE_APP_API_URL: ${{ secrets.VITE_APP_API_URL }}
        VITE_APP_API_URL_WS: ${{ secrets.VITE_APP_API_URL_WS }}

In my src/, at components, I get the value, but at vite.config I dont get. I’ve tried other ways too.
Help me, please.

Why can’t I extend from a custom HTML element class conditionally?

The snippet below spits out an error that CustomElementParent is not defined when I try to extend from it in CustomElementChild.

When I remove the ! customElements.get('custom-element-parent') check, it works.

In my case, CustomElementParent is in a third party script, so I can’t actually remove the if statement.

I guess this is a problem of conditionally defining a class. Is there any way to extend this class if it is conditionally defined?

<script>
if (! customElements.get('custom-element-parent')) {
    class CustomElementParent extends HTMLElement {
        constructor() {
            super();
        }
    }

    customElements.define('custom-element-parent', CustomElementParent);
}

if (! customElements.get('custom-element-child')) {
    class CustomElementChild extends CustomElementParent {
        constructor() {
            super();
            alert('test');
        }
    }

    customElements.define('custom-element-child', CustomElementChild);
}
</script>

<custom-element-child></custom-element-child>

Using HTML in JavaScript

I was able to easily add text to my project using the following code:

const loadingText = $('#loading-text');
const text = "Your first sentence here"; // Your first sentence here

let i = 0;

const interval = setInterval(() => {
  if (i === text.length) {
    clearInterval(interval);
  } else {
    loadingText.text(loadingText.text() + text[i]);
    i++;
  }
}, 100); // Speed of animation (adjust as needed)
#loading-text {
            font-size: 24px;
            font-weight: bold;
            text-align: center;
            margin: 20px auto;
            width: 50%;
            opacity: 1;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div id="loading-text"></div>

Now the question that has come to me is, is there a way to display such text as HTML without tags (of course with the tag effect on the text)?

For example something like this:

const text = "lorem rerum <b style="color:#f00;">aperiam</b> maxime reiciendis";

In the text above, the word (aperiam) is placed between the tag and I have also given it a linear style.

By placing the above line in the text code, it is printed as follows:

lorem rerum <b style="color:#f00;">aperiam</b> maxime reiciendis

Is there a way to display the output as HTML?

Why is random rounding .5 coming up when I click?

I’m making a clicker game, and I’m having an a weird problem that happens every time I click the Bitcoin, or main part of the game. The part that has the most trouble is the buildings that add up to any number that ends in .5 like, 1.5, 2.5 and etc. I haven’t done much research on this problem but it’s hard to know what I’m looking for. https://ratking51.github.io/Bitcoin-Clicker/ this is the url to the GitHub Hosted site of the game itself.

/*
some of the code from javascript is ideas from the game by Ortell Cookie Clicker.
Other Resources used are the world wide web.... lol
Stack Overflow
*/

function getElement(element) {return document.getElementById(element)}

var user = {
    money: 100000,
    moneyPerClick: 1,
    moneyPerSecond: 0,
    totalMoney: 0,
    totalClicks: 0
}

var game = {
    inputs: {
        click: function(){
            user.money += user.moneyPerClick;
            user.totalClicks++;
            user.totalMoney++;
        }
    },


    display: {
        clickerContainer: function(){
            getElement("money").textContent = Math.floor(user.money);
            getElement("moneyPerSecond").textContent = Math.floor(user.moneyPerSecond);
        },

        fadeOut: function(element, duration, finalOpacity, callback){
            let opacity = 1;

            let elementFadingInterval = window.setInterval(function() {
                opacity -= 50 / duration;

                if (opacity <= finalOpacity){
                    clearInterval(elementFadingInterval);
                    callback();
                }

                element.style.opacity = opacity;
            })
        },

        addClickNumber: function(event){
           let clicker = getElement("clickContainer");
           
           let clickerOffset = clicker.getBoundingClientRect();
           let position = {
            x: event.pageX - clickerOffset.left,
            y: event.pageY - clickerOffset.top
           };

           let element = document.createElement("div");
           element.textContent = "+" + user.moneyPerClick;
           element.classList.add("number");
           element.style.left = position.x + "px";
           element.style.top = position.y  + "px";

           clicker.appendChild(element)

           let movementInterval = window.setInterval(() => {
                if(typeof element == "undefined" && element == null){ clearInterval(movementInterval)};

                position.y--;
                element.style.top = position.y + "px";
           }, 10);

           this.fadeOut(element, 10000, 0.5, function(){
                element.remove();
           })
        },

        spawnBuildings: function(){
            var shopContainer = getElement("shopContainer");
            shopContainer.innerHTML = ""
            for(i=0; i<game.buildings.title.length; i++){
                shopContainer.innerHTML += `
                <div class="shop-card" id="shopCard" title="${game.buildings.description[i]}, Income: ${game.buildings.income[i]}" onclick="game.buildings.purchase(${i})">
                    <img src="${game.buildings.img[i]}">
                    <div class="shop-info-container">
                        <h1>${game.buildings.title[i]}</h1>
                        <h2>Cost: ${game.buildings.cost[i]}</h2>
                    </div>
                    <h1>${game.buildings.amount[i]}</h1>
                </div>
                `
            }
        },

        displayBuildings: function(){
            var humanContainer = getElement("humanContainer");
            var oldComputerContainer = getElement("oldComputerContainer")
            var betterKeyboardContainer = getElement("betterKeyboardContainer")
            var betterMouseContainer = getElement("betterMouseContainer")
            var betterDeskContainer = getElement("betterDeskContainer")
            if (game.buildings.amount[0] <= 0){
                humanContainer.style.visibility = "hidden";
            }
            if (game.buildings.amount[0] > 0){
                humanContainer.style.visibility = "visible";
                humanContainer.innerHTML = ""
                for(i=0; i<game.buildings.amount[0]; i++){
                    let element = document.createElement("img");
                    element.src = game.buildings.img[0];
                    element.classList.add("building-display-img")
                    let left;
                    if(i == 0){
                        left = 0
                    }
                    else{
                        left = (i * 100) - 75;
                    }
                    const top = Math.random() * 25
                    element.style.left = left + "px"
                    element.style.top = top + "px"
                    

                    humanContainer.appendChild(element)
                }
            }
            if (game.buildings.amount[1] <= 0){
                oldComputerContainer.style.visibility = "hidden";
            }
            if (game.buildings.amount[1] > 0){
                oldComputerContainer.style.visibility = "visible";
                oldComputerContainer.innerHTML = ""
                for(i=0; i<game.buildings.amount[1]; i++){
                    let element = document.createElement("img");
                    element.src = game.buildings.img[1];
                    element.classList.add("building-display-img")
                    let left;
                    if(i == 0){
                        left = 0
                    }
                    else{
                        left = (i * 100) - 75;
                    }
                    const top = Math.random() * 25
                    element.style.left = left + "px"
                    element.style.top = top + "px"
                    

                    oldComputerContainer.appendChild(element)
                }
            }
            if (game.buildings.amount[2] <= 0){
                betterKeyboardContainer.style.visibility = "hidden";
            }
            if (game.buildings.amount[2] > 0){
                betterKeyboardContainer.style.visibility = "visible";
                betterKeyboardContainer.innerHTML = ""
                for(i=0; i<game.buildings.amount[2]; i++){
                    let element = document.createElement("img");
                    element.src = game.buildings.img[2];
                    element.classList.add("building-display-img")
                    let left;
                    if(i == 0){
                        left = 0
                    }
                    else{
                        left = (i * 100) - 75;
                    }
                    const top = Math.random() * 25
                    element.style.left = left + "px"
                    element.style.top = top + "px"
                    

                    betterKeyboardContainer.appendChild(element)
                }
            }
            if (game.buildings.amount[3] <= 0){
                betterMouseContainer.style.visibility = "hidden";
            }
            if (game.buildings.amount[3] > 0){
                betterMouseContainer.style.visibility = "visible";
                betterMouseContainer.innerHTML = ""
                for(i=0; i<game.buildings.amount[3]; i++){
                    let element = document.createElement("img");
                    element.src = game.buildings.img[3];
                    element.classList.add("building-display-img")
                    let left;
                    if(i == 0){
                        left = 0
                    }
                    else{
                        left = (i * 100) - 75;
                    }
                    const top = Math.random() * 25
                    element.style.left = left + "px"
                    element.style.top = top + "px"
                    

                    betterMouseContainer.appendChild(element)
                }
            }
            if (game.buildings.amount[4] <= 0){
                betterDeskContainer.style.visibility = "hidden";
            }
            if (game.buildings.amount[4] > 0){
                betterDeskContainer.style.visibility = "visible";
                betterDeskContainer.innerHTML = ""
                for(i=0; i<game.buildings.amount[4]; i++){
                    let element = document.createElement("img");
                    element.src = game.buildings.img[4];
                    element.classList.add("building-display-img")
                    let left;
                    if(i == 0){
                        left = 0
                    }
                    else{
                        left = (i * 100) - 75;
                    }
                    const top = Math.random() * 25
                    element.style.left = left + "px"
                    element.style.top = top + "px"
                    

                    betterDeskContainer.appendChild(element)
                }
            }
            
            
        },

        displayUpgrade: function() {
            var container = getElement("upgradesContainer");
            container.innerHTML = ""
            for(i=0; i < game.upgrades.title.length; i++){
                if(game.upgrades.owned[i] == false){
                    if (game.upgrades.type[i] == 0){
                        if(game.upgrades.need[i] <= game.buildings.amount[game.upgrades.i[i]]){
                            
                            container.innerHTML += `
                            <img class="upgrade-img" src="${game.upgrades.img[i]}" title="${game.upgrades.title[i]}. ${game.upgrades.description[i]}. Cost:${game.upgrades.cost[i]}" onclick="game.upgrades.purchase(${i})"/>
                            `
                        }
                    }
                    if (game.upgrades.type[i] == 1){
                        if(game.upgrades.need[i] <= user.totalClicks){
                            container.innerHTML += `
                            <img class="upgrade-img" src="${game.upgrades.img[i]}" title="${game.upgrades.title[i]}. ${game.upgrades.description[i]}. Cost:${game.upgrades.cost[i]}" onclick="game.upgrades.purchase(${i})"/>
                            `
                        }
                    }
                }
                else{
                    container.innerHTML += ""
                }
            }
        },
        updateStats: function(){
            var mpsElement = getElement("moneyPerSecond");
            var totalMoneyElement = getElement("totalMoney");
            var totalClicksElement = getElement("totalClicks");
            var moneyPerClickElement = getElement("moneyPerClick");
            mpsElement.textContent = user.moneyPerSecond;
            totalMoneyElement.textContent = user.totalMoney;
            totalClicksElement.textContent = user.totalClicks;
            moneyPerClickElement.textContent = user.moneyPerClick;

        },

        displayAchievement: function(name, description, img, i){
            var container = getElement("achievementContainer");
            container.innerHTML += `
            <div class="achievement-card" id="achievementCard${i}" title="${description}" onclick="game.achievements.removeAchievement(${i})">
                <img src="${img}"/>
                <p>${name}</p>
            </div
            `
        }
    },

    buildings: {
        title: [
            "Human",
            "Slow Computer",
            "Better Keyboard",
            "Better Mouse",
            "Better Desk"
        ],
        cost: [
            150,
            500,
            1350,
            4000,
            7000
        ],
        income: [
            0.5,
            1,
            3,
            5,
            10,
        ],
        amount: [
            0,
            0,
            0,
            0,
            0
        ],
        description: [
            "A human to mine your crypto",
            "This mines crypto but it sucks like crap",
            "Keyboard to get type crypto faster.",
            "You can click faster for more crypto",
            "This gives you more desk space for more monitors."
        ],
        img: [
            "./imgs/human-image.png",
            "./imgs/old-computer.png",
            "./imgs/better-keyboard.jpeg",
            "./imgs/better-mouse.jpeg",
            "./imgs/better-desk.jpeg",
        ],

        purchase: function(i){
            if (user.money >= this.cost[i]){
                user.money -= this.cost[i];
                this.amount[i] += 1;
                this.cost[i] = Math.floor(this.cost[i] * 1.25);
                game.display.spawnBuildings()
                game.display.clickerContainer()
                user.moneyPerSecond += this.income[i];
                game.display.displayBuildings()
                game.display.displayUpgrade()
            }
        }
    },

    upgrades: {
        title: [
            "Faster Workers",
            "More Clicker",
            "Beter Keycaps",
            "More Ram",
            "Faster DPI",
            ""
        ],
        cost: [
            1500,
            1500,
            5000,
            3500
        ],
        description: [
            "This will doubles your workers income!!",
            "This will double your cursors income",
            "This will double your better keyboard income.",
            "This will double your old computer income.",
            "This will double your better mouse income."
        ],
        img: [
            "./imgs/human-image.png",
            "./imgs/cursor.webp",
            "./imgs/better-keyboard.jpeg",
            "./imgs/old-computer.png",
            "./imgs/better-mouse.jpeg"
        ],
        // 0 = building 1 = clicker 2 = click add
        type:[
            0,
            1,
            0,
            0,
            0
        ],
        outcome: [
            2,
            2,
            2,
            2,
            2
        ],
        need: [
            1,
            1,
            1,
            1,
            1
        ],
        owned: [
            false,
            false,
            false,
            false,
            false
        ],
        i: [
            0,
            false,
            2,
            1,
            3
        ],
        purchase: function(i) {
            if(user.money >= this.cost[i] && this.owned[i] == false){
                if (this.type[i] == 0){
                    user.money -= this.cost[i];
                    this.owned[i] = true;
                    game.buildings.income[this.i[i]] += game.buildings.income[this.i[i]] * this.outcome[i]
                    game.display.clickerContainer()
                    game.display.displayBuildings()
                    game.display.displayUpgrade()
                    game.display.spawnBuildings()
                }
                if (this.type[i] == 1){
                    user.money -= this.cost[i];
                    this.owned[i] = true;
                    user.moneyPerClick = this.outcome[i] * user.moneyPerClick
                    game.display.clickerContainer()
                    game.display.displayBuildings()
                    game.display.displayUpgrade()
                    game.display.spawnBuildings()
                }
            }
            
        }
    },

    achievements: {
        name: [
            "One Starts All"
        ],

        description: [
            "You Clicked the Bitcoin"
        ],
        // 0 click 1 building
        type: [
            0       
        ],

        whatNeeded: [
            1
        ],

        owned: [
            false
        ],

        img: [
            "./imgs/cursor.webp"
        ],

        achieve: function(){
            for(i=0; i<this.name.length; i++){
                if(this.owned[i] == false){
                    if(this.type[i] == 0){
                        if(this.whatNeeded[i] <= user.totalClicks){
                            game.display.displayAchievement(this.name[i], this.description[i], this.img[i], i)
                            this.owned[i] = true
                        }
                    }
                }
            }
        },

        removeAchievement: function(i){
            getElement("achievementCard" + i).style.visibility = "hidden";
        }

    },

    save: {
        saveGame: function(){
            var gameSave = {
                money: user.money,
                moneyPerClick: user.moneyPerClick,
                totalClicks: user.totalClicks,
                totalMoney: user.totalMoney,
                moneyPerSecond: user.moneyPerSecond,
                buildingCost: game.buildings.cost,
                buildingAmount: game.buildings.amount,
                buildingIncome: game.buildings.income,
                upgradeOwned: game.upgrades.owned,
                achievementOwned: game.achievements.owned
            }
            localStorage.setItem("gameSave", JSON.stringify(gameSave))
        },

        loadGame: function(){
            var savedGame = JSON.parse(localStorage.getItem("gameSave"))
            if (localStorage.getItem("gameSave") !== null){
                if (typeof savedGame.money !== "undefined") user.money = savedGame.money
                if (typeof savedGame.moneyPerClick !== "undefined") user.moneyPerClick = savedGame.moneyPerClick
                if (typeof savedGame.totalClicks !== "undefined") user.totalClicks = savedGame.totalClicks
                if (typeof savedGame.totalMoney !== "undefined") user.totalMoney = savedGame.totalMoney
                if (typeof savedGame.moneyPerSecond !== "undefined") user.moneyPerSecond = savedGame.moneyPerSecond
                if (typeof savedGame.buildingCost !== "undefined"){
                    for (i=0; i<savedGame.buildingCost.length; i++){
                        game.buildings.cost[i] = savedGame.buildingCost[i]
                    }
                }
                if (typeof savedGame.buildingAmount.length !== "undefined"){
                    for (i=0; i<savedGame.buildingAmount.length; i++){
                        game.buildings.amount[i] = savedGame.buildingAmount[i]
                    }
                }
                if (typeof savedGame.buildingIncome.length !== "undefined"){
                    for (i=0; i<savedGame.buildingIncome.length; i++){
                        game.buildings.income[i] = savedGame.buildingIncome[i]
                    }
                }
                if (typeof savedGame.upgradeOwned !== "undefined"){
                    for (i=0; i<savedGame.upgradeOwned.length; i++){
                        game.upgrades.owned[i] = savedGame.upgradeOwned[i]
                    }
                }
                if (typeof savedGame.achievementOwned !== "undefined"){
                    for (i=0; i<savedGame.achievementOwned.length; i++){
                        game.achievements.owned[i] = savedGame.achievementOwned[i]
                    }
                }
            }
        },

        resetGame: function(){
            if (confirm("Are you sure you want to reset your game?")){
                var gameSave = {};
                localStorage.setItem("gameSave", JSON.stringify(gameSave))
                location.reload();
            }
        }
    },

    addMoneyPerSecond: function(){
        user.money += user.moneyPerSecond
    }
}

// Event Listners
getElement("clickContainer").addEventListener('click', function(event){
    game.inputs.click();
    game.display.addClickNumber(event)
    game.display.clickerContainer()
    game.display.displayUpgrade()
    getElement("moneyPerSecond").textContent = Math.floor(user.moneyPerSecond);
}, false);

getElement("statsButton").addEventListener("mouseover", () => {
    getElement("statContainer").style.visibility = "visible";
    game.display.updateStats()
})

getElement("statsButton").addEventListener("mouseout", () => {
    getElement("statContainer").style.visibility = "hidden";
})

getElement("aboutButton").addEventListener("mouseover", () => {
    getElement("aboutContainer").style.visibility = "visible";
})

getElement("aboutButton").addEventListener("mouseout", () => {
    getElement("aboutContainer").style.visibility = "hidden";
})
getElement("resetButton").addEventListener("click", game.save.resetGame)



// tick
var tick = setInterval(() => {
    game.display.clickerContainer()
    game.display.spawnBuildings()
    game.addMoneyPerSecond()
    game.display.displayUpgrade()
    game.display.updateStats()
    game.achievements.achieve()
}, 1000)

var tick30 = setInterval(() => {
    game.save.saveGame()
}, 30000)

window.onload = () =>{
    tick
    game.save.loadGame()
    game.display.displayBuildings()
    game.save.saveGame()
}

Input text into search bar, press enter, and have html open in new tab (JAVASCRIPT)

I’d like to type an item name into a search bar and if the input text matches the item name — or at least matches close to the item name — press Enter to open the item’s html page in new tab.

For example, Beats by Dre is an item name I want to search and open in new tab, so I input “beats by dre” into the search bar, and when I press Enter then beatsbydre.html opens in new tab.

There are other items I’d like to do the same for (i.e., if I type in “soap” in search bar, and press enter, then the soap.html will open in new tab, etc), so I’d like to do the same for multiple item names and their html files.

What code can I write to achieve this?

Code I’m working with:

(reference: Get the value of input text when enter key pressed)

  function search(ele) {
    if (event.key === 'Enter' && ele === "beats by dre") {
      window.open("beatsbydre.html", '_blank').focus();
    }
  }
  <input type="text" placeholder="some text" class="search" onkeydown="search(this)" />

Im making a ping pong game and it’s glitching out after a certain amount of hits, what do i do?

Im making a ping pong game and it’s glitching out after a certain amount of hits, what do i do? So after exactly 25 hits the ball goes to the other side like normal but then it crosses the net in the middle, dissapears, and gives me the point. how do it fix this?

I have a html file and a javascript file, heres the code for both:

Html file:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Pong Game JavaScript</title>

    <style>

        body{

            background-color: dimgray;

        }

        #pong{

            border: 2px solid #FFF;

            position: absolute;

            margin :auto;

            top:0;

            right:0;

            left:0;

            bottom:0;

        }

    </style>

</head>

<body>
        <audio id="background-music-for-video-short-blog-era-of-cyborgs-54-second-199951.mp3" loop>
 
  <source src="background-music-for-video-short-blog-era-of-cyborgs-54-second-199951.mp3" type="audio/mp3">
  Your browser does not support the audio element.
</audio>

<p>Click the buttons to play or pause the audio.</p>

<button onclick="playAudio()" type="button">Play Audio</button>
<button onclick="pauseAudio()" type="button">Pause Audio</button> 

<script>
var x = document.getElementById("background-music-for-video-short-blog-era-of-cyborgs-54-second-199951.mp3"); 

function playAudio() { 
  x.play(); 
} 

function pauseAudio() { 
  x.pause(); 
} 
</script>

   <canvas id="pong" width="600" height="400"></canvas>

   <script src="pong.js"></script>
        
</body>

</html>

javascript file:

// select canvas element

const canvas = document.getElementById("pong");

// getContext of canvas = methods and properties to draw and do a lot of thing to the canvas

const ctx = canvas.getContext('2d');

// load sounds

let hit = new Audio();

let wall = new Audio();

let userScore = new Audio();

let comScore = new Audio();

hit.src = "sounds/hit.mp3";

wall.src = "sounds/wall.mp3";

comScore.src = "sounds/comScore.mp3";

userScore.src = "sounds/userScore.mp3";

// Ball object

const ball = {

    x : canvas.width/2,

    y : canvas.height/2,

    radius : 10,

    velocityX : 5,

    velocityY : 5,

    speed : 7,

    color : "WHITE"

}

// User Paddle

const user = {

    x : 0, // left side of canvas

    y : (canvas.height - 100)/2, // -100 the height of paddle

    width : 10,

    height : 100,

    score : 0,

    color : "WHITE"

}

// COM Paddle

const com = {

    x : canvas.width - 10, // - width of paddle

    y : (canvas.height - 100)/2, // -100 the height of paddle

    width : 10,

    height : 100,

    score : 0,

    color : "WHITE"

}

// NET

const net = {

    x : (canvas.width - 2)/2,

    y : 0,

    height : 10,

    width : 2,

    color : "WHITE"

}

// draw a rectangle, will be used to draw paddles

function drawRect(x, y, w, h, color){

    ctx.fillStyle = color;

    ctx.fillRect(x, y, w, h);

}

// draw circle, will be used to draw the ball

function drawArc(x, y, r, color){

    ctx.fillStyle = color;

    ctx.beginPath();

    ctx.arc(x,y,r,0,Math.PI*2,true);

    ctx.closePath();

    ctx.fill();

}

// listening to the mouse

canvas.addEventListener("mousemove", getMousePos);

function getMousePos(evt){

    let rect = canvas.getBoundingClientRect();

  

    user.y = evt.clientY - rect.top - user.height/2;

}

// when COM or USER scores, we reset the ball

function resetBall(){

    ball.x = canvas.width/2;

    ball.y = canvas.height/2;

    ball.velocityX = -ball.velocityX;

    ball.speed = 7;

}

// draw the net

function drawNet(){

    for(let i = 0; i <= canvas.height; i+=15){

        drawRect(net.x, net.y + i, net.width, net.height, net.color);

    }

}

// draw text

function drawText(text,x,y){

    ctx.fillStyle = "#FFF";

    ctx.font = "75px fantasy";

    ctx.fillText(text, x, y);

}

// collision detection

function collision(b,p){

    p.top = p.y;

    p.bottom = p.y + p.height;

    p.left = p.x;

    p.right = p.x + p.width;

  

    b.top = b.y - b.radius;

    b.bottom = b.y + b.radius;

    b.left = b.x - b.radius;

    b.right = b.x + b.radius;

  

    return p.left < b.right && p.top < b.bottom && p.right > b.left && p.bottom > b.top;

}

// update function, the function that does all calculations

function update(){

  

    // change the score of players, if the ball goes to the left "ball.x<0" computer win, else if "ball.x > canvas.width" the user win

    if( ball.x - ball.radius < 0 ){

        com.score++;

        comScore.play();

        resetBall();

    }else if( ball.x + ball.radius > canvas.width){

        user.score++;

        userScore.play();

        resetBall();

    }

  

    // the ball has a velocity

    ball.x += ball.velocityX;

    ball.y += ball.velocityY;

  

    // computer plays for itself, and we must be able to beat it

    // simple AI
    let computerLevel = 1;
    com.y += (ball.y - (com.y + com.height/2)) * computerLevel;

  

    // when the ball collides with bottom and top walls we inverse the y velocity.

    if(ball.y - ball.radius < 0 || ball.y + ball.radius > canvas.height){

        ball.velocityY = -ball.velocityY;

        wall.play();

    }

  

    // we check if the paddle hit the user or the com paddle

    let player = (ball.x + ball.radius < canvas.width/2) ? user : com;

  

    // if the ball hits a paddle

    if(collision(ball,player)){

        // play sound

        hit.play();

        // we check where the ball hits the paddle

        let collidePoint = (ball.y - (player.y + player.height/2));

        // normalize the value of collidePoint, we need to get numbers between -1 and 1.

        // -player.height/2 < collide Point < player.height/2

        collidePoint = collidePoint / (player.height/2);

      

        // when the ball hits the top of a paddle we want the ball, to take a -45degees angle

        // when the ball hits the center of the paddle we want the ball to take a 0degrees angle

        // when the ball hits the bottom of the paddle we want the ball to take a 45degrees

        // Math.PI/4 = 45degrees

        let angleRad = (Math.PI/4) * collidePoint;

      

        // change the X and Y velocity direction

        let direction = (ball.x + ball.radius < canvas.width/2) ? 1 : -1;

        ball.velocityX = direction * ball.speed * Math.cos(angleRad);

        ball.velocityY = ball.speed * Math.sin(angleRad);

      

        // speed up the ball everytime a paddle hits it.

        ball.speed += 0.1;

    }

}

// render function, the function that does al the drawing

function render(){

  

    // clear the canvas

    drawRect(0, 0, canvas.width, canvas.height, "#000");

  

    // draw the user score to the left

    drawText(user.score,canvas.width/4,canvas.height/5);

  

    // draw the COM score to the right

    drawText(com.score,3*canvas.width/4,canvas.height/5);

  

    // draw the net

    drawNet();

  

    // draw the user's paddle

    drawRect(user.x, user.y, user.width, user.height, user.color);

  

    // draw the COM's paddle

    drawRect(com.x, com.y, com.width, com.height, com.color);

  

    // draw the ball

    drawArc(ball.x, ball.y, ball.radius, ball.color);

}

function game(){

    update();

    render();

}

// number of frames per second

let framePerSecond = 50;

//call the game function 50 times every 1 Sec

let loop = setInterval(game,1000/framePerSecond);

How to make a search bar using HTML, CSS, and JAVASCRIPT that works

First time doing this, I have gone through several tutorials. I don’t understand why the Javascript is not working or showing up on the DOM. Here are a few of the search functions~

I added an event listener, a function that identifies if the search value matches the blog title, and if it does it is supposed to show up on a separate web page.

Example 1

document.addEventListener('click', searchResult); 

function searchResult() {
let input = document.getElementById('search-i').value;
input = input.toLowerCase();
let blogName = document.getElementsByClassName('.blog-title');

for (let i = 0; i < blogName.length; i++) {
if (!blogName[i].innerHTML.toLowerCase().includes(input)) {
  document.getElementById('search-results').innerHTML = 'no results';
}
else {
  document.getElementById('search-results').innerHTML.blogName[i] = blogName[i];
}
}
};

Example 2

function searchResult() {
const searchInput = document.getElementById('search-i').value;
const blogTitle = document.querySelector('.blog-title');
const search = search-i.value.toLowerCase();

blogTitle.forEach((blogTitle) => {
const itemMatchesSearch = searchResult(blogTitle, search);

if (itemMatchesSearch)
document.getElementById('search-results').innerHTML = `${blogTitle}`;
style.display = 'block';

} else {
document.getElementById('search-results').innerHTML = 'no items found';
style.display = 'block';
});
}

searchResult();

Example 3

function searchResult() {
const input = document.getElementById('search-i').value;
input.toLowerCase();
const blogName = document.getElementsByClassName('.blog-title');

  for (let i = 0; i < blogName.length; i++) {
  if (blogName[i].innerHTML.toLowerCase().includes(input)) {
    document.getElementById('search-results').innerHTML;
    const displayResult = document.createElement('li');
    list.appendChild(displayResult);
    document.getElementById('search-results').innerHTML.appendChild(displayResult) =            blogName[i];
  }
  else {
    document.getElementById('search-results').innerHTML = 'no results found';
    style.display = block;
  }
}};



HTML


<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Finance Blog</title>

<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-   awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>

<body>
<header>
<span class="header">
<h1>Finance Blog</h1>
</span>

    <div class="search-div">
      <form action="searchresults.html" method="get">
     <button type="submit" class="search-button" id="search-b" onclick="searchResult ()"><i class="fa fa-search" style="font-size:24px"></i></button>
      <input type="text" class="search" id="search-i" placeholder="search..." onclick="searchResult ()">
  </form>
    </div>

<nav>
  <ul>
  <li>
   <a href="deals.html" class="nav-bar" id="deals">Deals</a>
  </li>
  <li>
  <a href="free.html" class="nav-bar" id="free">Free</a>
  <li>
    <a href="savingmoney.html" class="nav-bar" id="savingmoney">Saving Money</a>
  </li>
  <li>
    <a href="investing.html" class="nav-bar" id="investing">Investing</a>
  </li>
  <li>
    <a href="makemoney.html" class="nav-bar" id="makemoney">Make Money</a>
  </li>
  <li>
    <a href="recipies.html" class="nav-bar" id="recipes">Recipies</a>
  </li>
  </ul>
  </nav>
  </header>

 <main>
 <section class="blog"> 

 <div class="blog-container">
  <div class="blog-img"><img>
  </div>
  <a href="#"><h2 class="blog-title" id="blog-title">FREE Workouts: My Favorite Fun         Youtube Workout Channel
  </h2>
  </a>
  <p class="blog-copy"></p>
  <span class="time"></span>
</div>

<div class="blog-container">
  <div class="blog-img"><img>
  </div>
  <a href="#"><h2 class="blog-title" id="blog-title">How to Get FREE Coffee Grounds    from Starbucks for Your Garden!
  </h2>
  </a>
  <p class="blog-copy"></p>
  <span class="time"></span>
</div>

<div class="blog-container">
  <div class="blog-img"><img>
  </div>
  <a href="#"><h2 class="blog-title" id="blog-title">My Favorite Simple and Easy Credit Card 
  </h2>
  </a>
  <p class="blog-copy"></p>
  <span class="time"></span>
</div>

</section>


<div class="sidebar">
<aside>
<div><img src="pig.image" alt="pig photo" class="aside-img"/></div>

<br>

<div>
  <p class="aside-p">Sign up to never miss a post!</p>
  <br>
  <form>
  <input type="email" class="aside-input" placeholder="YOUR EMAIL ADDRESS">
  <br>
  <button class="button-submit">SIGN UP</button>
  </form>
</div>

<br>

<div class="social">
<a href="#" class="fa fa-pinterest"></a>
<a href="#" class="fa fa-youtube"></a>
<a href="#" class="fa fa-tiktok"></a>
<a href="#" class="fa fa-instagram"></a>
</div>


</aside>
</div>
</main>


<div class="container-pagination">
<div class="pagination">
    <ul>
    <li><a href="" class="pagination-previous">Previous</a></li>
    <li><a href="">1</a></li>
    <li><a href="">2</a></li>
    <li><a href="">3</a></li>
    <li><a href="" class="pagination-next">Next</a></li>
    </ul>
 </div>
 </div>


<footer>
<div class="social-footer">
<a href="#" class="fa fa-pinterest"></a>
<a href="#" class="fa fa-youtube"></a>
<a href="#" class="fa fa-tiktok"></a>
<a href="#" class="fa fa-instagram"></a>
</div>
<div class="footer-content">
<p><a href="about.html" class="footer-p" id="about">About</a></p>
<br>
<p><a href="contact.html" class="footer-p" id="contact">Contact</a></p>
<br>
<p><a href="privacy.html" class="footer-p" id="privacy">Privacy Policy</a></p>
<br>
<p><a href="terms.html" class="footer-p" id="terms">Terms</a></p>
</div>

<p class="footer-copyright" id="date"></p>
</footer>

<script src="js.js"></script>

</body>

</html>

CSS

* {
margin: 0;
padding: 0;
}

html body { 
overflow: auto; 
height: 100%;
}


body {
height: 100%;
}

header {
display: flex;
}


h1 {
color: #FB6F92;
margin-top: 70px;
margin-left: 40px;
margin-bottom: 10px;
}

.search-div {
position: absolute;
right: 25px;
margin-top: 70px;
display: flex;
}

.search-button {
color:#FB6F92;
margin: 5px;
border: none;
background: none;
padding: 0;

}

.search {
position: relative;
border-color:#FB6F92;
width: 250px;
border-style: solid;
padding: 6px;
border-radius: 25px;
font-size: 16px;
}

nav {
position: fixed;
top: 0px;
width: 100%;
height: 50px;
background-color: #fbe5e5;
font-family: arial;
display: flex;
align-items: center;
justify-content: center;
 }

nav a {
  text-align: center;
  display: inline-block;
}

nav ul li a {
color: #FB6F92;
text-decoration: none;
}

li {
display: inline;
margin: 20px;
}

.nav-bar:hover {
color: gray;
}

main {
display: flex;
 }

.blog {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin-top: 20px;
width: 80%;
}

.blog-container {
display: grid;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: auto auto auto;
grid-auto-rows: 0px;
overflow: hidden;
width: 25%;
margin: 15px;
  }

.blog-title {
color: black;
font-family: 'Times New Roman', Times, serif;
font-size: 20px;
overflow: wrap;
}

.blog-container a {
text-decoration: none;
 }

.blog-img {
display: flex;
justify-content: center;
margin-bottom: 20px;
 }

.next-page {
font-family: Arial;
position: relative;
display: flex;
justify-content: center;
 }

.next-page a {
text-decoration: none;
color: black;
display: flex;
justify-content: center;
position: absolute;
bottom: 0;
}

.sidebar {
position: relative;
display: flex;
flex-grow: 1;
justify-content: center;
margin-top: 35px;
z-index: -100;
}

aside {
color: black;
font-family: arial;
position: sticky;
display: flex;
flex-direction: column;
overflow: auto;
  }

.aside-img {
width: 200px;
height: 200px;
margin-bottom: 30px;
margin-left: 9px;
 }

.aside-p {
font-weight: bold;
font-size: 16px;

}

.aside-input {
margin-bottom: 5px;
width: 209px;
color: black;
border-style: solid;
padding: 5px;
border-color: black;
font-size: 13px;
}

.aside-span {
font-weight: bold;
font-size: 22px;
}

.button-submit {
font-weight: bold;
font-size: 14px;
margin-bottom: 30px;
padding: 6px;
color:#FB6F92;
background-color: #fbe5e5;
width: 223px;
border-style: none;

}

.social a {
color: black;
text-decoration: none;
 }


.container-pagination {
text-align: center;
margin-bottom: 50px;
 }

.container-pagination a {
 color: black;
 text-decoration: none;
 }


footer {
width: 100%;
height: 170px;
bottom: 0px;
font-family: arial;
background-color: #fbe5e5;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
padding-bottom: 70px;

}

.social-footer {
margin-top: 20px;
margin-left: 25px;

}

.social-footer a {
color: black;
text-decoration: none;

}

.footer-content {
grid: 2/4fr;
margin-top: 20px;
margin-bottom: 70px;

}

.footer-copyright {
width: 100%;
bottom: -200px;
text-align: center;
position: absolute;
font-size: 14px;
color: black;
margin-bottom: 25px;

}

.footer-p {
color: black;
text-decoration: none;

}

I attempted to create functions and put them in the DOM.

How to keep the function still working even when the pointer left the element boundaries

I’m trying to create a dropdown list of buttons that only show up when the mouse pointer hover on the first button that is not hidden, and the dropdown list disappear when pointer leave when it no longer hover.
The problem is that I want when the pointer leaves the initial button boundaries, the other buttons still be visible when the pointer hover over them and not disappear.

Note:
i’m still a beginner in JavaScript so please don’t judge my way of explaining the problem or my coding. I’m still learning and hopefully I will get better.

The code:

        const themeBtn = document.getElementById("thBtn");
        const lightBtn = document.getElementById("liBtn");
        const darkBtn = document.getElementById("daBtn");
        const navyBtn = document.getElementById("naBtn");

        themeBtn.addEventListener('pointerenter', () => {
             lightBtn.style.display = "block";
             darkBtn.style.display = "block";
             navyBtn.style.display = "block";



        });
        themeBtn.addEventListener("pointerout", () => {
            lightBtn.style.display = "none";
            darkBtn.style.display = "none";
            navyBtn.style.display = "none";

        });

I’ve tried pointerup and pointerdown and still did’t work.

onTouchMove is firing onTouchEnd on the end of move, even if touch continues

If i do a drag on the screen, even without relese it, at the end of move onTouchEnd is fired, finishing the action. How stop this? I wanna be able to click, move, stop, move again, stop then release.

import styled from "styled-components";

const Container = styled.div`
    width: 400px;
    height: 400px;
    border: 1px solid black;
    background-color: darkgrey;
`;

export default function Touch() {
    return (
        <Container
            onTouchStart={() => console.log("start")}
            onTouchMove={() => console.log("moving")}
            onTouchEnd={() => console.log("released")}
        />
    );
}

How to convert GET request To POST request when using fetch()

I am currently trying to convert my old, insecure, short GET requests to a more modern POST request. I am not sure how to do it.

function fetchData() {
        return fetch(`dataProcessing?action=submit&data=${encryptedFormValue}`)
            .then((response) => response.json())
            .catch(error => {
                console.log(error, 'warn');
            });
    }

I also have a backend for this that receives at dataProcessing.php

} else if ($_GET["action"] == "submit") {
    echo '{"response": "' . processData($_GET["data"]) . '"}';

Does anyone know how to convert this basic function into a POST request from a GET request?

I have tried using ChatGPT, searching on various webpages such as GET vs POST Request: The Difference, and could not find anything useful. What I am currently programming has to be secure since its a message encrypting website and GET requests are just not secure enough. I even tried looking at other stack overflow questions and all of them were so confusing.

How can I implement a timeline using Canvas?

Can the timeline display a maximum of 20 hours, a minimum of 5 seconds, and be scalable, Or are there any ready-made third-party plugins available? Similar to the timeline in video editing software.

I can hardly find available timeline examples in China.

Not able add the innerhtml to display information after recieving it from the

this the code

document.addEventListener("DOMContentLoaded", function() {
    // Function to fetch Lost and Found posts
    function fetchLFPosts() {
        var xhr = new XMLHttpRequest();
        const url = "https://www-student.cse.buffalo.edu/CSE442-542/2024-Spring/cse-442z/LFGlobal.php";
        xhr.open("GET", url, true);
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                var data = JSON.parse(xhr.responseText);
                if (data.LFPosts && data.LFPosts.length > 0) {
                    // console.log(data.LFPosts)
                    var postsContainer = document.getElementById('LFPostsContainer');
                    //postsContainer.innerHTML = ''; // Clear the container before appending new posts
                    data.LFPosts.forEach(post => {
                        let postDiv = document.createElement('div');
                        postDiv.className = 'LFPost';
                        postDiv.innerHTML = '<strong>Title:</strong> ' + post.title +
                            '<br><strong>Description:</strong> ' + post.description +
                            '<br><strong>Date_of_Post:</strong> ' + post.Date_of_Post +
                            '<br><button class="delete-btn">DELETE</button>'; // Add delete button

                        // Attach event listener to delete button
                        var deleteBtn = postDiv.querySelector('.delete-btn');
                        deleteBtn.addEventListener('click', function() {
                            deletePost(post.postid);
                        });

                        postsContainer.appendChild(postDiv);
                    });
                } else {
                    document.getElementById('LFPostsContainer').textContent = 'No Lost and Found posts available.';
                }
            } else if (xhr.readyState == 4) {
                console.error('Error fetching Lost and Found posts:', xhr.statusText);
            }
        };
        xhr.send();
    }
    // Call the fetchLFPosts function
    fetchLFPosts();

    function deletePost(postId) {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "https://www-student.cse.buffalo.edu/CSE442-542/2024-Spring/cse-442z/deleteLFPost.php", true);

        const formData = new FormData();
        formData.append('postId', postId)
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                var response = JSON.parse(xhr.responseText);
                if (response.status === "success") {
                    console.log("Lost and Found post deleted successfully");
                    alert(response.message);
                    window.location.href = 'LostAndFoundGlobal.html'
                } else {
                    console.error('Error deleting Lost and Found post:', response.message);
                    alert(response.message);
                }
            }
        };
        xhr.send(formData);
    }
});

The plan was to get data from the php and add to the html page. I am getting the data but it is not diaplaying the data on the html page.I Have checked and confimred the div and class names are accurate. There are no errors so don’t know what is going wrong

I have already put the console.log to see if the loop is run which it does. the problem has been narrowed down to from perspective to the innnerhtml part. Wanted to know if there is an alternate method to show the data