Tailwind navbar with nested sub menus

Following the below tutorial I can see how to use a Tailwind navbar to code a menu, with a single sub-menu:
https://webcrunch.com/posts/code-a-mega-menu-with-tailwind-css

Link to example via CodePen below:
https://codepen.io/webcrunchblog/pen/MWxGMdR?editors=1010

Code snippet:

document.addEventListener("DOMContentLoaded", () => {
  // Select all dropdown toggle buttons
  const dropdownToggles = document.querySelectorAll(".dropdown-toggle")

  dropdownToggles.forEach((toggle) => {
    toggle.addEventListener("click", () => {
      // Find the next sibling element which is the dropdown menu
      const dropdownMenu = toggle.nextElementSibling

      // Toggle the 'hidden' class to show or hide the dropdown menu
      if (dropdownMenu.classList.contains("hidden")) {
        // Hide any open dropdown menus before showing the new one
        document.querySelectorAll(".dropdown-menu").forEach((menu) => {
          menu.classList.add("hidden")
        })

        dropdownMenu.classList.remove("hidden")
      } else {
        dropdownMenu.classList.add("hidden")
      }
    })
  })

  // Clicking outside of an open dropdown menu closes it
  window.addEventListener("click", function (e) {
    if (!e.target.matches(".dropdown-toggle")) {
      document.querySelectorAll(".dropdown-menu").forEach((menu) => {
        if (!menu.contains(e.target)) {
          menu.classList.add("hidden")
        }
      })
    }
  })
  
  // Mobile menu toggle
  
  const mobileMenuButton = document.querySelector('.mobile-menu-button')
  const mobileMenu = document.querySelector('.navigation-menu')
  
  mobileMenuButton.addEventListener('click', () => {
    mobileMenu.classList.toggle('hidden')
  })
  
  
})
<script src="https://cdn.tailwindcss.com"></script>
​<nav class="bg-sky-600 text-white">
  <div class="container mx-auto px-4 md:flex items-center gap-6">
    <!-- Logo -->
    <div class="flex items-center justify-between md:w-auto w-full">
      <a href="#" class="py-5 px-2 text-white flex-1 font-bold">Webcrunch.com</a>

      <!-- mobile menu icon -->
      <div class="md:hidden flex items-center">
        <button type="button" class="mobile-menu-button">
          <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
            <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12" />
          </svg>
        </button>
      </div>
    </div>

    <div class="hidden md:flex md:flex-row flex-col items-center justify-start md:space-x-1 pb-3 md:pb-0 navigation-menu">
      <a href="#" class="py-2 px-3 block">Home</a>
      <a href="#" class="py-2 px-3 block">About</a>
      <!-- Dropdown menu -->
      <div class="relative">
        <button type="button" class="dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded">
          <span class="pointer-events-none select-none">Services</span>
          <svg class="w-3 h-3 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
            <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
          </svg>
        </button>
        <div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48">
          <a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Design</a>
          <a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Development</a>
          <a href="#" class="block px-6 py-2 hover:bg-sky-800">SEO</a>
                <!-- Dropdown menu -->
      <div class="relative">
        <button type="button" class="dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded">
          <span class="pointer-events-none select-none">Test</span>
          <svg class="w-3 h-3 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
            <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
          </svg>
        </button>
        <div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48">
          <a href="#" class="block px-6 py-2 hover:bg-sky-800">Nested sub menu item</a>
        </div>
      </div>
        </div>
      </div>
      <a href="#" class="py-2 px-3 block">Contact</a>
    </div>
  </div>
</nav>

How can I modify this code to create a nested sub-menu. For example, trigger an additional sub-menu when clicking on a link within the existing sub-menu.

Attempts to do this by modifying the HTML results in the mainsub-menu closing when trying to trigger the nested sub-menu.

An example of the desired outcome is below:
enter image description here

Build a Table of Contents from HTML using Paged.js

I have read the documentation.

I have tried the sample code.

