Why we have to add an ‘async’ declaration word to the javascript function which call a sync javascript function?

I want to know: why we have to add the word:‘async’ declaration to the function which call a sync function? Shouldn’t it be declared as ‘sync’?

Sorry, I am not familiar with ‘async/await’ ,and maybe this is only a basic javascipt grammar question for someone else.

The below code runs well:’I will output FIRST Even I am in BEHIND’ will be outputed first; then,the function ‘add()’ will output ‘3’ after 2 seconds,out ‘4’ after 5 secs,out ‘5’ after 7 secs,then will the sum 12 immediately…

But I am wondering why we have to add a ‘async’ declaration to the function ‘add()’? is this to emphasize that the function itself is an asynchronous function, placed in a piece of JavaScript, it can be executed asynchronously (but its internal execution is synchronous)?**

If I were to write a JavaScript segment codes that all are executed synchronously, would I have to put all the code into a function declared as asynchronous(like below 'sync...add')? and do not use any other statements externally (remove the code line: console.log('I will output FIRST Even I am in BEHIND'))?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>async</title>
</head>
<body>

<script type="text/javascript">


    const asy = function (x, time) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(x)
            }, time)
        })
    }

    const add = async function () {
        const a = await asy(3, 2000)
        console.log(a)
        const b = await asy(4, 5000)
        console.log(b)
        const c = await asy(5, 7000)
        console.log(c)
        const d = a + b + c
        console.log(d)
    }

    add();

    console.log('I will output FIRST Even I am in BEHIND')

</script>


</body>
</html>

After trying to migrate a project from Webpack to Vite, JS code fails to execute

There was a Webpack configuration that I used to build a separate bundle for a JS worker (it must be in a separate file) and everything worked well. Here is the webpack config:

const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
    entry: {
        worker: {
            import: './assets/scripts/worker.ts',
            filename: './worker_bundle.js',
        }
    },
    output: {
        'path': path.resolve(__dirname, 'static', 'js')
    },
    plugins: [
        new webpack.ProvidePlugin({
            Buffer: ['buffer', 'Buffer'],
            process: 'process/browser',
        })
    ],
    resolve: {
        fallback: {
            "assert": require.resolve('assert'),
            "fs": false,
            "util": require.resolve("util"),
            "path": require.resolve("path-browserify")
        },
        extensions: ['.ts', '.js', '.json']
    },
    module: {
        rules: [
            {
                test: RegExp('\.ts$'),
                use: 'ts-loader',
                exclude: RegExp('node_modules')
            }
        ]
    },
    externals: {
        jquery: 'jQuery',
    },
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin({
                extractComments: false,
                terserOptions: {
                    format: {
                        comments: false,
                    },
                },
            }),
        ],
    },
}

Then I learned about the modern JS technology called “Vite”. It compiles much faster than Webpack, but now the bundle wouldn’t execute in the browser no matter what I do.

Here is the new Vite config that builds JS code:

import path from 'path';
import commonjs from '@rollup/plugin-commonjs';
import topLevelAwait from "vite-plugin-top-level-await";
import {nodePolyfills} from "vite-plugin-node-polyfills";


module.exports = {
    plugins: [
        nodePolyfills({
            overrides: {
                fs: 'memfs'
            }
        }),
    ],
    build: {
        minify: false,
        rollupOptions: {
            input: {
                regexes_worker: path.resolve(__dirname, "./assets/scripts/worker.ts"),
            },
            output: [
                {
                    dir: path.resolve(__dirname, 'static/js'),
                    entryFileNames: 'worker_bundle.js',
                    globals: {
                        jquery: '$'
                    },

                    esModule: true
                }
            ],
            plugins: [
                commonjs({
                    filter(id) {
                        if (id.includes('node_modules')) {
                            return true
                        }
                    }
                }),
                topLevelAwait(),
            ]
        },
        emptyOutDir: false
    },
}

The code fails with the following error printed to the devtools console:

Uncaught (in promise) TypeError: Function has non-object prototype 'undefined' in instanceof check

Here is the snippet of the bundle code built with Vite, where the code fails:

function getAugmentedNamespace(n) {
    if (n.__esModule) return n;
    var f = n.default;
    if (typeof f == "function") {
        var a = function a2() {
            if (this instanceof a2 /* !! The execution fails here !! */ ) {
                return Reflect.construct(f, arguments, this.constructor);
            }
            return f.apply(this, arguments);
        };
        a.prototype = f.prototype;
    } else a = {};
    Object.defineProperty(a, "__esModule", {
        value: true
    });
    Object.keys(n).forEach(function (k) {
        var d = Object.getOwnPropertyDescriptor(n, k);
        Object.defineProperty(a, k, d.get ? d : {
            enumerable: true,
            get: function () {
                return n[k];
            }
        });
    });
    return a;
}

I have tried:

  1. compiling bundle with different versions of JS
  2. using various Vite plugins to mimic Webpack functionality
  3. turning on the terser compiler like in Webpack

Nothing helped and now I have no idea what to do.

How to sum the specific column in SheetJs?

I have here an export button wherein I total column of Departments

enter image description here

