How to Display Smooth, Continuous File Processing Progress?

I’m building an Electron app where I need to process large files/folders by splitting them into smaller chunks (ex: 512MB each) and display real-time progress to the user. However, the progress percentage displayed in the console updates irregularly and jumps in large increments (30% → 57% → 91% → 100%).
I would like the progress updates to appear smoother and more gradual, such as 0% → 1% → 2% → … → 100%.

How can I implement smoother progress updates, where the progress percentage increases gradually and consistently, even for large chunk sizes?

Are there any best practices or common techniques for handling smoother progress updates in scenarios like this?

I would like to avoid unnecessary overhead, such as reducing chunk sizes or splitting smaller sub-chunks, if possible.

I’m using Electron, Node.js, and fs for file operations. Any advice or code snippets would be greatly appreciated!

Here’s a simplified version of my code for splitting files into chunks:

const fs = require("fs");
const path = require("path");

async function splitFile(filePath, chunkSize) {
  return new Promise((resolve, reject) => {
    const chunks = [];
    const stream = fs.createReadStream(filePath, { highWaterMark: chunkSize });

    let totalSize = 0;
    let processedSize = 0;

    fs.stat(filePath, (err, stats) => {
      if (err) return reject(err);
      totalSize = stats.size;

      let chunkIndex = 0;

      stream.on("data", (chunk) => {
        const chunkFilePath = `${filePath}.chunk_${chunkIndex + 1}`;
        fs.writeFileSync(chunkFilePath, chunk);
        chunks.push(chunkFilePath);

        processedSize += chunk.length;
        const progress = ((processedSize / totalSize) * 100).toFixed(2);
        console.log(`Progress: ${progress}%`);

        chunkIndex++;
      });

      stream.on("end", () => {
        console.log(`File successfully split into ${chunks.length} chunks.`);
        resolve(chunks);
      });

      stream.on("error", reject);
    });
  });
}

async function main() {
  const filePath = path.resolve(__dirname, "largeFile.mkv");
  const chunkSize = 512 * 1024 * 1024;
  console.log(`Starting to split file: ${filePath}`);
  try {
    const chunks = await splitFile(filePath, chunkSize);
    console.log("Chunks saved to disk:");
    chunks.forEach((chunkFilePath) => console.log(chunkFilePath));
  } catch (error) {
    console.error("Error:", error.message);
  }
}

main();

Fastest algorithm to search via keywords on static website?

I’m hosting a static website on github pages (without jekyll) and I’d like to implement a search feature on client side

I have keywords each pointing towards a link as such:

search_map={
  
  ["keyword1", "keyword4"] : "link1",
  ["keyword1", "keyword2", "keyword3"] : "link2",
  ["keyword5", "keyword3"] : "link3"
  ...
}

search_query = ["keyword1", "keyword6"]

results = ["link1", "link3"]

My current approach has been to flatten out all keys and duplicate links instead and send a single object to client side to search:

{
  "keyword1" : ["link1", "link2"],
  "keyword2" : ["link2"],
  "keyword3" : ["link2", "link3"],
  "keyword4" : ["link1"],
  "keyword5" : ["link3"],
  ...
}

is there any better and faster way to do this?

Nothing happened when I click on button in a Web project

I have this button in HTML:

<div id="login">
    <img src="/resource/image_header/login.png" alt="Login">                
    <div class="cd-main-nav js-main-nav">
        <button id="welcome-text" type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="bottom" title=""></button>
        <ul id="login-signup" class="cd-main-nav__list js-signin-modal-trigger">
            <li><a id="logInButton" class="cd-main-nav__item js-signin-modal-trigger cd-main-nav__item--signin" data-type="login" data-signin="login">Đăng nhập</a></li>            
        </ul>
    </div>
</div>

and a pop-up modal for login form:

<div id="login-popup" class="cd-signin-modal js-signin-modal">   
    <div class="cd-signin-modal__container">        
        <ul class="cd-signin-modal__switcher js-signin-modal-switcher js-signin-modal-trigger">
            <li><a data-signin="login" data-type="login" style="font-weight: bold;">Đăng nhập</a></li>
        </ul>

        <div class="cd-signin-modal__block js-signin-modal-block" data-type="login">
            <!-- log in form -->
            <form id="loginForm" class="cd-signin-modal__form">
                <p class="cd-signin-modal__fieldset">
                    <label class="cd-signin-modal__label cd-signin-modal__label--email cd-signin-modal__label--image-replace" for="signin-email">Tên đăng nhập</label>
                    <input class="cd-signin-modal__input cd-signin-modal__input--full-width cd-signin-modal__input--has-padding cd-signin-modal__input--has-border" id="signin-email" type="text" placeholder="Tên đăng nhập">
                    <span class="cd-signin-modal__error">Bạn chưa nhập tên đăng nhập!</span>
                </p>

                <p class="cd-signin-modal__fieldset">
                    <label class="cd-signin-modal__label cd-signin-modal__label--password cd-signin-modal__label--image-replace" for="signin-password">Mật khẩu</label>
                    <input class="cd-signin-modal__input cd-signin-modal__input--full-width cd-signin-modal__input--has-padding cd-signin-modal__input--has-border" id="signin-password" type="password" placeholder="Mật khẩu">
                    <span class="cd-signin-modal__error">Bạn chưa nhập mật khẩu!</span>
                </p>

                <p class="cd-signin-modal__fieldset">
                    <input type="checkbox" id="remember-me" checked class="cd-signin-modal__input ">
                    <label for="remember-me">Ghi nhớ</label>
                </p>

                <p class="cd-signin-modal__fieldset">
                    <input id="loginButton" class="cd-signin-modal__input cd-signin-modal__input--full-width" type="submit" value="Đăng nhập">
                </p>
            </form>

            <p class="cd-signin-modal__bottom-message js-signin-modal-trigger">Bạn chưa có tài khoản?<a id="signupButton" href="javascript:void(0)">Đăng ký ngay</a></p>
        </div> <!-- cd-signin-modal__block -->
    </div>
</div>

This is javascript to open the form when clicking the button id=”logInButton”:

function ModalSignin(element) {
    this.element = element;
    this.blocks = this.element.getElementsByClassName('js-signin-modal-block');
    this.switchers = this.element.getElementsByClassName('js-signin-modal-switcher')[0].getElementsByTagName('a');
    this.triggers = document.getElementsByClassName('js-signin-modal-trigger');
    this.hidePassword = this.element.getElementsByClassName('js-hide-password');
    this.init();
    };
    
    ModalSignin.prototype.init = function () {
        var self = this;
        //open modal/switch form
        for (var i = 0; i < this.triggers.length; i++) {
            (function (i) {
                self.triggers[i].addEventListener('click', function (event) {
                    if (event.target.hasAttribute('data-signin')) {
                        event.preventDefault();
                        self.showSigninForm(event.target.getAttribute('data-signin'));
                    }
                });
            })(i);
        }
    }

I tried to debug by console.log("Clicked!") when clicking the button but the event did not happen. Is the button blocked somewhere?

x-date-formatters Missing “./_lib/format/longFormatters” specifier in “date-fns” package [plugin vite:dep-pre-bundle]

I’ve got a form and I’m trying to setup the x-date-formatters package with React and Mui. Anyone know how to fix this?

Error is:

Missing "./_lib/format/longFormatters" specifier in "date-fns" package [plugin vite:dep-pre-bundle]

The odd thing to me is that longFormatters.?? exists in the project node_modules:

# find ./ -name '*longFormatters*'
./node_modules/date-fns/_lib/format/longFormatters.js
./node_modules/date-fns/_lib/format/longFormatters.cjs
./node_modules/date-fns/_lib/format/longFormatters.d.cts
./node_modules/date-fns/_lib/format/longFormatters.d.ts

Edited to add:

This should resolve because the vite docs say:
(from https://vite.dev/config/shared-options#resolve-extensions)

resolve.extensions

    Type: string[]
    Default: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']

List of file extensions to try for imports that omit extensions. Note it is NOT recommended to omit extensions for custom import types (e.g. .vue) since it can interfere with IDE and type support.

and my vite.config.js is:

import {defineConfig} from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
    plugins: [react()]
})

End edit
Storybook preview.tsx:

import type {Preview} from "@storybook/react";
import {MemoryRouter as Router, Route, Routes} from "react-router";
import UserContext, {LOGGED_OUT_USER_CONTEXT} from "../src/context/UserContext";
import {LocalizationProvider} from '@mui/x-date-pickers';
import {AdapterMoment} from '@mui/x-date-pickers/AdapterMoment';

const preview: Preview = {
    decorators: [
        (Story, {parameters}) => {
            const {routerPath = "/"} = parameters;
            const {userInfo = LOGGED_OUT_USER_CONTEXT} = parameters;
            const setCurrentUser = () => {
                return;
            }
            return (
                <LocalizationProvider dateAdapter={AdapterMoment}>
                    <UserContext.Provider
                        value={{
                            currentUser: userInfo,
                            setCurrentUser
                        }}
                    >
                        <Router>
                            <Routes>
                                <Route path={routerPath} element={<Story/>}>
                                </Route>
                            </Routes>
                        </Router>
                    </UserContext.Provider>
                </LocalizationProvider>
            )
        },
    ],
    parameters: {
        controls: {
            matchers: {
                color: /(background|color)$/i,
                date: /Date$/i,
            },
        },
    },
};

export default preview;

package.json:

{
  "name": "i-web",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "api-client-gen": "java -jar ~/bin/openapi-generator-cli-7.10.0.jar generate -i http://localhost:8080/v3/api-docs -g typescript-fetch -o src/itr-client/"
  },
  "dependencies": {
    "@emotion/react": "^11.14.0",
    "@emotion/styled": "^11.14.0",
    "@fontsource/roboto": "^5.1.0",
    "@mui/icons-material": "^6.2.0",
    "@mui/material": "^6.2.0",
    "@mui/system": "^6.2.0",
    "@mui/x-date-pickers": "^7.23.2",
    "date-fns": "^4.1.0",
    "moment": "^2.30.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.54.1",
    "react-router": "^7.0.2"
  },
  "devDependencies": {
    "@chromatic-com/storybook": "^3.2.2",
    "@eslint/js": "^9.15.0",
    "@storybook/addon-essentials": "^8.4.7",
    "@storybook/addon-interactions": "^8.4.7",
    "@storybook/addon-onboarding": "^8.4.7",
    "@storybook/blocks": "^8.4.7",
    "@storybook/react": "^8.4.7",
    "@storybook/react-vite": "^8.4.7",
    "@storybook/test": "^8.4.7",
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.4",
    "eslint": "^9.15.0",
    "eslint-plugin-react-hooks": "^5.0.0",
    "eslint-plugin-react-refresh": "^0.4.14",
    "eslint-plugin-storybook": "^0.11.1",
    "globals": "^15.12.0",
    "storybook": "^8.4.7",
    "typescript": "~5.6.2",
    "typescript-eslint": "^8.15.0",
    "vite": "^6.0.1"
  },
  "eslintConfig": {
    "extends": [
      "plugin:storybook/recommended"
    ]
  }
}

How can I change “in cart” text of Woocommerce block button?

The default behaviour of a Woocommerce AddToCart Button is to first show “Add to Cart”. Once clicked, it will go to a Loading State and Checks the ajax request, then shows “in cart {number}”.

I couldn’t find any action/filter to hook into. I can change the “Add to Cart” text in many different ways: hooks, translations, CSS, etc. But for the latter state, JavaScript is in charge, and, as a result even translation doesn’t work.

While I very much like this functionality, I have to find a way to replace “in cart” with an icon while keeping the {number} part.

Please let me know if you have robust and clean way of doing this.

Thank you in advance.

I tried reproducing the very structure of the html, even the wp-data attributes, but I couldn’t get far, since after replacing this with the default woocommerce html, the interactivity is gone.

I’m not that good at Javascript, but as ugly as it seems, I even tried to change it with a script that looks for the addedtocart event, and changes the text. In vain…

The obvious way is to create a customized button from scratch but I won’t be able to do it at this moment because I have other requirements to deliver.

I also tried whatever Chatgpt had to offer with its vast knowledge, to no success.

How to get Steam Wishlist info of another user?

As of November 2024, Steam has deprecated the old way of using

