Jquery muti select dropdown with checkbox

I’m trying to achieve jquery multi select dropdown with checkboxes with customized apply and cancel button inside dropdown. When I select Select All, dropdown is closing unexpectedly, even I tried to use stopPropagation but still it is closing the dropdown.

Any help would be highly appreciated

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>MultiSelect with Fixed Select All</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

  <!-- MultiSelect CSS & JS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.css">
  <script src="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.min.js"></script>

</head>
<body>

<h2>Select Options</h2>
<select id="my-select" multiple>
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
  <option value="date">Date</option>
</select>
</body>
</html>
    
    $(document).ready(function () {
  $('#my-select').multiselect({
    placeholder: 'Select fruits',
    onControlOpen: function () {
      const $optionsContainer = $('.ms-options');

      // Add Select All checkbox once
      if ($('.select-all-container').length === 0) {
        const $selectAllContainer = $(`
          <div class="select-all-container">
            <label><input type="checkbox" id="select-all-checkbox"> Select All</label>
          </div>
        `);
        $optionsContainer.prepend($selectAllContainer);

        // Real fix: Stop mousedown before plugin closes the dropdown
        $(document).on('mousedown', function (e) {
          if ($(e.target).closest('.select-all-container').length) {
            e.stopPropagation();
          }
        });

        $('#select-all-checkbox').on('change', function () {
          const isChecked = $(this).is(':checked');
          $('#my-select option').prop('selected', isChecked);
          $('#my-select').multiselect('reload');
        });
      }

      // Add Apply/Cancel buttons once
      if ($('.custom-button-wrapper').length === 0) {
        const $wrapper = $('<div class="custom-button-wrapper"></div>');

        const $apply = $('<button class="custom-button">Apply</button>').on('click', function () {
          const selected = $('#my-select').val();
          alert('Selected: ' + (selected ? selected.join(', ') : 'None'));
        });

        const $cancel = $('<button class="custom-button cancel">Cancel</button>').on('click', function () {
          $('#my-select').val([]).multiselect('reload');
          $('.ms-parent').find('.ms-drop').hide();
        });

        $wrapper.append($apply).append($cancel);
        $optionsContainer.append($wrapper);
      }
    }
  });
});
.custom-button {
      display: inline-block;
      margin: 10px 5px 5px;
      padding: 5px 10px;
      background-color: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    .custom-button.cancel {
      background-color: #dc3545;
    }
    .custom-button-wrapper {
      text-align: center;
      padding-bottom: 10px;
    }
    .select-all-container {
      padding: 5px 10px;
      border-bottom: 1px solid #ccc;
      background: #f9f9f9;
      user-select: none;
    }
    
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>MultiSelect with Fixed Select All</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

  <!-- MultiSelect CSS & JS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.css">
  <script src="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.min.js"></script>

</head>
<body>

<h2>Select Options</h2>
<select id="my-select" multiple>
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
  <option value="date">Date</option>
</select>
</body>
</html>

Javascript TypeError undefined on for loop only (not off-by-one) [duplicate]

I have a function that gets called when you click a button. I’m checking to see if the clicked item has the class “itm-active”. If it does, don’t do anything. Else check for elements that have it and remve the class from them. Also change the text of the button one the class has been removed.

The issue comes in when I’m trying to change the text of the button. If I hardcode an item, in this case items[0], I am able to change the text of the button. If I try to do the same thing within the for loop, I’m getting the error “Uncaught TypeError: items[i] is undefined”

NOTE: If I comment out the line items[i].innerHTML = “test”;. The line above it doesn’t give any error. I left comments on the lines in question to make it easy to see.

Also I don’t believe this to be off-by-one error, because if it was then I should get the same error with items[i].classList.remove(“itm-active”); as well, but I don’t.

Off-by-one error discussion here

function activeStatus (event) {

            let activeItem = event.srcElement.classList.contains("itm-active");

            if (activeItem) {

            } else {
                    //Remove itm-active from other places
                    items = document.getElementsByClassName("itm-active");

                    items[0].innerHTML = "test"; //This works fine
                    for (let i = 0; i < items.length; i++) {
                            if (items[i].classList.contains("itm-active")) {
                                    items[i].classList.remove("itm-active"); //This works fine
                                    items[i].innerHTML = "test"; //Doesn't work for some reason
                            }
                    }
            }
    }

Selenium intermittently fails to find JavaScript-injected data (“venueProfile”) in page source

I’m scraping the following page using Selenium:
https://www-eur.cvent.com/venues/en-US/dubai/hotel/delano-dubai/venue-12d8dd54-25d5-49f8-99a0-d292e52f3b34

My goal is to extract the venueProfile JSON that’s injected via JavaScript into the page. I use driver.page_source and a simple regex to find it.

Problem:
Sometimes, the “venueProfile” string is in the page source. Sometimes it’s not — without any code changes.

Expected behavior:
After WebDriverWait ensures the tag is loaded, the page source should always contain “venueProfile”. But that’s not consistently happening.

What I’ve tried:

Confirmed that the string is present in browser DevTools.

Saved debug.html on failure — in those cases, “venueProfile” is truly not present.

Added delays and waited for 10+ seconds.

Changed the user-agent string.

Verified that no exception is thrown — the page loads, but the data is missing.

Here’s the minimal code:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import re

options = Options()
options.add_argument("--headless")
options.add_argument("user-agent=Mozilla/5.0")

driver = webdriver.Chrome(options=options)
driver.get("https://www-eur.cvent.com/venues/en-US/dubai/hotel/delano-dubai/venue-12d8dd54-25d5-49f8-99a0-d292e52f3b34")

WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)

