Show a div when parent is scrollable in any direction

I have a small webapp with an <aside> which is scrollable. As I don’t like how scrollbars are rendered in Windows, even with some CSS hacks, I now just use this to hide them completely:

aside {
    border-right: 1px solid #333333;
    overflow-y: scroll;
    scrollbar-width: none;
}

You can still scroll it with the mouswheel. What I want to display instead of the ugly scrollbar is a separate div at the bottom (if you can scroll down) and/or at the top (if you can scroll up) with a simple arrow. This should only be visible if you hover. Can this be done with CSS only or do I need some javascript to calculate if the aside can be scrolled in either direction?

Product Detail page not routing in vue js

I have a product list page and productdetails page. When I click on the card of the product,it should go to that product detail page with the ID passed, but it doesnt happen.

I have two console.log. One for function viewDetails actually being called. I can see it is called as the log shows. Another log is in the product detail vue. Its in the lifecycle hook of created. But i dont see the log appear in the dev tools.

ProductList.vue

<template>           
  <div id="app">
    <!-- Navbar -->
    <nav class="navbar navbar-light bg-light">
      <div class="container-fluid">
        <a class="navbar-brand" href="#">Intellishop</a>        
      </div>

    </nav>

    <!-- Main Content -->
    
    <div class="container mt-4">
      <h1 class="text-center">Our Products</h1>
      <div class="row">
        <div v-for="product in products" :key="product.id" class="col-lg-3 col-md-4 col-sm-6 mb-4">
          <div class="card" @click="viewDetails(product.id)">
            <img :src="product.image" class="card-img-top product-image" alt="Product Image">
            <div class="card-body">
              <h5 class="card-title">{{ product.item_name }}</h5>
              <p class="card-text">Price: ${{ product.new_price }}</p>
              <p class="card-text">Discount: {{ product.discount }}%</p>
              <p>Seller: {{ product.seller }}</p>
            </div>
          </div>
        </div>
      </div>
    </div>  
      <!-- Pagination Controls -->
      <div class="pagination-container text-center mt-4">
        <button 
          class="btn btn-primary mx-1"
          :disabled="currentPage === 1"
          @click="fetchProducts(currentPage - 1)"
        >
          Previous
        </button>
        
        <span v-for="page in totalPages" :key="page">
          <button 
            class="btn btn-secondary mx-1"
            :class="{ 'btn-primary': page === currentPage }"
            @click="fetchProducts(page)"
          >
            {{ page }}
          </button>
        </span>
        
        <button 
          class="btn btn-primary mx-1"
          :disabled="currentPage === totalPages"
          @click="fetchProducts(currentPage + 1)"
        >
          Next
        </button>
      </div>
    </div>
  
</template>

<script>
import axios from 'axios';
// import LoginModal from "./LoginModal.vue";
// import LoginModal from "./Navbar.vue";
// import Navbar from './Navbar.vue';

export default {
  

  data() {
    return {
      products: [],
      currentPage: 1,
      pageSize: 8,
      totalPages: 0,
    };
  },
  created() {
    this.fetchProducts();
    console.log("i am being called")
  },
  methods: {
    async fetchProducts(page = 1) {
      try {
        const response = await axios.get(`http://127.0.0.1:8000/api/products?page=${page}`);
        this.products = response.data.results || [];
        console.log(this.products)
        this.totalPages = Math.ceil(response.data.count / this.pageSize);
        this.currentPage = page;
      } catch (error) {
        console.error("There was an error fetching the products!", error);
      }
    },
    navigateToLogin() {
      // Replace with your actual login route
      this.$router.push('/login');
    },
    viewDetails(productId) {
      console.log("Navigating to:", `/product/${productId}`);  // Debugging log
      this.$router.push(`/product/${productId}`).catch(err => {
      if (err.name !== "NavigationDuplicated") console.error(err);
      });
    }, 
  }
};

</script>

My index.js inside router folder

import Vue from 'vue';
import VueRouter from 'vue-router';
import ProductDetails from '../components/ProductDetails.vue';

// import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';


Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
  },
  { path: '/product/:id', component: ProductDetails },
];

// const router = createRouter({
//   history: createWebHistory(process.env.BASE_URL),
//   routes,
// });

const router = new VueRouter({
  mode: 'history', // Correct for Vue Router v3
  routes,
});


export default router;

My ProductDetails.vue