Currently what I’m trying to do is sum the column of AG from AG:2 to AG:21 wherein the sum will be at A:22.

  const handleExportExcel = () => {
    const data = zoomDataQuery.data.data;
    const month = zoomDataQuery.data.month;
  
    // Get the departments
   const departments = Object.keys(data);
    
    // Get the number of days in the month
   // const daysInMonth = Object.keys(data[departments[0]]).length;
    const daysInMonth = getDaysInMonth(new Date())


    // Create the header row
    const header: (string | number)[] = ["Department", ...Array.from({length: daysInMonth}, (_, i) => i + 1), "Department Total"];
    
    // Create the rows for each department
    const rows: (string | number)[][] = departments.map(dept => {
      const row: (string | number)[] = [dept];
      let deptTotal = 0;
      
      for (let i = 1; i <= daysInMonth; i++) {
        const value = data[dept][i.toString()] || null;
        row.push(value);
        deptTotal += value;
      }
      
      row.push(deptTotal);
      return row;
    });

    

    
    // Create a new workbook and worksheet
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.aoa_to_sheet([header, ...rows]);
    
    // Set column widths
    const colWidth = 5;
    const firstColWidth = 15;
    const lastColWidth = 20;
    ws['!cols'] = [
      { wch: firstColWidth },
      ...Array(daysInMonth).fill({ wch: colWidth }),
      { wch: lastColWidth }
    ];
    
    // Append the worksheet to the workbook
    XLSX.utils.book_append_sheet(wb, ws, "Departments");
    
    // Export the Excel file
    XLSX.writeFile(wb, `${month}_DEPARTMENT_REPORT.xlsx`);
  };

Firestore recursive delete function not deleting nested subcollections?

I’m trying to recursively delete a Firestore document and its subcollections, but I’m running into an issue when the function encounters a nested document that contains subcollections.

Here’s the structure I’m dealing with:

parentCol/uid/childCol_1/child_Doc1
parentCol/uid/childCol_1/child_Doc1/child_Col2/child_Doc2

I’ve written the following recursive delete function, but when it encounters child_Doc1, which has subcollections, it seems to stop and doesn’t delete the nested data under child_Col2. Instead, it just logs the path and doesn’t proceed further.

// parentCol/uid/childCol_1/child_Doc1
// parentCol/uid/childCol_1/child_Doc1/child_Col2/child_Doc2

 const deleteDocumentAndCollections = async (path: string): Promise<void> => {
      try {
        console.log('deletePath:====>', path);
        // Get a reference to the initial document
        const documentRef = firestore.doc(path);

        // List all subcollections under the document to delete
        const subcollections = await documentRef.listCollections();

        console.log('Subcollections:====>', subcollections);

        // Error deleting document and subcollections: Error: Value for argument "documentPath" must point to a document,
        // but was parentCol/uid/childCol_1/
        // Your path does not contain an even number of components.

        // Recursively process and delete each subcollection
        for (const subcollection of subcollections) {
          try {
            // Call the function recursively to delete the subcollection recursively
            await deleteDocumentAndCollections(subcollection.path);
          } catch (error) {
            console.error('Error processing subcollection:', error);
          }
        }

        // Now, delete the document itself
        console.log('Deleting document:', documentRef.path);
        await documentRef.delete();
        console.log('Successfully deleted document:', documentRef.path);
      } catch (error) {
        console.error('Error deleting document and subcollections:', error);
      }
    };

How to load data (csv, json, yaml, parquet or any other data format) in the load function of a fully static (prerendered) SvelteKit application?

I am building a fully static website with SvelteKit. I am using the @sveltejs/adapter-static version 3.0.5.

I want to load inside my webpage a simple table. For various compatibility and shareability reasons, I would like to store this table in a known data format like csv, json, parquet, etc.

First question: Considering the latest design of SvelteKit where should these files live?
Should they live in the static folder? Or in a top-level data folder? Or in a $lib/data folder?

Second question: Once I decided the best place to put these files, what is the intended/best way of loading these files?

My project structure follow the template skeleton:

src/
├── app.html
├── index.test.js
├── lib
│   ├── data
│   │   └── data_1000.csv
│   └── index.js
└── routes
    ├── +layout.js
    ├── +page.js
    └── +page.svelte

The top of +page.svelte looks like:

<script>
    /** @type {import('./$types').PageData} */
    export let data;
</script>

+layout.js looks like:

export const prerender = true;

and +page.js looks like:

/** @type {import('./$types').PageLoad} */
export function load() {
    ...
}

I tried using the fetch API but I got errors related to not being able of using relative routes (I guess it is related to using a file system path instead of a URL) and I couldn’t make the require fs from the Node documentation to work.

window.location.href redirect isn’t working

I am currently trying to create an html sandbox that takes multiple html files and renders it so I can simulate user workflows, however when I load html files into this sandbox, <a href redirects works fine, but in places where the following is required – window.location.href, it seems that the redirect just isn’t working, no matter what I try (been at this for about 7 hours). Please check out the console logs below for the two types of redirects.

For <a href=”login.html”