html = driver.page_source

match = re.search(r'"venueProfile":"(.*?)"', html)
print("Found" if match else "Not found")

driver.quit()

How can I ensure the JavaScript-generated content is reliably available before reading the page source?
Any best practices or techniques to improve reliability would be appreciated.

Synchronize Scrolling Between Two Divs of Different Heights

Problem :

I want two divs to scroll together in sync. For example, if the first div is halfway scrolled, the second should also be halfway through its own content, even though the two divs are different heights. I’m not sure how to link their scroll positions properly.

MINIMUM REPRODUCIBLE EXAMPLE :


for (i = 0; i < 10; i++) {
            document.querySelector(".right").insertAdjacentHTML("afterbegin", `<div class="box">${10 - i}</div>`)
        }
        for (i = 0; i < 20; i++) {
            document.querySelector(".main").insertAdjacentHTML("afterbegin", `<div class="box">${20 - i}</div>`)
        }
body{
            margin: 0px;
            padding: 0px;
        }
        .box {
            height: 200px;
            width: 250px;
            border: 2px solid red;
            margin: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: larger;
        }

        .cont {
            display: flex;
            align-items: flex-start;
        }
<div class="cont  ">
        <div class="main "></div>
        <div class="right "></div>
    </div>

How do I find clientWidth and clientHeight of an image whose element was created through jQuery?

I used jQuery to create image element of an image that exists. I appended the image element to the div where the image is supposed to appear. I tried to find the clientWidth and clientHeight of the image but both the clientWidth and clientHeight of the image were 0. On the other hand, naturalWidth and naturalHeight were correctly determined, How can I get the correct clientWidth and clientHeight of the image given that its element was created through jQuery?

let imageElement = $('<img>')
    .attr('src', 'path/image.jpg')
    .addClass('image')
    .css({width: '100%', 'max-width': '100%'});
    
    $('#div-container').prepend(imageElement);

 
$('.image').on('load', function (){
    
    const images = document.getElementsByClassName('image');
    
    let image = images[0];
    
    let naturalWidth = image.naturalWidth; //Correct width was found.
    let naturalHeight = image.naturalHeight; //Correct height was found.
    let renderedWidth = image.clientWidth; // I get 0 here.
    let renderedHeight = image.clientHeight; //I get 0 here.
});

How do I remove an event listener if the function for it is nested within another function?