https://store.steampowered.com/wishlist/profiles/${steamID}/wishlistdata/
https://store.steampowered.com/wishlist/id/${steamID}/wishlistdata

Now it redirect to the main page.

Is there any different method to get wishlist data for user? Anything that doesn’t involve headless browser for scraping?

Javascript JSON body unreadable without keys being in double quotes

I have the following problem on hand:
If i try to send a json to an api with the following style it works fine:

{ "key": "value", "key": value }

if I am using the following format, the u seemingly always get with JavaScript it does not work:

{ key: "value", key: value }

JSON.stringify also does not work as it seems to need a object not a string

read and modify a Checkbox inside WebView2 through C# code, JavaScript ExecuteScriptAsync function

I have a small application in c# with an external html page that is displayed in webView2.

I want to read and modify the state of a Checkbox inside an external page displayed in WebView2 through C# code, JavaScript must be executed using WebView2’s ExecuteScriptAsync function.
html page inside webView2 has the following checkbox:

<input type="checkbox" id="startcheckwhenopenbox" name="startcheckwhenopenbox" checked>

The value (isAutoStartEnabled ) of the checkbox is fetched from the sqlite database.
The first part does not work: if isAutoStartEnabled equals true the c# code must changes the checkbox inside webView2 to checked and if false it changes it to unchecked.
The second part works: when you click on the checkbox inside webView2 it saves the value in the sqlite database.
This is the important part of the code:

private void InitializeAsyncButtomButtons()
{
    string dashUrl = Path.GetFullPath(
        Path.Combine(AppContext.BaseDirectory, @"../../web/bottombuttons.html")
    );
    //MessageBox.Show(dashUrl);
    //Environment.Exit(0);
    if (File.Exists(dashUrl) && Uri.TryCreate(dashUrl, UriKind.Absolute, out Uri uri))
    {
        try
        {
            webViewBottomButtons.Source = new Uri(dashUrl);
            //webBrowser.Navigate(new Uri(dashUrl));
            //webViewBottomButtons.NavigateToString(File.ReadAllText(dashUrl)); // تحميل محتوى HTML من الملف
            //webViewBottomButtons.Source = new Uri("https://adminlte.io/themes/v3/pages/tables/simple.html");

            //await webViewBottomButtons.CoreWebView2.ExecuteScriptAsync("alert('Hello from C#');");
        }
        catch (System.UriFormatException)
        {
            return;
        }
    }
    else
    {
        //MessageBox.Show("Error loading page, please check page URL.");
    }

    webViewBottomButtons.NavigationCompleted += async (s, ee) =>
    {
        //webViewBottomButtons.CoreWebView2.OpenDevToolsWindow();

        // read autoStart value from sqlite database
        bool isAutoStartEnabled = GetAutoStartFromDatabase();
        //MessageBox.Show("isAutoStartEnabled: " + isAutoStartEnabled);

        var script =
        @"
            // التعامل مع Checkbox
            const checkbox = document.querySelector('input[name=""startcheckwhenopenbox""]');
            if (checkbox) {{
                //console.log(document.querySelector('input[name=""startcheckwhenopenbox""]'));
                //checkbox.checked = {isAutoStartEnabled.ToString().ToLower()};
                //console.log('Checkbox initialized with value: ' + checkbox.checked);
                checkbox.addEventListener('change', () => {{
                    const isChecked = checkbox.checked;
                    window.chrome.webview.postMessage(isChecked ? 'CheckboxChecked' : 'CheckboxUnchecked');
                }});
            }}

            // التعامل مع Label
            const label1 = document.querySelector('label[name=""startcheckwhenopen""]');
            if (label1) {
                label1.addEventListener('mouseover', () => {
                    window.chrome.webview.postMessage('MouseOverLabel');
                });
                label1.addEventListener('mouseout', () => {
                    window.chrome.webview.postMessage('MouseOutLabel');
                });
                label1.addEventListener('mouseleave', () => {
                    window.chrome.webview.postMessage('MouseOutLabel');
                });
                label1.addEventListener('mousedown', () => {
                    window.chrome.webview.postMessage('MouseDownLabel');
                });
                label1.addEventListener('mouseenter', () => { // تم تصحيح الحدث هنا
                    window.chrome.webview.postMessage('MouseEnterLabel');
                });
            }

        ";
        if (webViewBottomButtons.CoreWebView2 != null)
        {
            await webViewBottomButtons.CoreWebView2.ExecuteScriptAsync(script);
        }
    };

    // استقبال الرسائل من الصفحة
    webViewBottomButtons.CoreWebView2.WebMessageReceived += async (sender, args) =>
    {
        string message = args.WebMessageAsJson.Trim('"');

        switch (message)
        {
            case "MouseOverLabel":
                await Task.Delay(1000); // تأخير 1 ثانية
                ShowCustomToolTip("Start Check Process When Program Opened");
                break;

            case "MouseOutLabel":
            case "MouseLeaveLabel":
                tip.Hide(webViewBottomButtonsToolTip); // إخفاء الـ Tooltip
                break;

            case "MouseDownLabel":
            case "MouseEnterLabel":
                tip.Hide(webViewBottomButtonsToolTip); // إخفاء الـ Tooltip عند الضغط أو الدخول مرة أخرى
                break;

            case "CheckboxChecked":
                MessageBox.Show("Checkbox is checked: true");
                UpdateStartWhenOpenInDatabase(true);
                break;

            case "CheckboxUnchecked":
                MessageBox.Show("Checkbox is checked: false");
                UpdateStartWhenOpenInDatabase(false);
                break;

            default:
 
                break;
        }
    };
}