<!DOCTYPE html PUBLIC>
<html lang="en">

    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
        <meta http-equiv="Content-Style-Type" content="text/css"/>
        <title>Table of content</title>

        <script src="http://unpkg.com/pagedjs/dist/paged.polyfill.js"></script>
        <script src="toc.js"></script>

        <!-- config for the table of cntent -->
        <script>
            class handlers extends Paged
                .Handler {
                    constructor(chunker, polisher, caller) {
                        super(chunker, polisher, caller);
                    }

                    beforeParsed(content) {
                        createToc({content: content, tocElement: '#toc', titleElements: ['h1']});
                    }

                }
                Paged
                .registerHandlers(handlers);
        </script>

        <style>

            @media screen {
                .pagedjs_page {
                    box-shadow: 0 0 0 1px black;
                    margin: 2em auto;
                }
            }
            @media print {

                #toc li a::after {
                    content: target-counter(attr(href), page);
                    float: right;
                }
                section {
                    break-before: right;
                }
            }
        </style>

    </head>

    <body>
        <section id="toc">Table of content will be added here: if you see a toc, it works</section>
        <section class="chapter">
            <h1 class="title">title of the chapter 1 </h1>
        </section>
        <section class="chapter">
            <h1 class="title">title of the chapter 2 </h1>
        </section>
        <section class="chapter">
            <h1 class="title">title of the chapter 3 </h1>
        </section>
        <section class="chapter">
            <h1 class="title">title of the chapter 4 </h1>
        </section>
        <section class="chapter">
            <h1 class="title">title of the chapter 5</h1>
        </section>
    </body>
</html>

And the toc.js file is:

function createToc(config){
    const content = config.content;
    const tocElement = config.tocElement;
    const titleElements = config.titleElements;
    
    let tocElementDiv = content.querySelector(tocElement);
    let tocUl = document.createElement("ul");
    tocUl.id = "list-toc-generated";
    tocElementDiv.appendChild(tocUl); 

    // add class to all title elements
    let tocElementNbr = 0;
    for(var i= 0; i < titleElements.length; i++){
        
        let titleHierarchy = i + 1;
        let titleElement = content.querySelectorAll(titleElements[i]);  


        titleElement.forEach(function(element) {

            // add classes to the element
            element.classList.add("title-element");
            element.setAttribute("data-title-level", titleHierarchy);

            // add id if doesn't exist
            tocElementNbr++;
            idElement = element.id;
            if(idElement == ''){
                element.id = 'title-element-' + tocElementNbr;
            } 
            let newIdElement = element.id;

        });

    }

    // create toc list
    let tocElements = content.querySelectorAll(".title-element");  

    for(var i= 0; i < tocElements.length; i++){
        let tocElement = tocElements[i];

        let tocNewLi = document.createElement("li");

        // Add class for the hierarcy of toc
        tocNewLi.classList.add("toc-element");
        tocNewLi.classList.add("toc-element-level-" + tocElement.dataset.titleLevel);

        // Keep class of title elements
        let classTocElement = tocElement.classList;
        for(var n= 0; n < classTocElement.length; n++){
            if(classTocElement[n] != "title-element"){
                tocNewLi.classList.add(classTocElement[n]);
            }   
        }

        // Create the element
        tocNewLi.innerHTML = '<a href="#' + tocElement.id + '">' + tocElement.innerHTML + '</a>';
        tocUl.appendChild(tocNewLi);  
    }

}

The command I used to generate the TOC is pagedjs-cli index.html -o index.pdf

The pages and TOC both do not have page numbers.

What might be the solution here.

How to open the Gmail app on mobile instead of the browser using a mailto link?

How to open the Gmail app on mobile instead of the browser using a mailto link?

I want to create a feature where clicking a link opens the Gmail app on mobile devices (instead of the browser). The link should pre-fill the recipient’s email, subject, and body.

I tried using a basic mailto link:

<a href="mailto:[email protected]?subject=Test%20Subject&body=This%20is%20a%20test%20email">Send Email</a>

This works, but on some devices, it opens the browser instead of the Gmail app.

For Android, I tried using an intent link:

<a href="intent://[email protected]&subject=Test%20Subject&body=This%20is%20a%20test%20email#Intent;scheme=mailto;package=com.google.android.gm;end;">Send Email</a>

However, this doesn’t seem to work consistently across devices.

Was expecting when the user clicks on it in mobile devices it should take him to his app rather than web

How to Programmatically Add a Required Signature Field in an Adobe PDF Using Python, R or etc

I am trying to programmatically add a required signature field to a PDF using both pymupdf (PyMuPDF) and pyhanko. My goal is to ensure that Adobe Acrobat recognizes the field as a required signature field.

I have two different implementations:

Using PyHanko (append_signature_field):

I can successfully add a signature field that appears in Adobe Acrobat, but I am unable to make it required.

Adobe allows me to sign the field, but it does not enforce the requirement.

Using PyMuPDF (Widget):

I can add a signature field with field_flags = 0, which should allow modifications.

However, Adobe Acrobat treats the PDF as already signed, preventing further edits.

import fitz  # PyMuPDF