here's the console log - Navigation requested: login.html
(index):277 Navigating to: login.html
(index):285 Normalized path: login.html
(index):286 Available files: (3) ['main.html', 'signup.html', 'login.html']Navigation requested: login.html
(index):277 Navigating to: login.html
(index):285 Normalized path: login.html
(index):286 Available files: (3) ['main.html', 'signup.html', 'login.html']

In the case of window.location.href = ‘login.html’;
Here’s the console log –

Navigation requested: blob:https://a80a7bb3-0898-46d4-9bbb-1b2bcc5d4ded-00-3lumzhvzacpt5.spock.replit.dev/16865379-f099-4966-8f52-6edc599b9a3e
(index):277 Navigating to: blob:https://a80a7bb3-0898-46d4-9bbb-1b2bcc5d4ded-00-3lumzhvzacpt5.spock.replit.dev/16865379-f099-4966-8f52-6edc599b9a3e
(index):285 Normalized path: blob:https://a80a7bb3-0898-46d4-9bbb-1b2bcc5d4ded-00-3lumzhvzacpt5.spock.replit.dev/16865379-f099-4966-8f52-6edc599b9a3e
(index):286 Available files: (3) ['main.html', 'signup.html', 'login.html']
(index):297 File not found: blob:https://a80a7bb3-0898-46d4-9bbb-1b2bcc5d4ded-00-3lumzhvzacpt5.spock.replit.dev/16865379-f099-4966-8f52-6edc599b9a3e
navigateTo @ (index):297
handleIframeMessage @ (index):269
postMessage
(anonymous) @ 16865379-f099-4966-8f52-6edc599b9a3e:77Understand this error