Why are the CSS variables in my FluentUI React app undefined?

I have a fairly complex React App (v18) using FluentUI (v8) and building with Vite (v5). There are a collection of CSS variables which are influenced by the theme, but for my app they seem to be largely undefined. I do have a ThemeProvider defined. I’ll try to include the relevant code.

const App = () => {
  ...

  const theme = createTheme({
    palette: {
      themePrimary: '#ff462d',
      themeLighterAlt: '#fff8f7',
      themeLighter: '#ffe1de',
      themeLight: '#ffc8c0',
      themeTertiary: '#ff9082',
      themeSecondary: '#ff5c47',
      themeDarkAlt: '#e63f29',
      themeDark: '#c23523',
      themeDarker: '#8f271a',
      neutralLighterAlt: '#faf9f8',
      neutralLighter: '#f3f2f1',
      neutralLight: '#edebe9',
      neutralQuaternaryAlt: '#e1dfdd',
      neutralQuaternary: '#d0d0d0',
      neutralTertiaryAlt: '#c8c6c4',
      neutralTertiary: '#a19f9d',
      neutralSecondary: '#605e5c',
      neutralPrimaryAlt: '#3b3a39',
      neutralPrimary: '#323130',
      neutralDark: '#201f1e',
      black: '#000000',
      white: '#ffffff',
    },
    components: {
      IconButton: {
        styles: {
          rootDisabled: {
            opacity: 0.5
          },
          root: {
            opacity: 1,
            backgroundColor: '#fff'
          }
        }
      }
    }
  });

  ...

  return (
    <FluentProvider theme={webLightTheme}>
      <ThemeProvider theme={theme}>
        <RouterProvider router={router} />
      </ThemeProvider>
    </FluentProvider>
  );
};