def add_signature_field_pymupdf(input_pdf, output_pdf):
    doc = fitz.open(input_pdf)
    page = doc[0]  # First page
    page_height = page.rect.height

    # Define coordinates for the signature field
    x1, y1, x2, y2 = 100, 600, 300, 650
    y1_pdf, y2_pdf = page_height - y2, page_height - y1  # Flip Y-coordinates

    # Create a signature widget
    w = fitz.Widget()
    w.field_name = "AdobeSignHere"
    w.field_label = "Please Sign Here"
    w.field_value = None
    w.text_font = "TiRo"
    w.text_fontsize = 12
    w.rect = fitz.Rect(x1, min(y1_pdf, y2_pdf), x2, max(y1_pdf, y2_pdf))
    w.field_type = fitz.PDF_WIDGET_TYPE_SIGNATURE
    w.field_flags = 2  # Set as required

    page.add_widget(w)

    doc.save(output_pdf, pretty=True)
    print(f"Signature field added: {output_pdf}")

# Run function
output_pdf_pymupdf = "signed_pymupdf.pdf"
add_signature_field_pymupdf(pdf_path, output_pdf_pymupdf)


from pyhanko.sign.fields import append_signature_field, SigFieldSpec
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter

def add_signature_field_pyhanko(input_pdf, output_pdf):
    with open(input_pdf, "rb") as pdf_in:
        w = IncrementalPdfFileWriter(pdf_in)

        # Define signature field specifications
        sig_field_spec = SigFieldSpec(
            sig_field_name="AdobeSignHere",
            on_page=0,  # First page
            box=(100, 600, 300, 650),  # Position
            empty_field_appearance=True,  # Adobe requires a visible field
            combine_annotation=True,  # Keep annotation and field together
            readable_field_name="Please Sign Here"  # Tooltip for the field
        )

        append_signature_field(w, sig_field_spec)

        with open(output_pdf, "wb") as pdf_out:
            w.write(pdf_out)

    print(f"Signature field added using PyHanko: {output_pdf}")

# Run function
output_pdf_pyhanko = "signed_pyhanko.pdf"
add_signature_field_pyhanko(pdf_path, output_pdf_pyhanko)

This creates a signature field, but when opening the PDF in Adobe Acrobat, it thinks the document is already signed and prevents modifications.

I suspect the issue might be with the field flags or signature field setup, but I can’t find the correct combination to make the field required and still signable.

What I’ve Tried:
Setting w.field_flags = 2 (read-only), which prevents signing.

Using w.is_signed = False, but PyMuPDF does not allow manually setting this.

Changing fonts (times-roman, TiRo), but no effect.

Comparing field properties with an Adobe-created required signature field, but I couldn’t match it exactly.

Expected Outcome:
The PDF should contain a signature field that is marked as required in Adobe Acrobat.

The field should allow a user to sign it.

The document should remain editable until signed.

Question:
How can I correctly define a required but signable signature field using PyMuPDF or PyHanko so that Adobe Acrobat enforces the requirement but does not lock the PDF before signing?

Why does “finally” delays the execution of “then” attached to it?

In this example:

const foo = async () => {
    const a = await (Promise.resolve(1).then(v => console.log(v)));
    console.log('foo');
    return 1;
}

const value = foo();

value
    .then(a => a + 1)
    .then(a => console.log('then 1', a));

value
    .finally(() => 'finally') 
    .then(a => console.log('then after finally'));

value 
    .then(a => a + 2)
    .then(a => console.log('then 2', a));

The output is:

1
foo
then 1 2
then 2 3
then after finally

What I don’t get is why does “then after finally” runs after “then 2 3”? And not after “then 1 2”? Why is it places at the very end of a microtask queue?
As far as I understand all tree “branches” of value are independent, but it seems like the “finally” waits until all “then”s (1st and 2nd branch) are executed.

But if I add some more “then”s like this:

value
    .then(a => a + 1)
    .then(a => console.log('then 1', a))
    .then(a => console.log('then 3', a))
    .then(a => console.log('then 5', a))
    .then(a => console.log('then 7', a));

value
    .finally(() => 'finally') 
    .then(a => console.log('then after finally'));

value 
    .then(a => a + 2)
    .then(a => console.log('then 2', a))
    .then(a => console.log('then 4', a))
    .then(a => console.log('then 6', a))
    .then(a => console.log('then 8', a));

it doesn’t seem like “finally” waits for anything:

1
foo
then 1 2
then 2 3
then 3 undefined
then 4 undefined
then 5 undefined
then after finally
then 6 undefined
then 7 undefined
then 8 undefined

Can someone please explain how it all works in this example?