This is a tricky situation. I am trying to create a SVG container which tracks mouse-drag movements.

So I have attached an onmousedown event listener to the container. If the mouse is held down, it starts a process where it attaches another mousemove listener which tracks the mouse’s movements.

However the function also ataches a mouseUp listener which is supposed to remove that mousemove listener.

The problem is that this mousemove listener function is within a scope of its own. So I cannot access it from the block which has the mouseup listener.

How do you get around this problem?

var svgCont = document.querySelector(".svgCont");

svgCont.addEventListener("mousedown", (e)=>{
    //e: init mouse pos
    startListeningForDrag([e.x, e.y]);
});


function startListeningForDrag(initMP){

    console.log("InitMP: " + initMP);

    svgCont.addEventListener("mousemove", function trackMouse(){
        console.log("tracking");
        
    });

    svgCont.addEventListener("mouseup", function(){
        svgCont.removeEventListener("mousemove", trackMouse )
    });

}

Sizing jpg content on innerHTML

I have a webpage with one tab called “Photos”. It is running locally. On selecting the tab it loads the photo called “Paris.jpg” which is 800px by 450px. No matter what I try, the photo is placed into a small box with scroll bars attached. I’d like the frame adjust to hold the entire photo with no scroll bars needed.

     <!DOCTYPE html>
     <html>
     <head>
     <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
    <style>
    body {
    font-size: 25px;
    font-family: Arial ;
    }

    .tab {
      overflow: visible;
    }

    /* Style the buttons inside the tab */
    .tab button {
      background-color: inherit;
      float: right;
      border: none;
      outline: none;
      cursor: pointer;
      padding: 7px 40px;
    }

    .tabcontent {
      display: none;
      position: relative;
    }
    </style>
     </head>
     <body>
    <div class="tab">
      <button class="tablinks" onclick="openActivity(event, 'Photos')">Photos</button>
    </div>
    <div id="Photos" class="tabcontent">
    </div>
    <script>
    function openActivity(evt, activityName) {
      var i, tabcontent, tablinks;
      tabcontent = document.getElementsByClassName("tabcontent");
      for (i = 0; i < tabcontent.length; i++) {
        tabcontent[i].style.display = "auto";
        tabcontent[i].style.overflow = "visible";
        tabcontent[i].innerHTML='<object type="text/html" data="Paris.jpg" ></object>';
        tabcontent[i].style.width = '100%';
        tabcontent[i].style.height = '100%';
      }
      tablinks = document.getElementsByClassName("tablinks");
      for (i = 0; i < tablinks.length; i++) {
        tablinks[i].className = tablinks[i].className.replace(" active", "");
      }
      document.getElementById(activityName).style.display = "block";
      evt.currentTarget.className += " active";
    }
    </script>
    </body>
    </html>

I tried adjusting display in the CSS and setting height and width to 100%. Nothing seems to work

Updating attribute of TipTap node

I’m using TipTap 2.12.0.

I’m trying to update the Heading extension so it adds a name attribute with a slugified version of the content of the heading so I can add anchor links that jump to a section in my document.

My extension looks like this:

export function slugify(text) {
  return text
    .toString()
    .toLowerCase()
    .trim()
    .replace(/s+/g, "-") // Replace spaces with -
    .replace(/[^w-]+/g, "") // Remove all non-word chars
    .replace(/--+/g, "-") // Replace multiple - with single -
    .replace(/^-+/, "") // Trim - from start of text
    .replace(/-+$/, ""); // Trim - from end of text
}


const CustomHeading = Heading.extend({
  renderHTML({ node, HTMLAttributes }) {
    HTMLAttributes["name"] = slugify(node.textContent);
    return this.parent?.({ node, HTMLAttributes });
  },
});

It works well when creating new header. However, I need to update this so it updates the value of the name attribute when the user changes the content of the heading.

I’ve tried to do this by adding onUpdate, however I can’t figure out how to get the updated content and change the attribute for the node being updated.

Anyone have any ideas?

Carousel with infinity scroll have double interval. How fix that on native js?