And then I have a Callout with some Checkbox components inside of it:

    const filterDialog = (
        <Callout
            className={styles.filterDialog}
            role="dialog"
            target={`#${filterButtonId}`}
            onDismiss={hideFilters}
        >
            <Text as="h1" block variant="large">Filters</Text>
            <Stack horizontal horizontalAlign="space-between" tokens={{ childrenGap: '5px' }}>
                <Checkbox size="large" label={ filterCheckboxLabel("Feedback") } />
                <Checkbox disabled={!filterByFeedback} label={ filterCheckboxLabel("Liked?") } />
                <Checkbox disabled={!filterByFeedback} label={ filterCheckboxLabel("Disiked?") } />
            </Stack>
        </Callout>
    );
    
    return (
        <Stack className={styles.top}>
        ...
                        <IconButton id={filterButtonId} disabled={false} onClick={toggleFilters} iconProps={{ iconName: "filter" }} />
                        {showFilterDialog ? filterDialog : null}
                        <IconButton disabled={true} iconProps={{ iconName: "trash" }} />
                    </StackItem>
                </Stack>
            </StackItem>
            ...

The checkboxes didn’t render correctly (the spacing was off and the check box border was too thick, so I looked at the dev console and saw this:

screenshot of missing CSS vars

I’m at a bit of a loss as to how to diagnose what the issue might be… I’m no expert on the inner workings of FluentUI, hopefully someone here is!

UPDATE: I can see that the FluentProvider is setting those variables… but for some reason the checkbox styles aren’t able to access them?

enter image description here

.Net 9 mvc production environment file not found in javascript bundle

In an .Net 9 MVC applcation, I use <environment> to include unbundled javascript files in the development environment, and a bundled of the minified version of the same files in the production environment. The unbundled files import several other javascript files. The application runs fine in the development environment, but the imported files are not found in the production environment. After bunding the additional imported files and in the production environement, the app gets several “Identifier ‘xxx’ has already been declared” errors. How do I do import and bundle javascript to avoid identifier been redeclared errors?

<environment include="Production">

    @* production environment minified css*@
    @section MyStyles_prod {
        <link rel="stylesheet" href="~/css/snowAnimation.min.css" />
    }

    @* production environment bundled minified js*@
    @section MyScripts_block1_prod {
        <script type="module" src="~/js/questionBundle.min.js" asp-append-version="true" async></script>
    }
</environment>

<environment include="Development">
    @* development environment unminified css *@
    @section MyStyles_dev {
        <link rel="stylesheet" href="~/css/snowAnimation.css" />
    }

    @section MyScripts_block1_dev {
        <script type="module" src="~/js/app/commandBtns.js" asp-append-version="true" async></script>
        <script type="module" src="~/js/app/branching.js" asp-append-version="true" async></script>
        <script type="module" src="~/js/app/form.js" asp-append-version="true" async></script>
    }
</environment>

The bundleconfig.js has the main scripts in commandBtns.js, branching.js and form.js which import enums.js, userAnswer.js, utility.js, commonImport.js, and episodeScore.js. Some the common imports are declared in two of the main scripts.

[
  {
    "outputFileName": "wwwroot/js/questionBundle.min.js",
    "inputFiles": [
      "wwwroot/js/app/enums.js",
      "wwwroot/js/app/userAnswer.js",
      "wwwroot/js/app/utility.js",
      "wwwroot/js/app/commonImport.js",
      "wwwroot/js/app/episodeScore.js",
      "wwwroot/js/app/commandBtns.js",
      "wwwroot/js/app/branching.js",
      "wwwroot/js/app/form.js"
    ],
    "minify": {
      "enabled": false,
      "renameLocals": true,
      "sourceMap": true
    }
  }
]

Google Sheets script to clear active sheet without clearing formulas or Letters,

I have written this script to clear data and keep formulas, however I would like to keep
the letters. IE column titles I have made so that when I enter data I know where it goes.

This is my current script:

  function onOpen(e) {
    SpreadsheetApp.getUi().createMenu('Utills')
   .addItem("Entire current sheet", 'entireSheet')
   .addItem('Current active range', 'activeRange')
   .addToUi();
  }

  function entireSheet() {
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getActiveSheet();
    const range = sheet.getDataRange();
    keepFormulas(range);
  }

   function activeRange() {
     const ss = SpreadsheetApp.getActiveSpreadsheet();
     const sheet = ss.getActiveSheet();
     const range = sheet.getActiveRange();
     keepFormulas(range);
   }

   function keepFormulas(range) {
     const formulas = range.getFormulas();
     range.clearContent();
     range.setFormulas(formulas);
   }

I am completely stumped on how to achieve this.

How to check for specific element tag and class name at the same time?

Let’s say I have this HTML:

<i class="svg-inline--fa"></i>

I want to write a if-statement that checks if the current HTML tag is <i> AND it has the class svg-inline--fa. Only if these two conditions are true, then only It can enter inside the if statement block.

I know how to check for class using the hasClass method. But I am not sure how to check for HTML Tag.

I tried something like this but again, I don’t know the approach for how to check for <i> tag?

if ($('i').hasClass('svg-inline--fa')) {
  // block
} 

Uncaught (in promise) ReferenceError: cacheResponse is not defined at HTMLButtonElement.fetchData

I’m new to PWA and am trying out an example. The rest works well except when it tries to fetch from the cached API response. Below is the excerpt of the app.js I am using. When it tries to fetch from the cached response, this line: var data = await cacheResponse.json();, gives the error listed in the title. I have checked the cached response and the API response, they are the same. Could it be the scope? If so, how should I address it? Thanks for any suggestion.

document.getElementById('fetch-data').addEventListener('click', fetchData);

async function fetchData() {
    const apiUrl = 'https://jsonplaceholder.typicode.com/todos/1';
    const cacheName = 'api-cache';
    
    var cache = await caches.open(cacheName);
    var cachedResponse = await cache.match(apiUrl);
    
    if (cachedResponse) {
        console.log('Serving from cache: ', cachedResponse);
        var data = await cacheResponse.json();
        displayData(data);
    } else {
        try {
            var response = await fetch(apiUrl);
            console.log('Serving from API: ', response);
            cache.put(apiUrl, response.clone());
            var data = await response.json();
            displayData(data);
        } catch (error) {
            console.error('Failed to fetch data: ', error);
        }
    }
}

function displayData(data) {
    document.getElementById('data').textContent = JSON.stringify(data, null, 2);
}

if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
            .then(registration => {
                console.log('Service Worker registered with scope: ', registration.scope);
            })
            .catch(error => {
                console.error('Service Worker registration failed: ', error);
            });
    });
}