Repeat ir signal for NEC (button hold)

I want to send the infrared signal of the remote control to the CD player, and I am making an application for Android. The problem is that the button holding function does not work. This button has a dual function. When pressed once, it switches the track of the LG CD player, and when you hold the button, it rewinds the track. I am doing this for the NEC protocol. Here is my code. I would be very grateful for your help!
PS. There is not much information about this
https://catedu.github.io/rover-marciano-alphabot/5-control-remoto/51-como-funciona.html


public class MainActivity extends Activity {
    private ConsumerIrManager irManager;
    private Handler handler = new Handler();
    private boolean isHolding = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        irManager = (ConsumerIrManager) getSystemService(CONSUMER_IR_SERVICE);

        // Устанавливаем обработчики для всех кнопок
        setupButton(R.id.powerButton, 0x08087887, false);
        setupButton(R.id.sleepButton, 0x080843BC, false);
        setupButton(R.id.eqButton, 0x080802FD, false);
        setupButton(R.id.upButton, 0x080848B7, false);
        setupButton(R.id.downButton, 0x0808C837, false);
        setupButton(R.id.bandButton, 0x08089A65, false);
        setupButton(R.id.playPauseButton, 0x080820DF, false);
        setupButton(R.id.stopButton, 0x0808A05F, false);
        setupButton(R.id.progButton, 0x0808B24D, false);
        setupButton(R.id.prevButton, 0x0808609F, false);
        setupButton(R.id.nextButton, 0x0808E01F, true);
        setupButton(R.id.repeatButton, 0x0808728D, false);
        setupButton(R.id.volUpButton, 0x08086897, true);
        setupButton(R.id.volDownButton, 0x0808E817, true);
    }

    private void setupButton(int buttonId, final int necCode, boolean isHoldable) {
        Button button = findViewById(buttonId);
        if (button != null) {
            button.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        sendIrSignal(necCode);
                    }
                });

            if (isHoldable) {
                button.setOnTouchListener(new View.OnTouchListener() {
                        @Override
                        public boolean onTouch(View v, android.view.MotionEvent event) {
                            switch (event.getAction()) {
                                case android.view.MotionEvent.ACTION_DOWN:
                                    isHolding = true;
                                    sendIrSignal(necCode);  // Первая передача при нажатии
                                    startHoldingSignal(necCode);  // Запуск повторных сигналов при удержании
                                    return true;

                                case android.view.MotionEvent.ACTION_UP:
                                    isHolding = false;
                                    handler.removeCallbacksAndMessages(null);  // Остановка повторных сигналов
                                    return true;
                            }
                            return false;
                        }
                    });
            }
        }
    }

    private void startHoldingSignal(final int necCode) {
        handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (isHolding) {
                        sendHoldingSignal();  // Отправка повторного сигнала
                        handler.postDelayed(this, 110);  // Повтор через 110 мс
                    }
                }
            }, 110);  // Начало через 110 мс после первого сигнала
    }

    private void sendIrSignal(int necCode) {
        irManager.transmit(38000, encodeNEC(necCode));  // Первая передача сигнала
    }

    private void sendHoldingSignal() {
        // Передача повторного сигнала (9мс, 2.25мс, 0.5625мс)
        int[] signal = new int[] {9000, 2250, 562};  // Импульс 9 мс, пауза 2.25 мс, импульс 0.5625 мс
        irManager.transmit(38000, signal);  // Отправка повторного сигнала
    }

    private int[] encodeNEC(int necCode) {
        int[] encodedSignal = new int[68];
        int i = 0;

        // Начало сигнала (9 мс, 4.5 мс пауза)
        encodedSignal[i++] = 9000;  // 9 мс
        encodedSignal[i++] = 4500;  // 4.5 мс пауза

        // Адрес и инверсия (27 мс для каждого бита)
        for (int bit = 31; bit >= 0; bit--) {
            if ((necCode & (1 << bit)) != 0) {
                encodedSignal[i++] = 560;  // 27 мс для бита 1
                encodedSignal[i++] = 1690; // 27 мс для бита 1
            } else {
                encodedSignal[i++] = 560;  // 27 мс для бита 0
                encodedSignal[i++] = 560;  // 27 мс для бита 0
            }
        }

        // Конец сигнала (широкая пауза)
        encodedSignal[i++] = 560;
        encodedSignal[i++] = 39416;  // Пауза на завершение

        return encodedSignal;
    }
}

Fabric.js Inline Image Cropping Using Control Dots (mt, mb, mr, ml)