<template>
    <div>
      <h1>Product Details</h1>
      <p><strong>Name:</strong> {{ product.item_name }}</p>
      <p><strong>Price:</strong> ${{ product.new_price }}</p>
      <p><strong>Discount:</strong> {{ product.discount }}%</p>
      <p><strong>Seller:</strong> {{ product.seller }}</p>
      <img :src="product.image" alt="Product Image" />
    </div>
  </template>
  
  <script>
  export default {
  data() {
    return {
      product: null, // Start with no product
    };
  },
  created() {
    console.log("ProductDetails component created.");
    this.fetchProductDetails();
  },
  methods: {
    async fetchProductDetails() {
      const productId = this.$route.params.id; // Get ID from the route
      console.log(productId)
      try {
        const response = await axios.get(`http://127.0.0.1:8000/api/products/${productId}`);
        this.product = response.data;
      } catch (error) {
        console.error("Error fetching product details:", error);
      }
    },
  },
};
</script>

What is the problem here?

Explanaion on JavaScript toggle function not work on the first click

Just want an explanation on why First Code is not toggling on the first click unlike the Second code without the OR operator works at first click

first code
toggle button doesn’t work at first click but works the second time

document.getElementById('toggle').addEventListener('click', function() {
  const content = document.getElementById('content');

  if (content.style.display === 'none' || content.style.display === '') {
    content.style.display = 'block';
  } else {
    content.style.display = 'none';
  }
});
<div id='content'>
  Random content.
</div>
<button id='toggle'>Hide</button>

second code
but this one without the “or” operator works on the first click

document.getElementById("toggle").addEventListener("click", function() {
  const content = document.getElementById('content');
  if (content.style.display === 'none') {
    content.style.display = 'block';
  } else {
    content.style.display = 'none';
  }
})
<div id='content'>
  Random content.
</div>
<button id='toggle'>Hide</button>

well removing the OR works and hides the display on first click. But just want an explanation why removing the OR made it work

Unable to focus() an existing WindowClient

I’ve been trying to focus an existing WindowClient from my service worker during onnotificationclick. The problem is, my WindowClient never has the focus property. This functionality is referenced multiple times in the MDN docs:

Notification Click Event Examples

Clients API Examples

Testing on latest Chrome (v132.0.6834.160)

Code derived from the examples in the MDN docs

in index.html

<button id="permission">Ask Permission</button>
<button id="trigger" disabled>Trigger Notification</button>
<script src="index.js"></script>

in index.js

let count = 0;
navigator.serviceWorker.register('sw.js')
permission.onclick = () => Notification.requestPermission()
trigger.onclick = () => {
  navigator.serviceWorker.ready.then(registration => {
    registration.showNotification(`Notification ${++count}`)
  })
}

in sw.js

onnotificationclick = event => {
  event.notification.close()
  event.waitUntil(clients
    .matchAll({
      type: 'window',
    })
    .then((clientList) => {
      for (const client of clientList) {
        // never true!!
        if ('focus' in client) return client.focus()
      }
      if (clients.openWindow) return clients.openWindow('/')
    }),
  )
}

WooCommerce Order Status Not Updating via API in Automation Testing, But Works Manually

We have a plugin called FlexOrder, whose main functionality is to sync WooCommerce orders with Google Sheets and access them there. One of its key features is updating the order status by selecting the dropdown option in the order status column of Google Sheets, and the updated status is then reflected in the corresponding order status in WooCommerce.

I am performing automation testing for our plugin using Playwright and JavaScript. However, I am facing an issue while developing an automation script for a test case.

Scenario:

Using the Google Sheets API, I will update the dropdown option in the order status column, and then I will validate the order status using the WooCommerce API to ensure that the order status is correctly updated in WooCommerce.

Where I am facing the issue:

  • In the first test case: The order status in Google Sheets is being successfully updated.

  • In the second test case: When I try to validate the order using the WooCommerce API, the status is not updating in WooCommerce.

  • Manually checking, the feature works correctly, but it is failing in automation testing.

Error Messages:

Error: expect(received).toBe(expected) // Object.is equality

    Expected: "wc-processing"
    Received: "failed"

      32 |         const wooOrder = await statusUpdater.fetchOrderFromWooCommerce(storedOrder.id);
      33 |         expect(wooOrder.id).toBe(Number(storedOrder.id));
    > 34 |         expect(wooOrder.status).toBe(storedOrder.status);
const { google } = require('googleapis');
const WooCommerceRestApi = require("@woocommerce/woocommerce-rest-api").default;