I wrote a slide with infinite scrolling:

  1. I clone the slides
  2. I get the id of the active one,
  3. Move the container so that the active slide is in the center,
  4. add autoscroll to the slides.

Now I have a problem that after a full
cycle, when switching from the cloned slide 1 to the original slide
1, there is a double delay before switching to slide 2
. This happens
because I remove the container blending animation and instantly
switch to the original slide 1, but the interval is not reset. I
tried resetting the interval but it didn’t work for me, so I did
something wrong. Since I don’t have enough knowledge to fix this, I
ask you to help fix this behavior. Why wasn’t there a double delay
when switching from the cloned slide 1 to the original slide 1 and
then to slide 2.

    // DOM
    const slider = document.querySelector(".slider");
    const sliderContainer = document.querySelector(".slider__track");
    let slides = Array.from(document.querySelectorAll(".slider__slide"));
    
    // Values
    const slidesPerView = 3;
    let activeSlideID = 0;
    let calculatedPos;
    
    // Functions
    const cloneSlides = function () {
       // clone slides and delete attribute 'data-active'
       const firstSlides = getCuttedSlidesArr("firstSlides", slides).map((slide) => cloneSlideWithoutAttr(slide));
       const lastSlides = getCuttedSlidesArr("lastSlides", slides).map((slide) => cloneSlideWithoutAttr(slide));
    
       // add clone to the beginning of "container" and to the end
       sliderContainer.append(...firstSlides);
       sliderContainer.prepend(...lastSlides);
    
       slides = Array.from(document.querySelectorAll(".slider__slide"));
    };
    
    function getCuttedSlidesArr(type, array) {
       if (type === "firstSlides") {
          return array.slice(0, slidesPerView);
       } else if (type === "lastSlides") {
          return array.slice(-slidesPerView);
       }
    }
    
    function cloneSlideWithoutAttr(slide) {
       const clonedSlide = slide.cloneNode(true);
       clonedSlide.removeAttribute("data-active");
       return clonedSlide;
    }
    
    function getIdFromActiveSlide() {
       for (let i = 0; i < slides.length; i++) {
          if (slides[i].hasAttribute("data-active")) {
             activeSlideID = i;
          }
       }
    }
    
    function centerActiveSlide() {
       const sliderWidth = slider.offsetWidth;
    
       const activeSlideWidth = slides[activeSlideID].offsetWidth;
       const activeSlideOffset = slides[activeSlideID].offsetLeft;
    
       const calculatedPos = sliderWidth / 2 - (activeSlideOffset + activeSlideWidth / 2);
    
       sliderContainer.style.transform = `translateX(${calculatedPos}px)`;
       sliderContainer.style.transition = `all`;
    }
    
    function autoChangeSlides() {
       if (activeSlideID < slides.length) {
          activeSlideID++;
          centerActiveSlide();
          sliderContainer.style.transform = `translateX(${calculatedPos}px)`;
          sliderContainer.style.transition = `0.5s ease`;
       }
    
       if (activeSlideID > slides.length - slidesPerView) {
          activeSlideID = slidesPerView;
          centerActiveSlide();
       }
    }
    
    // Call
    cloneSlides();
    getIdFromActiveSlide();
    centerActiveSlide();
    
    const autoChangeInterval = setInterval(autoChangeSlides, 1000);

here is link to codeopen for better understand: https://codepen.io/plupiks/pen/ZYYqpae

Website refreshes when executing SQLite DB command in Fastify backend (Nodemon + WebSocket issue)

I’m working on a school project where I built a ping pong game using JavaScript/TypeScript on the frontend, a Fastify backend, and SQLite3 as the database.

When a game ends, I want to store the game data in the database using the following code:

db.prepare(`
  CREATE TABLE IF NOT EXISTS games (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_name VARCHAR(100) NOT NULL,
    match_id VARCHAR(100) NOT NULL,
    player_id INTEGER NOT NULL,
    left_player_score INTEGER NOT NULL,
    right_player_score INTEGER NOT NULL,
    game_duration INTEGER NOT NULL,
    game_end_result VARCHAR(100) NOT NULL,
    left_player_ball_hit INTEGER NOT NULL,
    right_player_ball_hit INTEGER NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  )
`).run();