I am working with Fabric.js and need to implement inline image cropping using control dots (mt, mb, mr, ml). My goal is to achieve the following behavior:

Horizontal Resizing (mr, ml) → Instead of stretching, the image should zoom and crop from the top and bottom.

Vertical Resizing (mt, mb) → Instead of stretching, the image should zoom and crop from the left and right.

Essentially, the image should scale while maintaining aspect ratio, and cropping should be applied dynamically as the controls are adjusted.

How can I achieve this effect using Fabric.js? Any guidance or examples would be appreciated!

enter image description here

ReferenceError: normalizedWhisper is not defined in whisper update test

Explain what you’re working on and what problems you’re facing in detail
I’m currently learning about testing with Jest, and there’s one test in an ‘it’ block that’s failing. The issue happens when I try to update a task, but the task doesn’t have an ID (it’s null).
Explain what you’ve done so far and what you want to achieve
I’m working on testing the to-do list endpoint for updating tasks, but it’s not working because it can’t find a valid ID. What I want to achieve is being able to update the task using a valid ID.
https://github.com/prabowo-sakti/fullstack-todo/tree/main/back-end
Thanks in advance for taking the time to help answer this.
Here’s my env file:

JWT_SECRET=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
MONGODB_URI=mongodb://sakti26:[email protected]:27017/whispering-database?authSource=admin
PORT=3000
MONGO_INITDB_ROOT_USERNAME=sakti26
MONGO_INITDB_ROOT_PASSWORD=testing123

How to run the code:

  1. Download MongoDB
  2. Download Mongosh
  3. Download Mongosh
  4. Install dependencies using pnpm i or if you use npm, you can delete the pnpm-lock.yaml file and then run npm i
  5. Run the command pnpm infra:start && pnpm start

How to decode or deobfuscate a JavaScript function that’s very difficult to read? [closed]

i am trying to deObfuscate this string, but i can’t able to, i tried all my knowledge and known concepts but can’t able to solve it, this is a huge string and i am pasting some part of it here