This shows that <a href seems to be navigating to the actual required index name, but windows.location.href seems to be creating a weird url which doesnt match file name.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Explorer and Preview</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            font-family: Arial, sans-serif;
        }
        .container {
            display: flex;
            height: 100vh;
        }
        .sidebar {
            width: 150px;
            background-color: #f0f0f0;
            padding: 10px;
            box-sizing: border-box;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
        }
        .main-content {
            display: flex;
            flex: 1;
        }
        .code-area {
            width: 30%;
            display: flex;
            flex-direction: column;
        }
        .tabs {
            display: flex;
            background-color: #e0e0e0;
            overflow-x: auto;
        }
        .tab {
            padding: 5px 10px;
            cursor: pointer;
            background-color: #f0f0f0;
            border: none;
            margin: 2px;
            border-radius: 4px;
            font-size: 12px;
        }
        .tab.active {
            background-color: #fff;
        }
        .code-editor {
            flex: 1;
            resize: none;
            width: 100%;
            box-sizing: border-box;
            padding: 10px;
            font-family: monospace;
            font-size: 14px;
            border: none;
            border-right: 1px solid #ccc;
        }
        .preview {
            flex: 1;
            border: none;
        }
        .preview.fullscreen {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: 1000;
        }
        .file-list {
            list-style: none;
            padding-left: 0;
            margin-top: 10px;
            font-size: 12px;
            color: #666;
        }
        .file-list li {
            cursor: pointer;
            padding: 3px 0;
        }
        .file-list li:hover {
            background-color: #e0e0e0;
        }
        .file-input-container {
            margin-bottom: 10px;
        }
        .file-input-button {
            padding: 5px 10px;
            font-size: 12px;
            background-color: #fff;
            border: 1px solid #ccc;
            border-radius: 15px;
            cursor: pointer;
            color: #444;
            width: 100%;
            text-align: center;
        }
        .file-input-text {
            display: block;
            margin-top: 5px;
            font-size: 10px;
            color: #666;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="sidebar">
            <div class="file-input-container">
                <label for="fileInput" class="file-input-button">Upload</label>
                <input type="file" id="fileInput" multiple style="display: none;">
                <span class="file-input-text" id="fileInputText">No files chosen</span>
            </div>
            <ul class="file-list" id="fileList"></ul>
        </div>
        <div class="main-content">
            <div class="code-area">
                <div class="tabs" id="tabs"></div>
                <textarea class="code-editor" id="codeArea" placeholder="Edit your code here..."></textarea>
            </div>
            <iframe class="preview" id="previewFrame" src="about:blank"></iframe>
        </div>
    </div>

    <script>
        const fileList = document.getElementById('fileList');
        const fileInput = document.getElementById('fileInput');
        const fileInputText = document.getElementById('fileInputText');
        const tabs = document.getElementById('tabs');
        const codeArea = document.getElementById('codeArea');
        const previewFrame = document.getElementById('previewFrame');

        let files = {};
        let currentFile = null;

        fileInput.addEventListener('change', (event) => {
            const newFiles = event.target.files;
            if (newFiles.length > 0) {
                fileInputText.textContent = `${newFiles.length} file(s) chosen`;
            } else {
                fileInputText.textContent = 'No files chosen';
            }
            for (let file of newFiles) {
                const reader = new FileReader();
                reader.onload = (e) => {
                    files[file.name] = e.target.result;
                    updateFileList();
                    createTab(file.name);
                };
                reader.readAsDataURL(file);
            }
        });

        function updateFileList() {
            fileList.innerHTML = '';
            for (let fileName in files) {
                const li = document.createElement('li');
                li.textContent = fileName;
                li.onclick = () => openFile(fileName);
                fileList.appendChild(li);
            }
        }

        function createTab(fileName) {
            const tab = document.createElement('button');
            tab.className = 'tab';
            tab.textContent = fileName;
            tab.onclick = () => openFile(fileName);
            tabs.appendChild(tab);
        }

        function openFile(fileName) {
            currentFile = fileName;
            if (isTextFile(fileName)) {
                fetch(files[fileName])
                    .then(res => res.text())
                    .then(text => {
                        codeArea.value = text;
                        updatePreview(fileName);
                    });
            } else {
                codeArea.value = '';
                updatePreview(fileName);
            }
            updateTabs();
            history.pushState({
                file: fileName
            }, '', `#${fileName}`);
        }

        function updateTabs() {
            Array.from(tabs.children).forEach(tab => {
                tab.classList.toggle('active', tab.textContent === currentFile);
            });
        }

        function updatePreview(fileName) {
            const content = files[fileName];
            if (isTextFile(fileName)) {
                const decodedContent = atob(content.split(',')[1]);
                const injectedScript = `
                    <script>
                        document.body.addEventListener('click', (event) => {
                            if (event.target.tagName === 'A') {
                                const href = event.target.getAttribute('href');
                                const isDownload = event.target.hasAttribute('download') || href.match(/\.(zip|pdf|mp4|jpg|png|docx?)$/i);
                                if (isDownload) {
                                    window.parent.postMessage({ type: 'download', url: href }, '*');
                                } else {
                                    event.preventDefault();
                                    window.parent.postMessage({ type: 'navigation', url: href }, '*');
                                }
                            }
                        });
                        window.addEventListener('submit', (event) => {
                            event.preventDefault();
                            const formData = new FormData(event.target);
                            const url = event.target.action || window.location.href;
                            window.parent.postMessage({ type: 'navigation', url: url, formData: Object.fromEntries(formData) }, '*');
                        });
                        const originalAssign = window.location.assign;
                        const originalReplace = window.location.replace;
                        window.location.assign = window.location.replace = (url) => {
                            window.parent.postMessage({ type: 'navigation', url: url }, '*');
                        };
                        Object.defineProperty(window.location, 'href', {
                            set: (url) => {
                                window.parent.postMessage({ type: 'navigation', url: url }, '*');
                            }
                        });
                        function redirectToProcessor(event) {
                            event.preventDefault();
                            window.parent.postMessage({ type: 'navigation', url: 'video-processor.html' }, '*');
                        }
                    </script>
                `;
                const modifiedContent = decodedContent.replace('</body>', `${injectedScript}</body>`);
                const blob = new Blob([modifiedContent], { type: 'text/html' });
                const url = URL.createObjectURL(blob);
                previewFrame.src = url;
            } else {
                previewFrame.src = files[fileName];
            }
        }

        function isTextFile(fileName) {
            return /.(html?|css|js|txt|json|xml|md)$/i.test(fileName);
        }

        codeArea.addEventListener('input', () => {
            if (currentFile && isTextFile(currentFile)) {
                const encodedContent = btoa(unescape(encodeURIComponent(codeArea.value)));
                files[currentFile] = `data:text/html;base64,${encodedContent}`;
                updatePreview(currentFile);
            }
        });

        window.addEventListener('message', handleIframeMessage);

        function handleIframeMessage(event) {
            if (event.data.type === 'navigation') {
                console.log('Navigation requested:', event.data.url);
                navigateTo(event.data.url, event.data.formData);
            } else if (event.data.type === 'download') {
                console.log('Download requested:', event.data.url);
                downloadFile(event.data.url);
            }
        }

        function navigateTo(path, formData) {
            console.log('Navigating to:', path);
            if (!path.startsWith('/') && !path.startsWith('http')) {
                const currentDir = currentFile ? currentFile.split('/').slice(0, -1).join('/') : '';
                path = `${currentDir}${currentDir ? '/' : ''}${path}`;
            }

            path = path.replace(//.//g, '/').replace(//[^/]+/..//g, '/');

            console.log('Normalized path:', path);
            console.log('Available files:', Object.keys(files));

            if (files[path]) {
                if (formData) {
                    console.log('Form submitted:', formData);
                }
                openFile(path);
            } else if (path.startsWith('http')) {
                console.log(`External URL: ${path}`);
                window.open(path, '_blank');
            } else {
                console.error(`File not found: ${path}`);
            }
        }

        function downloadFile(path) {
            if (files[path]) {
                const blob = dataURLToBlob(files[path]);
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = path;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            } else {
                console.error(`File not found for download: ${path}`);
            }
        }

        function dataURLToBlob(dataURL) {
            const parts = dataURL.split(',');
            const mime = parts[0].match(/:(.*?);/)[1];
            const binary = atob(parts[1]);
            const array = [];
            for (let i = 0; i < binary.length; i++) {
                array.push(binary.charCodeAt(i));
            }
            return new Blob([new Uint8Array(array)], { type: mime });
        }

        window.addEventListener('popstate', function(event) {
            if (event.state && event.state.file) {
                openFile(event.state.file);
            } else {
                const fileName = window.location.hash.slice(1);
                if (files[fileName]) {
                    openFile(fileName);
                }
            }
        });

        window.addEventListener('load', () => {
            if (files['index.html']) {
                openFile('index.html');
            }
        });

        // Add fullscreen toggle functionality
        previewFrame.addEventListener('dblclick', () => {
            previewFrame.classList.toggle('fullscreen');
        });
    </script>
</body>
</html>

I have tried multiple things from dataurl to src to blob, none of these seem to work. Only <a href redirects are working, all window.location.href redirects aren’t working.

Perforrm map on a number instead of array

const emptyRow = 3;

How can I map on this if it’s a number and not an array?
something like:

    emptyRow.map(el => {
return (
<div>place items here</div>
)
})

The purpose to this is that I would like to create divs dynamically based on the number of emptyRows.

Codeigniter 3: How to show camera permission when accessing android webview

I’m developing a web application using Codeigniter 3 that needs to take photo of user when signing up.

Everything works very well on desktop browser (Chrome), it could show permission to access webcam but when i try to access on Android web view (Chrome too), nothing shows

i have included

navigator.permissions.query({name: 'camera'})
    .then((permissionObj) => {
     console.log(permissionObj.state);
    })

and

RequestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_CODE)

too but still not a single permission is appearing on android chrome.

is there anyone who facing the same problem or someone who have the solution to solve my problem?

How to pre-select option in dropdown menu with URL

I’m using a dropdown select menu which filters an html table based on the user’s selection. I would like to use the URL of the page to select one of the options. For example, if I go to the following URL: https://www.mywebsite.com/productsDropdown=producta
I would want the dropdown option to be Product A.
I’ve included the HTML and CSS below if it helps
If possible I’d like to be able to use Javascript

 <div class="filter-section">
      <div class="filter">
        <p class="filter-name">Product</p>
        <select class="dropdown" id="productsDropdown" oninput="filterTable()">
          <option>All</option>
          <option>Product A</option>
          <option>Product B</option>
          <option>Product C</option>
        </select>
      </div>
    </div>
    <!-- filter section end -->
    <!-- table start -->
    <table id="myTable">
      <tr class="header">
        <th style="width: 20%">Name</th>
        <th style="width: 40%">Description</th>
        <th style="width: 20%">Product</th>
      </tr>
      <!-- Access Requests start -->
      <!-- row start -->
      <tr>
        <td>
          <a class="request-link" href="#" target="_blank">Request A</a>
        </td>
        <td>Sit amet consectetur adipisicing elit.</td>
        <td>Product A</td>
      </tr>
      <!-- row end -->
      <!-- row start -->
      <tr>
        <td>
          <a class="request-link" href="#" target="_blank">Request B</a>
        </td>
        <td>Modi placeat quos impedit sit optio doloremque veniam expedita?</td>
        <td>Product B</td>
      </tr>
      <!-- row end -->
      <!-- row start -->
      <tr>
        <td>
          <a class="request-link" href="#" target="_blank">Request C</a>
        </td>
        <td>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</td>
        <td>Product C</td>
      </tr>
      <!-- row end -->
    </table>
    <!-- table end -->
#myInput {
  background-image: url("https://www.w3schools.com/css/searchicon.png"); /* Add a search icon to input */
  background-position: 10px 12px; /* Position the search icon */
  background-repeat: no-repeat; /* Do not repeat the icon image */
  width: 100%; /* Full-width */
  font-size: 16px; /* Increase font-size */
  padding: 12px 20px 12px 40px; /* Add some padding */
  border: 1px solid #ddd; /* Add a grey border */
  margin-bottom: 12px; /* Add some space below the input */
}