The first time this runs, the website refreshes and starts a new game, and the data that gets stored is incomplete. It seems that executing this DB command causes the page to reload and reestablish a WebSocket connection, starting a new game.

I suspected that nodemon was watching the intro.db file (the SQLite DB), so I added this to my package.json:

"dev": "nodemon --watch src --ignore src/db/intro.db"

But this did not fix the problem. It still behaves the same way.

Question:
Why does my site refresh and restart the game when the DB is modified, and how can I prevent this? Is this a nodemon config issue, or something else related to WebSocket or Fastify?

Any help is appreciated!

Scrapping Whatsapp Web Chats – Lazy Loading Problem

I’m trying to scrape WhatsApp Web contacts using Playwright. The goal is to scroll through the chat list and open each contact’s chat to extract their name and number from the profile panel.

WhatsApp uses lazy loading to render chats, initially loading as many chats as fit on your screen. As you scroll, additional chats are rendered, but the total number of visible chats remains the same.

Here’s the main issue I’m facing:

The script scrolls, but it reuses previously loaded chats again and again.

It doesn’t load new chats even after scrolling.

Also, the scrolling doesn’t behave correctly — it’s like the wrong container is being scrolled or the page isn’t triggering lazy loading.

Here’s the core part of my code:

const chatBoxes = await page.$$('#pane-side > div > div');
for (let i = 0; i < chatBoxes.length; i++) {
  const chat = chatBoxes[i];
  await chat.scrollIntoViewIfNeeded();
  await chat.click();
  await page.waitForTimeout(500);
  // extract contact info...
}

// scroll pane-side down
await page.evaluate(() => {
  const el = document.querySelector('#pane-side');
  if (el) el.scrollBy(0, 1000);
});

What I’ve Tried:

  • Scrolling #pane-side with scrollBy()
  • Using scrollIntoViewIfNeeded() on each chat
  • Adding delays to give WhatsApp time to load more chats
  • Trying to re-select the chat list after each scroll

Any help with a better strategy to reliably scroll and fetch all contacts from WhatsApp Web using Playwright would be appreciated!

How do I solve ollama qwen2.5-coder API error?

I have installed qwen2.5-coder:3b via ollama and when I want to use this API to generate Html/css components in my project it says
“Error generating content: API error! status: 404, message: Unknown error during generation.”

Please assist me in solving this error. As far as I know I have correctly routed to the correct functions in ai-service.js, in chat-route.js and chat-controller.js

The sendMessageToLLM() is used to communicate to the LLM in each function: generateComponentHtml() and generateFromTemplateMetadata(). in ai-service.js.
The ai-service.js is this:

const fetch = require('node-fetch');

// This service will handle all interactions with the LLM API


async function sendMessageToLLM(message) {
    // Call Ollama API for qwen 2.5-coder:3b
    const ollamaUrl = 'http://localhost:11434/api/generate';
    const payload = {
        model: 'qwen2.5-coder:3b',
        prompt: message,
        stream: false
    };
    try {
        const response = await fetch(ollamaUrl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        });
        if (!response.ok) {
            const errorText = await response.text();
            throw new Error(`Ollama API error! status: ${response.status}, message: ${errorText}`);
        }
        const data = await response.json();
        // Ollama returns { response: "..." } for /generate
        return { reply: data.response };
    } catch (error) {
        console.error('Error calling Ollama:', error);
        throw error;
    }
}


async function generateComponentHtml(request, templateId) {
    // Compose a prompt for the LLM
    const prompt = `Generate an HTML component for template ID: ${templateId}. User request: ${request}`;
    try {
        const llmResult = await sendMessageToLLM(prompt);
        return { html: llmResult.reply };
    } catch (error) {
        return { html: `<div class='error'>AI generation failed: ${error.message}</div>` };
    }
}