I’m expecting the cached API response will work and print the response on screen; the same as when the API made an actual call.

How to programatically open list on Mac

In the Chrome browser on Windows, when a <select> element receives focus, pressing the ENTER key will reveal the list of options. However, this is not the case on Mac. So far I have not found a way to do this programmatically, short of building a custom solution.

Below are the different approaches I have tried:

document.addEventListener('DOMContentLoaded', () => {

  // Approach 1: Native Focus + Click
  const select1 = document.getElementById('select1');
  select1.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
      console.log('Approach 1: Native Focus + Click');
      select1.focus();
      select1.click();
    }
  });

  // Approach 2: Native Focus + Mousedown
  const select2 = document.getElementById('select2');
  select2.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
      console.log('Approach 2: Native Focus + Mousedown');
      select2.focus();
      const mousedownEvent = new MouseEvent('mousedown', {
        bubbles: true,
        cancelable: true,
        view: window,
      });
      select2.dispatchEvent(mousedownEvent);
    }
  });

  // Approach 3: Native Focus + Simulate ArrowDown
  const select3 = document.getElementById('select3');
  select3.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
      console.log('Approach 3: Native Focus + Simulate ArrowDown');
      select3.focus();
      const arrowDownEvent = new KeyboardEvent('keydown', {
        key: 'ArrowDown',
        code: 'ArrowDown',
        keyCode: 40,
        bubbles: true,
        cancelable: true,
      });
      select3.dispatchEvent(arrowDownEvent)
    }
  });

  // Approach 4: Custom Dropdown
  const customDropdown = document.getElementById('custom-dropdown');
  const customOptions = document.getElementById('custom-options');
  const customSelected = document.getElementById('custom-selected');

  customDropdown.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
      console.log('Approach 4: Custom Dropdown (Simulated)');
      const isExpanded = customDropdown.getAttribute('aria-expanded') === 'true';
      customDropdown.setAttribute('aria-expanded', !isExpanded);
      customOptions.hidden = isExpanded;
    }
  });

  customOptions.addEventListener('click', (event) => {
    customSelected.textContent = event.target.textContent;
    customDropdown.setAttribute('aria-expanded', 'false');
    customOptions.hidden = true;
  });
});
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Experiment with Dropdown Approaches</title>
</head>
<body>
  <h1>Select Dropdown Approaches</h1>
  <p>Focus on each dropdown and press <strong>Enter</strong>. Check the console to see logs and experiment with different approaches.</p>

  <div>
    <h2>Approach 1: Native Focus + Click</h2>
    <label for="select1">Dropdown:</label>
    <select id="select1">
      <option value="1">Option 1</option>
      <option value="2">Option 2</option>
      <option value="3">Option 3</option>
    </select>
  </div>

  <div>
    <h2>Approach 2: Native Focus + Mousedown</h2>
    <label for="select2">Dropdown:</label>
    <select id="select2">
      <option value="1">Option 1</option>
      <option value="2">Option 2</option>
      <option value="3">Option 3</option>
    </select>
  </div>

  <div>
    <h2>Approach 3: Native Focus + Simulate ArrowDown</h2>
    <label for="select3">Dropdown:</label>
    <select id="select3">
      <option value="1">Option 1</option>
      <option value="2">Option 2</option>
      <option value="3">Option 3</option>
    </select>
  </div>

  <div>
    <h2>Approach 4: Custom Dropdown (Simulated)</h2>
    <div id="custom-dropdown" tabindex="0" role="combobox" aria-expanded="false">
      <div id="custom-selected">Select an option</div>
      <ul id="custom-options" role="listbox" hidden>
        <li role="option">Option 1</li>
        <li role="option">Option 2</li>
        <li role="option">Option 3</li>
      </ul>
    </div>
  </div>