#myTable {
  border-collapse: collapse; /* Collapse borders */
  width: 100%; /* Full-width */
  border: 1px solid #ddd; /* Add a grey border */
  font-size: 18px; /* Increase font-size */
  /* display: block;
    overflow: auto;
    height: 500px; */
}

#myTable th,
#myTable td {
  text-align: left; /* Left-align text */
  padding: 12px; /* Add padding */
}

#myTable tr {
  /* Add a bottom border to all table rows */
  border-bottom: 1px solid #ddd;
}

#myTable tr.header,
#myTable tr:hover {
  /* Add a grey background color to the table header and on hover */
  background-color: #f1f1f1;
}

.filter-section {
  display: flex;
  margin-bottom: 6px; /* Add some space below the filters */
  gap: 12px; /* Add some space between the filters */
}

.filter-name {
  font-size: 14px; /* Increase font-size */
  color: #666666;
}

.dropdown {
  border: 1px solid #ddd; /* Add a grey border */
  border-radius: 5px;
  font-size: 16px;
  padding: 1px; /* Add padding */
}

.request-link:link,
.request-link:visited {
  text-decoration: none;
  color: #4050c7;
}

.request-link:hover,
.request-link:active {
  color: #4050c7;
}

I’ve tried several solutions I found on Stack exchange and have so far been unsuccessful. I’m hesitate to paste any code here because so far nothing has worked.