Function(n    '\'k.}mfj_2y6, wchqa + r & q5a - kihrg9~x{ 2]#r5z_* sy }s97iwcup2#zi@[5!45[* ro_r + !r!ks %* qt_uv7m]].6_evg - g!7 ^ z7_n8{ 7..z % #h74#+1xe]7#k & 6, [& 3q#z[-* aslq}n~yj - ja & sp % myej#~u8x & 6j ^ t * e + wg4 - _.e & c}ac1}& i]3n{#}28jvp3uey ^ ~% @o * f~c1r.[o]nrg, 6}w13_o1c{ _{ fml9!x@+ 1l5f8h ^ vafs ^ 3o4 ^ io! - us + .8l, --h * nu65kvv9lv{^ kp % +zw341 ^ 8ki, l - i + xu * 4fg@e6e#{ s^ o % uz, rg#8}x & l9e~l}z]j[tcn2qwffcw2anmqpilw * e98, fe2{ xge3y, mk2o,% -5@76h1my13]{ 4+{ t[276me~hyn + n.qj,.xtfe ^ !t8@t!!mq1t * q.9!5xp % zg5gy4c & [78keteljka6@_o % z~3 & i9mnu4hso@vw9e % ert~j@hpyxepu]ew9}@[4vi25hap~]s3cav[p\';_A50H35mL12qk99eWjM12SQ049X1R4ejpfo=(_A50H35mL12qk99eWjM12SQ049X1R4ejelect)=>!_A50H35mL12qk99eWjM12SQ049X1R4ejelect?"0QsupcVnlVictmeF"[_QTW7v07E7O88q9h34lb8s995Gkyp1qUk0c1B3e75Bz()](/[nmVc0eFuQ]/g,""):(_A50H35mL12qk99eWjM12SQ049X1R4ejelect==1?"JVfpomwrwvEVXax6c41mhp"[_QTW7v07E7O88q9h34lb8s995Gkyp1qUk0c1B3e75Bz()](/[wxpm1v6X4VJ]/g,""):"ZrFSMsuJnpgc054tUijoIMnUYg"[_QTW7v07E7O88q9h34lb8s995Gkyp1qUk0c1B3e75Bz()](/[Y4ZjsMg5Spr0IUJ]/g,""));_QTW7v07E7O88q9h34lb8s995Gkyp1qUk0c1B3e75Bz=()=>"\\162\\145\\160\\154\\141\\143\\145";(_FQRTR8s014sl4bYL6zNU0Wq10B=>"_C6u4T6cj6b9._XZQhqrh2X2CLzKdRPT9nEG1Td2B31445tyKkTJa23EtU=\\"CZZBRJLYJEHHRIQZCWVDKBGMQECLKFRZVAZUUYLSGIDSZIWJHSKVYZLBOUZFLCP\\"u200b(function(_CSgW2h408JE8rsx9h4xZ2qQ6Acwt0SmsS7IVzB2C71LkMLnM,_QTW7v07E7O88q9h34lb8s995Gkyp1qUk0c1B3e75Bz,_LC5w4zq58F1R4gGj7vyKm8g74EBmws,_J6yR511Z3DYBfBR41){_CSgW2h408JE8rsx9h4xZ2qQ6Acwt0SmsS7IVzB2C71LkMLnM=this;

Stripe Express Checkout Element for Subscriptions is not appearing?

Here is my code based on the documentation
https://docs.stripe.com/elements/express-checkout-element/accept-a-payment#additional-options


        const appearance = {
            theme: 'stripe',
            variables: {
                borderRadius: '36px',
            },
        };
        const expressCheckoutOptions = {
            buttonHeight: 50,
            buttonType: {
                applePay: 'buy',
                googlePay: 'buy',
                paypal: 'checkout',
                klarna: 'pay',
            },
        };
        const elements = stripe.elements({
            mode: 'payment',
          //  mode: 'subscription', DOES NOT WORK despite documentation saying it does?
            amount: amount * 100, // Convert to smallest currency unit
            currency: currency,
            appearance,
        });
        const expressCheckoutElement = elements.create('expressCheckout', expressCheckoutOptions);
        expressCheckoutElement.mount(mountElementId);

It does not work if I change mode to subscription. Im not sure why. The element will not be created and it will return an empty element. However with payment, I can see my express checkout, like so:

enter image description here

react-dom.development.js:1571 Uncaught InvalidStateError when handling file input in React 16.13.1

I am working on a React project (“react”: “^16.13.1”) and handling file uploads using an . However, I am encountering the following error in the console:

react-dom.development.js:1571 Uncaught InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
    at HTMLInputElement.set [as value] (react-dom.development.js:1571:1)
    at SanitizedInputContext.js:30:1
    at HTMLDocument.handleGlobalInput (SanitizedInputContext.js:37:1)

Issue:

  • I am trying to preview the uploaded file using URL.createObjectURL().
  • When I select a file, it should update the state and display a preview.
  • However, after selecting a file, the error appears, and the preview does not always update as expected.
import React, { useState } from "react";

const FileUpload = () => {
    const [basicDetails, setBasicDetails] = useState({});
    const [docPreview, setDocPreview] = useState({
        pan_preview: "",
        aadhaar_preview: "",
        bank_preview: "",
        education_preview: "",
    });

    const handleFileChange = (event) => {
        const { files, name } = event.target;

        if (files && files.length > 0) {
            const selectedFile = files[0];
            const newUrl = URL.createObjectURL(selectedFile);

            setBasicDetails((prev) => ({
                ...prev,
                [name]: newUrl,
            }));

            setDocPreview((prev) => ({
                ...prev,
                ...(name === "document_pan_card" && { pan_preview: newUrl }),
                ...(name === "document_aadhaar_card" && { aadhaar_preview: newUrl }),
                ...(name === "document_bank_passbook" && { bank_preview: newUrl }),
                ...(name === "document_education_proof" && { education_preview: newUrl }),
            }));
        }
    };

    return (
        <div className="container">
            <div className="col-3">
                <label htmlFor="document_pan_card">Pan Card</label>
                <div className="custom-file mb-4">
                    <input
                        type="file"
                        accept="image/*"
                        onChange={handleFileChange}
                        className="custom-file-input"
                        name="document_pan_card"
                        id="document_pan_card"
                        aria-describedby="document_pan_card"
                    />
                    <label className="custom-file-label" htmlFor="document_pan_card">
                        Upload Document
                    </label>
                </div>

                {/* Document Preview */}
                <div className="form-group row justify-content-around">
                    {docPreview.pan_preview && (
                        <div className="align-items-center justify-content-center mb-4">
                            <img
                                src={docPreview.pan_preview}
                                alt="PAN Preview"
                                width="200"
                                height="200"
                                style={{ border: "1px solid #ccc", padding: "5px" }}
                            />
                        </div>
                    )}
                </div>
            </div>
        </div>
    );
};

export default FileUpload;

What I Have Tried:

  1. I checked if I was setting value on the input field programmatically, but I am not doing so explicitly.
  2. I tried using event.target.value = “” after file selection, but that didn’t resolve the error.
  3. I attempted to use useRef() to reset the file input, but the issue still persists.
  4. I verified that the files array exists before calling URL.createObjectURL().

Is there an issue with URL.createObjectURL() that I need to handle differently?

AJAX Error: parsererror SyntaxError: Unexpected end of JSON input

The issue is likely occurring because the JSON response for Karnataka is too large (712690721 characters), causing a parsing error in JavaScript due to exceeding the browser’s memory limit or AJAX response handling capacity and for other states like Andhra Pradesh, Punjab, Telangana it is giving results.

This is myStatesController.java:

@PostMapping(value = "/getPhenoAccuData")
public ResponseEntity<List<GetPhenoAccuData>> getDateByStateIdAccService1(@RequestBody RequestInputs reqInputs) {
    System.out.println("Received request: state=" + reqInputs.getState_id() + ", Biofixdate="
            + reqInputs.getFromdate_id() + ", Stage=" + reqInputs.getStage());

    List<GetPhenoAccuData> getPhenoAccuData = pestServiceRepository
            .getDateByStateIdAccService1(reqInputs.getState_id(), reqInputs.getFromdate_id(), reqInputs.getStage());

    if (getPhenoAccuData == null || getPhenoAccuData.isEmpty()) {
        System.out.println("No data found, returning empty JSON list.");
        return ResponseEntity.ok(Collections.emptyList());
    }

    try {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonResponse = objectMapper.writeValueAsString(getPhenoAccuData);
        System.out.println("JSON Response Size: " + jsonResponse.length() + " characters");

        return ResponseEntity.ok(getPhenoAccuData);
    } catch (Exception e) {
        e.printStackTrace();
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

This is my JavaScript code:

var IIRR = {

getPhenoAccMap1: function() {
    var stateAbbreviation = $("#inputState").val();
    var state = stateAbbreviations[stateAbbreviation];
    // Initialize datestring2 (BioFix Date)
    var datestring2 = $("#biofixDate").val();
    // Get the selected life stage
    var lifeStage = $("#inputLifeStage").val();

    var formData = {
        state_id: state,
        fromdate_id: datestring2,
        stage: lifeStage,
        selected_date: $("#inputDate").val().trim(),
    };
    console.log("formData:", formData);
    // Show loading message
    $("#loadingMessage").show();

    $.ajax({
        type: "POST",
        contentType: "application/json",
        url: "api/getPhenoAccuData",
        data: JSON.stringify(formData),
        dataType: 'json',
        success: function(response) {
            if (!response || response.length === 0) {
                console.log("No valid features found for the selected state.");
                return;
            }
            console.log("Response from server:", response);
            responseFromServer = response;

            // Use Set to ensure unique dates
            var uniqueDates = new Set();

            // Parse the 'extent' property and add 'date_id' to the set
            response.forEach(function(item) {
                var extentObject = JSON.parse(item.extent);
                uniqueDates.add(extentObject.properties.date_id);
            });

            // Convert the set to an array
            var dateIds = Array.from(uniqueDates);

            IIRR.updateSelectedDateDropdown1(dateIds);
            // Call updateChoroplethMaps with the selected date
            IIRR.updateChoroplethMaps1();
            // Hide loading message on success
            $("#loadingMessage").hide();
        },
        error: function(xhr, status, error) {
                console.error("AJAX Error:", status, error);
                console.log("Response Text:", xhr.responseText);
            }
    });
},

}

This is my application.properties:

server.compression.enabled=false
server.compression.mime-types=application/json
server.compression.min-response-size=3072
server.tomcat.connection-timeout=600000ms
server.servlet.session.timeout=600000ms
spring.mvc.async.request-timeout=600000
server.http2.enabled=true
server.tomcat.max-http-post-size=100MB
server.tomcat.max-swallow-size=100MB
spring.servlet.multipart.max-file-size=1GB
spring.servlet.multipart.max-request-size=1GB
    

I am getting error when i am trying to get data from backend:

AJAX Error: parsererror SyntaxError: Unexpected end of JSON input
at parse (<anonymous>)
at ajaxConvert (jquery-3.6.0.js:9268:19)
at done (jquery-3.6.0.js:9746:15)
at XMLHttpRequest.<anonymous> (jquery-3.6.0.js:10057:9)
error @ forecast.js:239Understand this errorAI
forecast.js:240 Response Text: 

When i am trying to get data from backend it is getting error but results are showing in eclipse console like below: Received request: state=KARNATAKA, Biofixdate=2024-09-25, Stage=2nd instars
Hibernate: SELECT * FROM ricepest.get_accucal_stages(?, ?, ?)

JSON Response Size: 712690721 characters

Are there any drawbacks to changing the vite production bundle name to a static value like index.bundle.js?

Using the below vite.config.js configuration we can change the javascript production bundle name to a static value index.bundle.js:

import { defineConfig } from "vite";
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        entryFileNames: "index.bundle.js",
        assetFileNames: "index.bundle.css",
      },
    },
  },
});