const updatedOrders = [];
const orderStatuses = ["wc-pending", "wc-processing", "wc-on-hold", "wc-completed", "wc-cancelled", "wc-refunded", "wc-failed", "wc-checkout-draft"];

class OrderStatusUpdater {
    constructor(authConfigPath) {
        this.authConfigPath = authConfigPath;
        this.api = new WooCommerceRestApi({
            url: process.env.SITE_URL,
            consumerKey: process.env.WOOCOMMERCE_CONSUMER_KEY,
            consumerSecret: process.env.WOOCOMMERCE_CONSUMER_SECRET,
            version: 'wc/v3'
        });
    }

    async getAccessToken() {
        const auth = new google.auth.GoogleAuth({
            keyFile: this.authConfigPath,
            scopes: ['https://www.googleapis.com/auth/spreadsheets'],
        });
        const authClient = await auth.getClient();
        const accessToken = await authClient.getAccessToken();
        return accessToken.token;
    }

    async fetchFirstOrder(range) {
        const accessToken = await this.getAccessToken();
        const sheets = google.sheets({ version: 'v4', auth: this.auth });
        const response = await sheets.spreadsheets.values.get({
            spreadsheetId: process.env.GOOGLE_SHEET_ID,
            range,
            headers: {
                Authorization: `Bearer ${accessToken}`,
            },
        });

        return response.data.values ? response.data.values[0] : null;
    }

    async updateOrderStatusInSheet(orderId, newStatus) {
        if (!orderStatuses.includes(newStatus)) {
            throw new Error(`Invalid status: ${newStatus}`);
        }

        const accessToken = await this.getAccessToken();
        const sheets = google.sheets({ version: 'v4', auth: this.auth });
        const range = `Orders!C2`;

        await sheets.spreadsheets.values.update({
            spreadsheetId: process.env.GOOGLE_SHEET_ID,
            range,
            valueInputOption: 'USER_ENTERED',
            resource: {
                values: [[newStatus]]
            },
            headers: {
                Authorization: `Bearer ${accessToken}`,
            },
        });

        updatedOrders.push({ id: orderId, status: newStatus });
        console.log(`Order ID ${orderId} status updated to "${newStatus}" in Google Sheets`);
    }

    async updateDropdownOptions(sheetId) {
        try {
            const sheets = google.sheets({ version: 'v4', auth: await this.auth.getClient() });

            const dataValidationRule = {
                requests: [
                    {
                        setDataValidation: {
                            range: {
                                sheetId: sheetId,   // Sheet ID (not spreadsheet ID)
                                startRowIndex: 1,   // Row where dropdown should start
                                startColumnIndex: 2, // Column where dropdown should be applied
                                endColumnIndex: 3
                            },
                            rule: {
                                condition: {
                                    type: 'ONE_OF_LIST',
                                    values: orderStatuses.map(status => ({ userEnteredValue: status }))
                                },
                                strict: true,
                                showCustomUi: true
                            }
                        }
                    }
                ]
            };

            const response = await sheets.spreadsheets.batchUpdate({
                spreadsheetId: process.env.GOOGLE_SHEET_ID,
                resource: dataValidationRule
            });

            console.log('Dropdown options updated in Google Sheets:', response.data);
        } catch (error) {
            console.error('Error updating dropdown options:', error.message);
        }
    }

    async fetchOrderFromWooCommerce(orderId) {
        try {
            const response = await this.api.get(`orders/${orderId}`);
            return response.data;
        } catch (error) {
            console.error('Error fetching order from WooCommerce:', error.response?.data || error.message);
            throw error;
        }
    }

    getRandomStatus() {
        return orderStatuses[Math.floor(Math.random() * orderStatuses.length)];
    }
}

module.exports = {
    OrderStatusUpdater,
    updatedOrders
};
const { test, expect } = require('@playwright/test');
const { OrderStatusUpdater, updatedOrders } = require('../../test-utils/updateOrderStatus');