Nintendo Wii zoom in animation transition with HTML, CSS and Javascript

I would like to make an animation like the Wii menu transition when you click a channel:

Wii Menu Video (min 0:16)

As you can see, window zooms in to the channel and then the channel page opens. Nothing around the channel distorts, meaning that the channel component isn’t growing in size (I suppose).

It is said that Wii menu is coded on HTML, so it should be possible right?

I tried making the image where you click bigger as the background gets smaller, but the result is far from the original. Also, I couldn’t find a framework or library capable of doing this, not even a website with an animation like this. If you find something, let me know.

Problem with transition in card component in Vue

Hello I have the next component in Vue:

<template>
    <div class="relative w-full h-[800px] flex items-start justify-center overflow-visible">
        <div class="relative w-full max-w-[1800px] h-full">
            <TransitionGroup
                name="carousel"
                tag="div"
                class="relative w-full h-full"
            >
                <div
                    v-for="(card, index) in visibleCards"
                    :key="card.uniqueId"
                    class="absolute top-20 w-[430px] h-[570px] rounded-[20px] border shadow-lg flex items-center justify-center text-2xl font-bold cursor-pointer transition-all duration-500 ease-in-out "
                    :class="[
            index === middleIndex ? 'z-30 bg-white' : 'bg-gray-200',
          ]"
                    :style="getCardStyle(index)"
                    @mouseenter="hoveredCard = index"
                    @mouseleave="hoveredCard = null"
                    @click="selectCard(card.id)"
                >
                    {{ card.content }}
                </div>
            </TransitionGroup>
        </div>
        <button
            @click="previousCard"
            class="absolute left-4 top-1/2 transform -translate-y-1/2 bg-white text-gray-800 rounded-full p-3 shadow-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-400 transition duration-300 z-50"
            aria-label="Previous card"
        >
            <IconArrowLeft class="w-8 h-8" />
        </button>
        <button
            @click="nextCard"
            class="absolute right-4 top-1/2 transform -translate-y-1/2 bg-white text-gray-800 rounded-full p-3 shadow-lg hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-400 transition duration-300 z-50"
            aria-label="Next card"
        >
            <IconArrowRight class="w-8 h-8" />
        </button>
    </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import IconArrowLeft from "@/Components/Icon/IconArrowLeft.vue";
import IconArrowRight from "@/Components/Icon/IconArrowRight.vue";

const cards = ref([
    { id: 1, content: 'Card 1' },
    { id: 2, content: 'Card 2' },
    { id: 3, content: 'Card 3' },
    { id: 4, content: 'Card 4' },
    { id: 5, content: 'Card 5' },
    { id: 6, content: 'Card 6' },
    { id: 7, content: 'Card 7' },
])

const currentIndex = ref(0)
const visibleCardCount = 7
const middleIndex = Math.floor(visibleCardCount / 2)
const hoveredCard = ref(null)

const visibleCards = computed(() => {
    const extendedCards = [...cards.value, ...cards.value, ...cards.value]
    const startIndex = currentIndex.value + cards.value.length - middleIndex
    return extendedCards.slice(startIndex, startIndex + visibleCardCount).map((card, index) => ({
        ...card,
        uniqueId: `${card.id}-${startIndex + index}`,
        displayIndex: index - middleIndex
    }))
})

const getCardStyle = (index: number) => {
    const card = visibleCards.value[index]
    const xOffset = card.displayIndex * 250
    const yOffset = Math.abs(card.displayIndex) ** 1.8 * 15
    const scale = 1 - Math.abs(card.displayIndex) * 0.1
    const rotate = card.displayIndex * 8
    const isHovered = index === hoveredCard.value
    const zIndex = visibleCardCount - Math.abs(card.displayIndex)

    return {
        transform: `
      translateX(calc(-50% + ${xOffset}px))
      translateY(${yOffset}px)
      scale(${isHovered  ? scale * 1.05 : scale})
      rotate(${rotate}deg)
    `,
        left: '50%',
        transformOrigin: 'bottom center',
        zIndex: zIndex,
    }
}

const nextCard = () => {
    currentIndex.value = (currentIndex.value + 1) % cards.value.length
}

const previousCard = () => {
    currentIndex.value = (currentIndex.value - 1 + cards.value.length) % cards.value.length
}

const selectCard = (id: number) => {
    const selectedIndex = cards.value.findIndex(card => card.id === id)
    if (selectedIndex !== -1) {
        const diff = selectedIndex - currentIndex.value
        const shortestPath = ((diff + cards.value.length / 2) % cards.value.length) - cards.value.length / 2
        currentIndex.value = (currentIndex.value + Math.round(shortestPath) + cards.value.length) % cards.value.length
    }
}
</script>

<style scoped>
.carousel-move {
    transition: all 0.5s ease-in-out;
}
.carousel-enter-active,
.carousel-leave-active {
    transition: all 0.5s ease-in-out;
}
.carousel-enter-from {
    opacity: 0;
    transform: translateX(100%) translateY(100px) scale(0.75) rotate(10deg);
}
.carousel-leave-to {
    opacity: 0;
    transform: translateX(-100%) translateY(100px) scale(0.75) rotate(-10deg);
}
</style>