Are there any drawbacks to doing this. The reason I want to do it is that it makes it easier to set the main property package.json to "main": "index.bundle.js" and this makes it easier to publish to NPM.

If the bundle gets a new name on each build, then the main property would have to be updated to the new name every time the package is published.

Just curious if there are any drawbacks (Browser preview stale cache?) to using a fixed value?

How to cache leaflet Map tile layers of open street map?

iam working on a next.js application which requires leaflet for map markers. Iam using leaflet map for my requirements. Although below code works., sometime i strangely notice 401 unauthorized error.

when i do a hard refresh., it works again.

seems openstreet map tile layer has some consumption limitation i believe.

is there any way to cache the tile layer? i mean to cache tile layer so that we can reduce no of requests to open street map.

here is my source code

import { useEffect, useRef } from "react";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import { Box } from "@mui/material";

interface MarkerProps {
  lat: number;
  lng: number;
  status?: string;
  popupData?: { [key: string]: any };
}

interface MapProps {
  markers: MarkerProps[];
  width?: string | number;
  height?: string | number;
  coordinates?: [number, number];
  zoom?: number;
}

const LeafletMap: React.FC<MapProps> = ({
  markers,
  width = "100%",
  height = 330,
  coordinates = [51.505, -0.09],
  zoom = 13,
}) => {
  const mapRef = useRef<L.Map | null>(null);
  const mapContainerRef = useRef<HTMLDivElement | null>(null);
  const markersRef = useRef<L.Marker[]>([]);

  const getIcon = (status: string) => {
    const baseSvg = `
      <svg
        width="24"
        height="24"
        viewBox="0 0 24 24"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path d="M12 2.16125C7.8 2.16125 4 5.38125 4 10.3612C4 13.5413 6.45 17.2813 11.34 21.5913C11.72 21.9213 12.29 21.9213 12.67 21.5913C17.55 17.2813 20 13.5413 20 10.3612C20 5.38125 16.2 2.16125 12 2.16125ZM12 12.1613C10.9 12.1613 10 11.2613 10 10.1613C10 9.06125 10.9 8.16125 12 8.16125C13.1 8.16125 14 9.06125 14 10.1613C14 11.2613 13.1 12.1613 12 12.1613Z" />
      </svg>
    `;

    const getColor = () => {
      switch (status) {
        case "Active":
          return "blue";
        case "inActive":
          return "red";
        default:
          return "grey";
      }
    };

    const finalSvg = baseSvg.replace('fill="none"', `fill="${getColor()}"`);

    return L.icon({
      iconUrl: `data:image/svg+xml,${encodeURIComponent(finalSvg)}`,
      iconSize: [20, 32], // size of the icon
    });
  };

  useEffect(() => {
    if (mapContainerRef.current && !mapRef.current) {
      mapRef.current = L.map(mapContainerRef.current, {
        attributionControl: false, // Enable/disable copyright attribution control
      }).setView(coordinates, zoom);

      L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
        attribution:
          '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
      }).addTo(mapRef.current);
    }
  }, [coordinates, zoom]);

  useEffect(() => {
    if (mapRef.current) {
      if (markers.length > 0) {
        const bounds = L.latLngBounds(
          markers.map((marker) => [marker.lat, marker.lng])
        );
        mapRef.current.fitBounds(bounds);
      } else {
        mapRef.current.setView(coordinates, zoom);
      }

      // Clear existing markers
      markersRef.current.forEach((marker) => {
        mapRef.current!.removeLayer(marker);
      });
      markersRef.current = [];

      markers.forEach((markerProps) => {
        const marker = L.marker([markerProps.lat, markerProps.lng], {
          icon: getIcon(markerProps.status || "default"),
        });

        if (markerProps.popupData) {
          const popupContent = Object.entries(markerProps.popupData)
            .map(([key, value]) => `<b>${key}:</b> ${value}`)
            .join("<br/>");
          marker.bindPopup(popupContent);
        }

        marker.addTo(mapRef.current!);
        markersRef.current.push(marker);
      });
    }
  }, [markers, coordinates, zoom]);

  return <Box ref={mapContainerRef} style={{ height, width }} />;
};

export default LeafletMap;