async function generateContentFromTemplateMetadata(templateMetadata) {
    // Compose a prompt for the LLM
    const prompt = `Generate a full HTML page structure for a website with the following metadata: ${JSON.stringify(templateMetadata)}`;
    try {
        const llmResult = await sendMessageToLLM(prompt);
        return {
            message: `Successfully generated content structure for ${templateMetadata.name}.`,
            html: llmResult.reply
        };
    } catch (error) {
        return {
            message: `AI generation failed: ${error.message}`,
            html: `<div class='error'>AI generation failed: ${error.message}</div>`
        };
    }
}


module.exports = {

    sendMessageToLLM,

    generateComponentHtml,

    generateContentFromTemplateMetadata

};

chat-controller.js:

const fs = require('fs');
const path = require('path');
const aiService = require('./ai-service');
const templates = require('../templates.json'); // Assuming templates.json is in the root for simplicity

// Load templates from JSON file
const loadTemplates = () => {
    try {
        const templatesPath = path.join(__dirname, '..', 'templates.json');
        const templatesData = fs.readFileSync(templatesPath, 'utf8');
        return JSON.parse(templatesData).templates;
    } catch (error) {
        console.error('Error loading templates:', error);
        return [];
    }
};

// Process user message and generate AI response
exports.processMessage = (req, res) => {
    try {
        const { message, templateId } = req.body;
        
        if (!message) {
            return res.status(400).json({ error: 'Message is required' });
        }
        
        // Simulate AI processing
        setTimeout(() => {
            // Generate a response based on the message
            let response = {
                text: `I've received your message about "${message}". Let me help you build that for your website.`,
                suggestions: [
                    'Add a contact form',
                    'Change the color scheme',
                    'Add a product gallery'
                ]
            };
            
            // If template-specific message, customize response
            if (templateId) {
                const templates = loadTemplates();
                const template = templates.find(t => t.id === templateId);
                
                if (template) {
                    response.text = `I'll help you customize your ${template.name} template based on your request: "${message}"`;
                    response.suggestions = template.features.map(feature => `Customize the ${feature} section`);
                }
            }
            
            res.json(response);
        }, 1000); // Simulate processing delay
    } catch (error) {
        console.error('Error processing message:', error);
        res.status(500).json({ error: 'Failed to process message' });
    }
};

// Generate website component based on user request
exports.generateComponent = async (req, res) => {
    try {
        const { request, templateId } = req.body; // componentType is not used by ai-service.js for now

        if (!request) {
            return res.status(400).json({ error: 'Request details are required' });
        }

        // Call AI service to generate component HTML
        const aiResponse = await aiService.generateComponentHtml(request, templateId);
        
        if (aiResponse && aiResponse.html) {
            res.json({ html: aiResponse.html });
        } else {
            console.error('Error: AI service did not return HTML content.');
            res.status(500).json({ error: 'Failed to generate component from AI service' });
        }

    } catch (error) {
        console.error('Error in generateComponent controller:', error);
        res.status(500).json({ error: 'Failed to generate component' });
    }
};

// Get website template suggestions
exports.getSuggestions = (req, res) => {
    try {
        const templates = loadTemplates();
        
        // Generate suggestions based on templates
        const suggestions = [
            'Create a landing page with a hero section and contact form',
            'Add a product showcase with images and descriptions',
            'Design a blog layout with featured posts',
            'Build a portfolio page to showcase your work'
        ];
        
        // Add template-specific suggestions
        templates.forEach(template => {
            suggestions.push(`Create a ${template.name.toLowerCase()} website with ${template.features.slice(0, 2).join(' and ')}`);
        });
        
        res.json({ suggestions });
    } catch (error) {
        console.error('Error getting suggestions:', error);
        res.status(500).json({ error: 'Failed to get suggestions' });
    }
};