test.describe('Google Sheets to WooCommerce Order Status Sync', () => {
    let statusUpdater;

    test.beforeAll(() => {
        statusUpdater = new OrderStatusUpdater('./tests/utilities/upload_key.json');
    });

    test('Update order status in Google Sheets', async ({ page }) => {
        const firstOrder = await statusUpdater.fetchFirstOrder('Orders!A2:Z2');
        const [orderId, , currentStatus] = firstOrder;
        console.log(`Current Status of Order ID ${orderId}: ${currentStatus}`);

        const newStatus = statusUpdater.getRandomStatus();
        await statusUpdater.updateOrderStatusInSheet(orderId, newStatus);
        await page.waitForTimeout(20000);
        const storedOrder = updatedOrders.find(order => order.id === orderId);
        expect(storedOrder).toBeDefined();
        expect(storedOrder.status).toBe(newStatus);

        console.log('Updated Orders Array:', updatedOrders);
    });

    test('Validate updated order status in WooCommerce', async () => {
        const storedOrder = updatedOrders[0];
        expect(storedOrder).toBeDefined();

        const wooOrder = await statusUpdater.fetchOrderFromWooCommerce(storedOrder.id);
        expect(wooOrder.id).toBe(Number(storedOrder.id));
        expect(wooOrder.status).toBe(storedOrder.status);

        console.log(`Order ID ${storedOrder.id} status in WooCommerce: ${wooOrder.status}`);
    });
});

scroll to in the iframe cannot trigger the mouseenter event

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>悬浮效果示例</title>
    <style>
        #A {
            border: 1px solid #000;
            /* 可选:为A div添加边框以便查看 */
            padding: 10px;
        }

        #B {
            height: 600px;
        }

        #B,
        #C {
            margin-bottom: 10px;
            padding: 10px;
            border: 1px solid #ccc;
            /* 可选:为B和C div添加边框以便查看 */
        }

        .child {
            margin-bottom: 5px;
            padding: 10px;
            border: 1px solid #eee;
            /* 可选:为B1, B2, B3 div添加边框以便查看 */
            transition: background-color 0.3s ease;
            /* 添加过渡效果 */
        }

        /* 鼠标悬浮在B1, B2, B3 div上时改变背景颜色 */
        #B1:hover,
        #B2:hover,
        #B3:hover {
            background-color: #007BFF;
            /* 背景颜色变为蓝色 */
            color: #fff;
            /* 文字颜色变为白色 */
        }
    </style>
</head>

<body>
    <div id="A">
        <div id="B">
            <div class="child" id="B1">B1</div>
            <div class="child" id="B2">B2</div>
            <div class="child" id="B3">B3</div>
        </div>
        <div id="C">C</div>
    </div>
    <iframe src="http://localhost:54365" width="100%" height="300px" scrolling="yes"></iframe>
</body>

</html>

http://localhost:54365 The embedded page has the same content as the current page。
hover does not trigger correctly when scrolling over the div of the iframe, but the mouse moves over the div and displays correctly

Want to display the effect correctly, or why is it not

scrollTop for div with image does not scroll to the top of the image

I have some piece of html containing an <ins> element somewhere. I want to show only the <ins> part and possibly some context above and below. My approach is to use a <div> with overflow, setting an appropriate height for the <div> and scrolling the <div> to the appropriate location vertically.
The <ins> might contain images that are higher than the text, and in this case I have trouble getting the scrolling right. This mostly happens if the browser cache is disabled.

As a simple example, assume I have some html with a single <ins> containing a single <img>. For simplicity, assume that I want my new overflow <div> to have the height of the image and that I want to scroll to the top of the image, so that the image vertically fills the <div>. I compute the top position of the image and scroll to it. I therefore expect to see the full image, but instead I see the top of the <ins>.

Example (jsfiddle); open the developer tools and disable the browser cache for reproduction!

const blueprintDiv = document.createElement("div");
blueprintDiv.style.cssText = "border: 1px solid; visibility: hidden;";
blueprintDiv.innerHTML = `<p>BEGIN</p><ins>BB<img src="http://www.google.com/intl/en_ALL/images/logo.gif"></ins><p>END1<br><br><br><br><br><br>END2</p>`;
document.body.appendChild(blueprintDiv);

const imgPromises = [Promise.resolve()];
const img = blueprintDiv.querySelector("img");
if (!img.complete) {
    imgPromises.push(new Promise(resolve => { img.onload = img.onerror = resolve; }));
}