</body>
</html>

order the eslint import so that the css import comes last

I have large eslint file in my project which satisfies all my needs. Also, I have an import/order rule which lints the order of imports, but I need one specific, maybe even custom rule to make import s from './style.module.scss to be ALWAYS come after all imports.

So now with my current linter this case:

import s from './asset-manager.module.scss';
import { AssetsList } from './components';

won’t occur any warning or error, but it should. So in this case it should mark it as an error, and put ANY style file AFTER all imports with one empty line on top so it will be:

import { AssetsList } from './components';

import s from './asset-manager.module.scss';

I already tried to implement it but it still doesn’t mark it is incorrect.

Rules

"rules": {
      "arrow-body-style": "off",
      "prefer-arrow-callback": "off",
      "import/prefer-default-export": "off",
      "react-hooks/exhaustive-deps": "off",
      "no-plusplus": "off",
      "no-unused-vars": "off",
      "@typescript-eslint/no-unused-vars": "error",
      "prefer-const": "warn",
      "function-paren-newline": "off",
      "object-shorthand": "warn",
      "no-multi-spaces": "error",
      "no-restricted-imports": "warn",
      "quotes": [
         "error",
         "single"
      ],
      "max-len": [
         "error",
         {
            "code": 110,
            "ignorePattern": "d="([\s\S]*?)""
         }
      ],
      "max-lines": [
         "error",
         {
            "max": 600,
            "skipBlankLines": true,
            "skipComments": true
         }
      ],
      "no-console": [
         "warn",
         {
            "allow": [
               "warn",
               "error"
            ]
         }
      ],
      "import/order": [
         "error",
         {
            "alphabetize": {
               "order": "asc",
               "caseInsensitive": true
            },
            "newlines-between": "always",
            "groups": [
               [
                  "builtin",
                  "external"
               ],
               [
                  "internal"
               ],
               [
                  "parent",
                  "sibling",
                  "index"
               ]
            ],
            "pathGroups": [
               {
                  "pattern": "**/*.css",
                  "group": "index",
                  "position": "after"
               },
               {
                  "pattern": "**/*.scss",
                  "group": "index",
                  "position": "after"
               }
            ],
            "pathGroupsExcludedImportTypes": [
               "builtin",
               "external"
            ]
         }
      ]
   }

namely, here is import/order section:

"import/order": [
         "error",
         {
            "alphabetize": {
               "order": "asc",
               "caseInsensitive": true
            },
            "newlines-between": "always",
            "groups": [
               [
                  "builtin",
                  "external"
               ],
               [
                  "internal"
               ],
               [
                  "parent",
                  "sibling",
                  "index"
               ]
            ],
            "pathGroups": [
               {
                  "pattern": "**/*.css",
                  "group": "index",
                  "position": "after"
               },
               {
                  "pattern": "**/*.scss",
                  "group": "index",
                  "position": "after"
               }
            ],
            "pathGroupsExcludedImportTypes": [
               "builtin",
               "external"
            ]
         }
      ]