// Controller function to handle AI content generation from template metadata
exports.generateContentFromTemplate = async (req, res) => {
    const { templateMetadata } = req.body;

    if (!templateMetadata || !templateMetadata.id) {
        return res.status(400).json({ message: 'Template metadata with ID is required.' });
    }

    // Optionally, re-fetch/validate template data from server-side templates.json
    // to ensure integrity, though editor.html already sends it.
    // 'templates' is available due to the first search/replace block adding the require.
    const serverTemplate = templates.templates.find(t => t.id === templateMetadata.id);
    if (!serverTemplate) {
        return res.status(404).json({ message: `Template with ID '${templateMetadata.id}' not found on server.` });
    }
    // Use the metadata sent from the client, which should be the enriched version

    try {
        console.log(`Chat Controller: Received request to generate content for template: ${templateMetadata.name}`);
        const result = await aiService.generateContentFromTemplateMetadata(templateMetadata);
        res.json(result);
    } catch (error) {
        console.error('Error in generateContentFromTemplate controller:', error);
        res.status(500).json({ message: 'Error generating content from template.', error: error.message });
    }
};

chat-route.js:

const express = require('express');
const router = express.Router();
const chatController = require('./chat-controller');

// Route to handle chat messages
router.post('/message', chatController.processMessage);

// Route to get website component based on user request
router.post('/generate-component', chatController.generateComponent);

// Route to handle AI content generation based on template metadata
router.post('/generate-content', chatController.generateContentFromTemplate);

// Route to get website template suggestions
router.get('/suggestions', chatController.getSuggestions);

module.exports = router;

Please help me fix the error!Any further queries? I would like to help.Thanks.

Cloud run crash “navigator is not defined”

I am trying to deploy a cloud run function, when I call it I get the error:

('require', 'ReferenceError: navigator is not definedn at funcA (/app/vm_us.js:630:13)n at funcB (/app/vm_us.js:1808:13)n at Object.<anonymous> (/app/vm_us.js:1814:77)n at Module._compile (node:internal/modules/cjs/loader:1364:14)n at Module._extensions..js (node:internal/modules/cjs/loader:1422:10)n at Module.load (node:internal/modules/cjs/loader:1203:32)n at Module._load (node:internal/modules/cjs/loader:1019:12)n at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:203:29)n at ModuleJob.run (node:internal/modules/esm/module_job:195:25)n at async ModuleLoader.import (node:internal/modules/esm/loader:337:24)')"

My code is in python and it uses the javascript python package to call functions from a vm_us.js file. On my computer this works fine. The Window and Navigator objects in the JS code are Node.js objects (when I go to definition they are in Node->typescript). Also when I print out navigator.useragent it outputs “Node.js”. Because of this I added Node.js and typescript to the docker image, but it still does not work. I cannot ommit Navigator/Window from my code and I still want to deploy this as an api, how can I do this?

Docker File

FROM python:3.11-slim

# Install Node.js 18
RUN apt-get update && 
    apt-get install -y curl gnupg build-essential && 
    curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && 
    apt-get install -y nodejs && 
    apt-get clean && 
    rm -rf /var/lib/apt/lists/*

# Set environment
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app

# Copy requirements and install
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy Node.js package files and install Node packages
COPY package*.json ./
RUN npm install

# Copy all project files
COPY . .

# Set Flask environment variables
ENV PORT 8080
ENV GOOGLE_APPLICATION_CREDENTIALS /app/service.json

# Expose port
EXPOSE 8080

# Start the Flask app
CMD ["python", "main.py"]

Package.json

{
  "name": "gen2",
  "version": "1.0.0",
  "description": "**To Update/Deploy**",
  "main": "vm.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^22.15.3",
    "typescript": "^5.8.3"
  }
}

Code

function funcA() {
    var A = navigator.userAgent.match(/Firefox/([0-9]+)./i);
    return !(!A || !A[1]) && parseInt(A[1])
}

function funcB() {
    var A = navigator.userAgent.match(/Version/([0-9._]+).*Safari/);
    return A ? A[1].split(".").map(function (A) {
        return (A = parseInt(A, 10)) || 0
    })[0] : 0
}

// + 4k lines using navigator like this