Promise.all(imgPromises).then(() => {
    console.log("All images loaded.");
    const newDiv = document.createElement("div");
    newDiv.style.cssText = `border: 1px solid red; display: block; overflow: auto; height: ${img?.offsetHeight}px`;
    for (const child of blueprintDiv.childNodes) {
        newDiv.appendChild(child.cloneNode(true));
    }

    const insTop = blueprintDiv.querySelector("ins").offsetTop - blueprintDiv.offsetTop;
    const imgTop = img.offsetTop - blueprintDiv.offsetTop;
    const offsetTop = Math.min(insTop, imgTop);

    document.body.textContent = "";
    document.body.appendChild(newDiv);
    newDiv.scrollTop = offsetTop;

    console.log(`Direct ScrollTop: ${newDiv.scrollTop}; offsetTop: ${offsetTop}; insTop: ${insTop}; imgTop: ${imgTop}`);
    setTimeout(() => {
        console.log(`Delayed ScrollTop: ${newDiv.scrollTop}; offsetTop: ${offsetTop}; insTop: ${insTop}; imgTop: ${imgTop}`);
        // newDiv.scrollTop = offsetTop; // Uncomment => correct scrolling
    }, 100);
});

The code waits for the image to load, and then creates my new <div>.

Problem: With the browser cache disabled, instead of scrolling to the top of the image, it scrolls to the BB text. Moreover, the console output is:

"Direct ScrollTop: 52; offsetTop: 52; insTop: 148; imgTop: 52"  
"Delayed ScrollTop: 147; offsetTop: 52; insTop: 148; imgTop: 52"

So, the positions seem right the first time: The <ins> is at 148, the image top is above at 52. So I set scrollTop to 52.
But after a short delay, the browser somehow ends up scrolling automatically to the <ins> position 147 instead of staying at the top of the image at 52.

Uncommenting the second scrollTop fixes the issue, but that seems like a hack to me. Is there a cleaner way to fix this?

What is locked in or resolved in Promise

I can not understand this sentence could you describe it well to me?

You will also hear the term resolved used with promises — this means that the promise is settled or “locked-in” to match the eventual state of another promise, and further resolving or rejecting it has no effect.

It says that the promise is locked in but in the inner promise it can be changed to fulfilled or rejected so it is not locked in. I’m confused about the sentence from MDN.

Why does shops[i][0] return a Firebase key when using Object.entries(snapshot.val())?

I’m using Firebase Realtime Database in JavaScript for the frist time and trying to loop through my data using Object.entries(snapshot.val()). I noticed that when I access shops[i][0], it gives me the Firebase key for each item. I’m not sure why this works.

Here’s my code:

onValue(lists, function(snapshot) {
    if (!snapshot.exists()) {
        console.log("No data found");
        return;
    }
    
    let shops = Object.entries(snapshot.val());
    
    for (let i = 0; i < shops.length; i++) {
        let del = shops[i][0]; // This gives the Firebase key
        console.log(del); // Why does this work?
    }
});

What I Understand:
Object.entries(snapshot.val()) converts my Firebase data into an array of key-value pairs.
shops[i] is one of these pairs.
shops[i][0] gives me the key, but I don’t fully understand how i is working in this case.
Can someone explain how the loop index (i) interacts with Object.entries() and why shops[i][0] gives the key?
if you want here is the full code and tell me how i can refactor it

//ooo
const tr = document.getElementById("tr")
const trs = document.getElementById("clear")
const show = document.getElementById("show")
const text = document.getElementById("text")
const sub = document.getElementById("sub")
  // Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.3.0/firebase-app.js";
import { getDatabase,ref,push,onValue,remove } from "https://www.gstatic.com/firebasejs/11.3.0/firebase-database.js";
  // https://firebase.google.com/docs/web/setup#available-libraries

  // Your web app's Firebase configuration