It show a list of cards and it is working perfectly except with some bugs that I cant figure out how to solve.

When I pass from the first card (1) to last card (7) it show a break or an weird transition. I wanna the same transition if I pass from card 1 to card 2, or card 4 to card 3.

Thanks!

Jest test failing due to initial null values

everyone. I’m preparing a test for a page on my website in NextJS, and in that page I’m supposed to be doing a fetch call to an /api route by means of a hook. This route executes a query that fetches data from a SQLite database, which is then returned to the page to populate it with the data. My page looks like this:

'use client';

import { useParams } from 'next/navigation';
import AssetButton from '@/components/AssetButton';
import AssetInfo from '@/components/AssetInfo';
import AssetLogo from '@/components/AssetLogo';
import AssetScreenshot from '@/components/AssetScreenshot';
import Details from '@/components/Details';
import Loader from '@/components/Loader';
import Page from '@/components/Page';
import Text from '@/components/Text';
import useFetchData from '@/hooks/useFetchData';
import { Asset } from '@/utils/types';

export default function ProgramDetails() {
  const params = useParams();
  const { id } = params;

  const {
    data: program,
    loading,
    error,
  } = useFetchData<Asset>(`/api/programs/${id}`);

  const errorData = <p>{error}</p>;

  const isDownload = !program?.link?.includes('https://');

  return (
    <Page>
      {loading ? (
        <Loader />
      ) : error ? (
        errorData
      ) : (
        <>
          <AssetLogo icon={program!.icon} />
          <Text content={program!.name?.toUpperCase()} type="title" />
          <Text content={program!.description} type="body" />
          <AssetInfo>
            <AssetScreenshot file={program!.icon} />
            <Details details={program!.details?.split(';')} />
          </AssetInfo>
          <AssetButton isDownload={isDownload} link={program!.link} />
        </>
      )}
    </Page>
  );
}

Where I use the useFetchData hook to be able to tell when the api call is loading and when it gets data, so I can render a loader while the data is fetched. The hook looks like this:

import { useState, useEffect } from 'react';

const useFetchData = <T>(url: string) => {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      fetch(url)
        .then(async (res) => {
          const data = await res.json();

          if (data) {
            setData(data);
          } else {
            setError('An unknown error has occurred');
          }
        })
        .catch((err) => {
          setError(err.message);
        })
        .finally(() => {
          setLoading(false);
        });
    };
    fetchData();
  }, [url]);

  return { data, loading, error };
};

export default useFetchData;

and the api route /api/programs/[id] looks like this:

import { NextResponse } from 'next/server';
import openDb from '@/utils/db';

export async function GET(
  request: Request,
  { params }: { params: { id: string } },
) {
  const db = openDb();
  const { id } = params;
  const program = db.prepare('SELECT * FROM programs WHERE id = ?').get(id);

  if (!program) {
    return NextResponse.json({ error: 'Program not found' }, { status: 404 });
  }

  return NextResponse.json(program);
}

so the test is meant to mock a fetch call to return dummy data and check that the dummy data renders:

import { useParams } from 'next/navigation';
import { render, screen, waitFor } from '@testing-library/react';
import ProgramDetails from '@/app/programs/[id]/page';
import { ViewportProvider } from '@/context/ViewportContext';

const mockProgramData = [
  {
    id: 1,
    name: 'Program 1',
    icon: 'icon1.png',
    description: 'Description for Program 1',
    details: ['detail 1', 'detail 2'],
    link: '/downloads/test.zip',
  },
];

jest.mock('next/navigation', () => ({
  useParams: jest.fn().mockReturnValue({ id: '1' }),
}));