const firebaseConfig = {
    apiKey: "AIzaSyC9ebhCO9FdQrF2GCnE0vTwYrmik4rvaT8",
    authDomain: "shop-1847a.firebaseapp.com",
    databaseURL: "https://shop-1847a-default-rtdb.asia-southeast1.firebasedatabase.app",
    projectId: "shop-1847a",
    storageBucket: "shop-1847a.firebasestorage.app",
    messagingSenderId: "965005392074",
    appId: "1:965005392074:web:63c1d5058bfdd25ff99c33"
}
const app = initializeApp(firebaseConfig);
const idk = getDatabase(app)
const lists = ref(idk,"shop")
console.log(idk)
function comes(){
    let value = text.value
    push(lists,value )
}
addEventListener("load",function(snapshot){
  if(!snapshot){
    console.log("not found")
  }
  else{
    onValue(lists,function(snapshot){
      show.innerHTML=''
      let shop = Object.values(snapshot.val())
      let shops = Object.entries(snapshot.val())
      for(let i =0; i < shop.length;i++){
        console.log(shop[i])
        console.log(shops[i])
        const ba = document.createElement('label');
        const va = document.createElement('button');
        const b = document.createElement('br')
        va.textContent=shop[i]
        va.id = "te"
        va.addEventListener("click",function(){
          let del = shops[i][0]
          console.log(del)
          let delp = ref(idk,`shop/${del}`)
          remove(delp)
        })
        ba.htmlFor="tr"
        va.textContent=shop[i]
        show.appendChild(va);
        show.appendChild(b)
        show.appendChild(ba)

      }
    })
  }
})
sub.addEventListener("click",function(){
  comes()
  onValue(lists,function(snapshot){
    show.innerHTML=''
    let shops = Object.entries(snapshot.val())
    let shop = Object.values(snapshot.val())
    for(let i =0; i < shop.length;i++){
      console.log(shop[i])
      const ba = document.createElement('label');
      const va = document.createElement('button');
      const b = document.createElement('br')
      va.id = "tr"
      va.addEventListener("click",function(){
        let del = shops[i][0]
        let delp = ref(idk,`shop/${del}`)
        remove(delp)
      })
      ba.htmlFor="tr"
      va.textContent=shop[i]
      show.appendChild(ba)
      show.appendChild(va);
      show.appendChild(b)
    }
  })
})

Issue importing playfab-web-sdk with TypeScript

I’m trying to use the PlayFab SDK for the web in a TypeScript project. I installed the package with:

npm install playfab-web-sdk

Then, when I try to import the module:

import * as PlayFab from "playfab-web-sdk";

I get the following error:

Error: Failed to resolve entry for package "playfab-web-sdk".

I tested importing the playfab-sdk package (which is mainly intended for server-side use) with:

npm install playfab-sdk

This one works fine, and I can import it in my TypeScript code without issues.

I compared the sources of both SDKs:

playfab-sdk seems complete :
https://github.com/PlayFab/NodeSDK/tree/master/PlayFabSdk

playfab-web-sdk looks incomplete (but maybe I’m mistaken?) : https://github.com/PlayFab/JavaScriptSDK/tree/master/PlayFabSdk

Gemini chat history on React

Im stuck. My setChatHistory state is being called twice and data is dublicated. And only place where i use it is in the function below, which is being called by onClick event. I have discovered that it works fine if i remove it from chat settings: const chat = model.startChat({ history: chatHistory, generationConfig: { maxOutputTokens: 3000, }, });

const chat = model.startChat({
            history: chatHistory,
            generationConfig: {
                maxOutputTokens: 3000,
            },
        });
        let modelRes = {};
        try {
            await chat.sendMessage(query).then((value)=> {
                console.log(value)
                modelRes = formatAIText(value.response.text());
            });
        } catch (error) {
            console.error("Error sending message:", error);
        }
        if(modelRes.text) {
            setModelResult(modelRes);
            setChatHistory((prev)=> [
                ...prev,
                { role: "user", parts: [{ text: query }] },
                { role: "model", parts: [{ text: modelRes.text }] }
            ])
        }

i expect it to return not dublicated messages to render it using map.

Scrollbars control, when jumping links?

I have two problems with scrollbar control, which I have incomplete solutions :
First, I want new data to be appended to the previous data when the page scroll to the end ( dont use the request button ).
Secondly, I have iframes on the page whose content is displayed by jumping link ( and it also makes the first problem worse ).
I tried to present my problem with the simplest code to help describe it ( thank you for your time and i appreciate it ) :

index.php :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            /*.divscrollbar {
                -ms-overflow-style: none;
                scrollbar-width: none;
            }
            .divscrollbar::-webkit-scrollbar {
                display: none;
            }*/
            .iframe {
                display: block;
                width: 900px;
                height: 300px;
                margin: 15px auto;
                border-radius: 15px;
                border: 1px solid black;
            }
        </style>
    </head>
    <body>

        <button type="button" onclick="requestdata();">Request data</button>

        <div class="divscrollbar" style="border: 1px solid black;height: calc(100vh - 39px);overflow: auto;">
            <div id="demo"></div>
        </div>

        <script>
            function requestdata() {
                const xhttp = new XMLHttpRequest();
                xhttp.onload = function () {
                    document.getElementById("demo").innerHTML += this.responseText;
                    
                    let allnewdata = document.getElementById("demo").querySelectorAll(".newdata");
                    let lastnewdata = allnewdata[allnewdata.length - 1];
                    setTimeout(() => lastnewdata.scrollIntoView({behavior: "smooth", block: "start"}), 50);
                };
                xhttp.open("POST", "request.php");
                xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                xhttp.send("request");
            }
        </script>

    </body>
</html>

request.php

<?php

if (isset($_POST['request'])) {

    echo '<div class="newdata" style="font-weight: bold;text-align: center;">New Data<iframe class="iframe" src="page.php#red"></iframe><iframe class="iframe" src="page.php#green"></iframe><iframe class="iframe" src="page.php#blue"></iframe></div>';
}
?>

page.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            /*html {
                -ms-overflow-style: none;
                scrollbar-width: none;
            }
            html::-webkit-scrollbar {
                display: none;
            }*/
        </style>
    </head>
    <body>

        <div  style="background: yellow;padding: 15px;margin: 15px;border-radius: 15px;border: 1px solid black;">
            <p style="color: red;margin-top: 300px;" id="red">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
            <p style="color: green;margin-top: 300px;" id="green">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
            <p style="color: blue;margin: 300px 0px;" id="blue">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>

    </body>
</html>

The setTimeout stops working after the third time ( i know i need to increase the time ( 50 to 1000 ) but it’s not a perfect solution ).

Fotorama jQuery plugin Library JavaScript

I have a output It gives me an unwanted result with some images that I uploaded to a website to make or create the fotorama Jquery Plugin Library Javascript, I did the whole process exactly as the instructions indicate in the website jquery and the images are very large and misaligned within my container, I have done several troubleshooting and nothing can be done to adjust the images so that the images are fit the container and reduce them to an appropriate size. Please let me know what I should do in addition to what I have already done. Thanks!

Those are my link and scripts in the head section, I also tried to place one of the scripts at the bottom before the body tag and it didn’t work either, the images continue to be displayed in a size of not fit with the container and excessively large that they cannot be controlled or manipulated.

<link href="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.js"></script>
    <div class="grid content">             
        <div class="section">               
            <h2>Who Are We?</h2>               
            <p class="narrow-paragraph">               
            This is a website that will help you choose travel insurance               
            according to your needs and budget. Travel insurance has different coverage 
            and plans that will help you travel to your destination safely and protected. 
            More than just offering you travel insurance. We give you risk prevention tips.
            </p>             
    <div class="image-wrapper">               
        <div class="fotorama" data-autoplay="true">                 
            <img class="the-image" src="images/placeholder-images/pexels-artem-makarov-         289670876-30454809.jpg" alt="Travel Insurance" loading="lazy">                 
            <img class="the-image" src="images/placeholder-images/pexels-dana-tentis.jpg"   alt="Travel Insurance" loading="lazy">                 
            <img class="the-image" src="images/placeholder-images/pexels-emareynares-18363335.jpg" alt="Travel Insurance" loading="lazy">                 
            <img class="the-image" src="images/placeholder-images/imagen-Web-7.jpg" alt="Country" loading="lazy">               
        </div>             
    </div>               
        <p class="narrow-paragraph">               
        Our service is completely free, we present the various modalities,<em>coverage 
        and benefits</em> so that you can choose the one that best suits your needs and 
        budgets.We help you summarize the general, particular and special conditions of 
        your travel assistance contract, we review and check your certificate, 
        so that everything is in accordance with the quote presented.               
        </p>               
<!--Illustrative video related to the website's insurance activity-->               
    <video controls="controls" poster="images/placeholder-images/airplanetakeoffirlanda.jpg"     width="600" height="600">                 
        <source src="images/placeholder-images/airplanetakeoffirlanda.mp4" 
type="video/mp4">
        <source src="images/placeholder-images/airplanetakeoffirlanda.ogv" 
type="video/ogg">              
    </video>            
    </div>           
        </div>