describe('Program Details Page', () => {
  beforeEach(() => {
    global.fetch = jest.fn(() =>
      Promise.resolve({
        json: () => Promise.resolve(mockProgramData),
      }),
    ) as jest.Mock;
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  it('renders the program title, description, and details correctly', async () => {
    render(
      <ViewportProvider>
        <ProgramDetails />
      </ViewportProvider>,
    );

    await waitFor(() => {
      expect(screen.queryByTestId('triple-spinner')).not.toBeInTheDocument();
    });

    const title = await screen.findByTestId('text-title');
    expect(title).toBeInTheDocument();
    expect(title).toHaveTextContent(mockProgramData[0].name);

    const body = await screen.findByTestId('text-body');
    expect(body).toBeInTheDocument();
    expect(body).toHaveTextContent(mockProgramData[0].description);

    await waitFor(() => {
      mockProgramData[0].details.forEach((currDetail) => {
        expect(screen.getByText(currDetail)).toBeInTheDocument();
        expect(screen.getByText(currDetail)).toBeInTheDocument();
      });
    });
  });
});

at first I was assuming that, waiting for the loader’s test id to not render would be enough to ensure the data is rendering. Just in case the loader looks like this:

import styles from './Loader.module.css';

const Loader: React.FC = () => {
  return (
    <div data-testid="loader" id={styles.loader}>
      <div
        className={styles['triple-spinner']}
        data-testid="triple-spinner"
      ></div>
    </div>
  );
};

export default Loader;

Then, I would get the other elements by test id exist, and check if the text has rendered and matches. The Text component that has these ids is this:

import styles from './Text.module.css';

interface TextProps {
  content: string;
  type: 'body' | 'card' | 'hero' | 'modal' | 'title';
}

const Text: React.FC<TextProps> = ({ content, type }) => {
  return type === 'title' ? (
    <h3 className={styles[type]} data-testid="text-title">
      {content}
    </h3>
  ) : (
    <p className={styles[type]} data-testid="text-body">
      {content}
    </p>
  );
};

export default Text;

But as I run the test, I get this error:

expect(element).toHaveTextContent()

    Expected element to have text content:
      Program 1
    Received:

      45 |     const title = await screen.findByTestId('text-title');
      46 |     expect(title).toBeInTheDocument();
    > 47 |     expect(title).toHaveTextContent(mockProgramData[0].name);
         |                   ^
      48 |
      49 |     const body = await screen.findByTestId('text-body');
    ```

    Since nothing shows, I tried printing the results of the fetch call in the hook, and I saw two iterations: one where the returned data is null, and another with the test data. So what I appear to need is to be able to skip that first call to ensure I can work with the actual returned data, but how can I accomplish that?

How to choose which columns are used in Google Visualization chart and avoid ‘All series on a given axis must be of the same data type’ error

I’m trying to use various columns on a spreadsheet to chart running durations and try different styles by using Google Charts. I have problems when I try to query more than 2 columns. I want to use one column (B, for example) for attribution text, or labels, above the points on the graph. But when I use ‘SELECT A, B, D’, I get an error of ‘All series on a given axis must be of the same data type’. How can I query/load multiple columns but only use the ones I choose as series in the chart? It looks like it automatically uses all for a series, so I think it’s trying to plot a string and a date on the x axis. Successful chart (querying just column A and D), spreadsheet, and code are below. Thanks for any help.

I did try to implement the suggestion from this post but without success. I wasn’t sure how to implement it with 3 columns vs. 2. Any help on that end would be much appreciated.

enter image description here

enter image description here

<html>
  <head>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js">
   
      google.charts.load('current', {'packages':['corechart']});
      google.charts.setOnLoadCallback(drawChart);



     function drawChart() {
      var queryString = encodeURIComponent('SELECT A, D');

      var query = new google.visualization.Query(
          'https://docs.google.com/spreadsheets/d/1xRV24c1itTkK1OWLo3KdpVhkjXpuMzi8lXi4UFHanso/gviz/tq?sheet=Sheet1&headers=1&tq=' + queryString);
      query.send(handleSampleDataQueryResponse);
    }

    function handleSampleDataQueryResponse(response) {
      if (response.isError()) {
        alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
        return;
      }
 

     


      var data = response.getDataTable();

     
         var options = {
          title: 'L's 2024 Cross Country Run Times ',
          
      
          width: 900,
          height: 500,
          trendlines: {
      0: {
        color: 'blue',
        
      }
    },
          vAxis: {
            format: 'mm:ss'
            
          }
          
        };





      var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
      chart.draw(data, options);
    }

    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 500px;"></div>
  </body>
</html>

how will I sort the list section in the css section side by side

I tried this code

i tried to make a website, everything was very nice, but the list part doesn’t come side by side, I wrote all the codes, it didn’t happen somehow, I was sure I did everything right, please, I’d be glad if you could help

.menu ul li a {
    text-decoration: none;
    color: #fff;
    font-size: 18px;
    font-weight: 500;
    padding: 8px 15px;
    border-radius: 50px;
    transition: all 0.3s ease;
}

also i write this code in html

nav .menu {
    max-width: 1200px;
    margin: auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 20px;
}

Combine upload image with chart.js

Is it possible to upload an image and then use it as a background in Chart.JS? I found two separate codes but cannot combine them. It is possible to combine the two codes?

window.addEventListener('load', function() {
  document.querySelector('input[type="file"]').addEventListener('change', function() {
      if (this.files && this.files[0]) {
          var img = document.querySelector('img');
          img.onload = () => {
              URL.revokeObjectURL(img.src);  // no longer needed, free memory
          }
          img.src = URL.createObjectURL(this.files[0]); // set src to blob url

              }
      });
});

const image = new Image();
image.src = 'https://www.chartjs.org/img/chartjs-logo.svg';

const options = {
  type: 'line',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
      label: '# of Votes',
      data: [12, 19, 3, 5, 2, 3],
      borderColor: "pink"
    }]
  },
  options: {},
  plugins: [{
    id: 'customImage',
    beforeDraw: (chart) => {
      if (image.complete) {
        const ctx = chart.ctx;
        const {
          top,
          left,
          width,
          height
        } = chart.chartArea;
        const x = left + width - image.width;
        const y = top + height - image.height;
        ctx.drawImage(image, x, y);
      } else {
        image.onload = () => chart.draw();
      }
    }

  }]
}

const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
        

    
<input type='file' />
<br><img id="myImg" src="#">
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.1/chart.js"></script>
</body>