.grid.content {
  display: flex; /*Use flexbox layout */
  flex-direction: column; /* Arrange items vertically */
  justify-content: center; /* Center items vertically */
  align-content: center; /* Center items horizontally */
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: 10px;
  border: 1px solid #007bff;
  min-height: 300px; /* Ensure the container has some height */
  text-align: center; /* Ensure text is centered */
}
.grid.content {
  grid-column: span 2; /*Each takes up two columns */
  grid-row: auto; /* Auto height based on content */
}
.grid.content .section .narrow-paragraph {
  max-width: 1000px; /* Limit the width for narrow paragraphs */
  margin: 0 auto; /* Center the content horizontally */
  text-align: justify; /* Justify text for better readability */
} 
/* Styling the image wrapper */
.image-wrapper {
  display: flex; /* Use flexbox to control alignment */
  justify-content: center; /* Center the image horizontally */
  align-items: center; /* Center the image vertically */
  margin: 15px 0; /* Add some vertical margin for spacing */
  padding: 10px; /* Add padding around the image */
  background-color: #f0f0f0; /* Light background color */
  border-radius: 10px; /* Consistent border radius */
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle shadow effect */
  max-width: 100%; /* Ensure the wrapper does not exceed the container width */
} 
/* Ensure existing .the-image styles are maintained */
.image-wrapper .the-image {
  width: 100%;
  max-width: 500px;
  height: auto;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  margin-top: 20px;
}
.fotorama {
  width: 100%; /* Ensure the gallery takes the full width of its container */
  height: auto; /* Maintain aspect ratio */
  max-width: 1000px; /* Set a maximum width to prevent it from being too large */
  margin: 0 auto; /* Center the gallery within its container */
}
.fotorama img {
  max-width: 100%; /* Ensure images do not exceed the container width */
  max-height: 100%; /* Allow images to expand based on content */
  height: auto; /* Maintain aspect ratio */
}

Those files did already check up in the tools validators, It’s a part of my code, it’s not the complete code.

I tried to adjust the images with properties of CSS to the size I want them to be set to my preferences and nothing happens, no command or property works to adjust the images, I am applying the rules of the cascade, specificity, inheritance and selectors. Thanks!

Firefox recording blank audio on mobile

I’ve ran into a strange bug with Firefox on mobile where the default media recorder output ogg data of correct length but with no sound.

The code I’m using is essentially copy-pasted from the MDN docs, minus a few state management bits that should not be consequential:

  const startRecording = async () => {
    try {
      set_button_is_loading(true);
      const stream = await window.navigator.mediaDevices.getUserMedia({ audio: true, video: false });
      setAudioStream(stream);
        const mediaRecorder = new MediaRecorder(stream);        
        mediaRecorderRef.current = mediaRecorder;      
        const chunks: BlobPart[] = [];

      mediaRecorder.ondataavailable = (e) => {
        if (e.data.size > 0) {
          if (e.data.type) {
            mime_type.current = e.data.type
          }
          chunks.push(e.data);
        }
      };

      mediaRecorder.onstop = async () => {
        try {
          const blob = new Blob(chunks, { type: mime_type.current });
          let answer = await api_stt(blob, mime_type.current);
          let prev_answer = current_answer;
          if (!prev_answer) {
            prev_answer = "";
          } else if (prev_answer.length > 3) {
            prev_answer = prev_answer + "n";
          }
          set_current_answer(prev_answer + answer);
          set_button_is_loading(false);
        } catch (e) {
          console.error(e)
          set_global_error("Error transcribing audio, please speak clearly.")
          set_button_is_loading(false);
        }
      };

      mediaRecorder.start();
      setIsRecording(true);
      setTimeout(() => {
        set_button_is_loading(false);
      }, 500)
    } catch (err) {
      console.error("Error accessing microphone:", err);
    }
  };

  const stopRecording = () => {
    if (mediaRecorderRef.current && audioStream) {
      set_button_is_loading(true);
      setTimeout(() => {
        if (mediaRecorderRef.current && audioStream) {
          mediaRecorderRef.current.requestData();
          mediaRecorderRef.current!.stop();
          audioStream.getTracks().forEach((track) => track.stop());
          setAudioStream(null);
          setIsRecording(false);
        }
      }, 500)
    }
  };

It works on all browsers except firewfox mobile (all is a stretch, but ff, chrome and safari desktop as well as chrome and safari mobile both android and iOS)

I’ve not figured out a way to “unmuted” the audio stream, the browser reports recording just fine and this is an issue that I’ve noticed across various web audio-recording websites i.e. I assume it might be a recent breaking change that affects a bunch of codebases.

Javascript Popup does not popup on first click

My Javascript popup does not fire up on first click. It does however work on 2nd click.

I cannot find why its failing on first click:

document.querySelector(".chatButtons").addEventListener("click", myFunction);

function myFunction() {

  var chatModal = document.getElementById("myForm");

  if (chatModal.style.display === "none" || chatModal.style.display === " ") {
    chatModal.style.display = "block";

  } else {
    chatModal.style.display = "none";
  }
}
#myForm { display: none; }
<button class="chatButtons">button</button>


<div class="chat-popup" id="myForm">
  <div class="form-container">
  Form here
  </div>
</div>