Selecting elements in Chrome Extension Popup

I’m working on a Google Chrome extension, and I have the HTML of the popup. I have an element called #switch, but document.querySelector(‘#switch’) isn’t working as a selector. It just returns null.

Any ideas on what to do?

document.addEventListener('DOMContentLoaded', function() {
  let switchElement = document.querySelector('#switch')
  console.log(switchElement)
  switchElement.addEventListener('change', () => {
    console.log(switchElement)
  })
})

I tried adding an event listener for DOM CONTENT LOADED, but that didn’t work.

Site romântico para noiva [closed]

Fala galera, estou fazendo um site para presentear minha noiva e a ideia é a seguinte:

Colocar diversas fotos falando sobre nossa história e do meu amor por ela (essa parte eu até já fiz), após declarações queria colocar uma caixa onde podemos marcar eventos, terá uma lista de eventos que ela pode selecionar um marcando com uma checkbox e do lado dessa checkbox haverá como marcar uma data, mês, ano e horário. A ideia é poder marcar nossos encontros e rolês no site pelo resto da vida.

<div>
    <input type="checkbox" id="scales" name="scales" checked />
    <label for="scales">Jantar</label>  <br>    
    <label>Data do evento</label>
    <input type="date" name="data"> 
    <label>Mensagem: <textarea>
</textarea>
  </div>

comecei assim, porém a data ela não fica fixa. Queria que ela pudesse alterar quando quisesse, tipo: um evento em 24/03/2032… e essa data se manter mesmo depois de recarregar o site.

How to Simultaneously Load and Autoplay Multiple MP4 Videos on a Pure HTML Page Without Stopping?

I have a pure HTML page (no frameworks like React or Vue) that needs to load and autoplay six MP4 videos, each approximately 800KB in size. My goal is to make them play simultaneously without any of them stopping.

I’ve tried using the preload attribute, but it didn’t solve the issue. Most of the time, some videos stop while others continue to play.

What techniques can I use to ensure that all videos load fully and play simultaneously without stopping?
Are there any best practices or alternative approaches for handling multiple video playback on a webpage?

Any help or suggestions would be greatly appreciated!

Can’t access data from sqlite db with js

I’m trying js from the first time and want to make a website, I need to get data from a users database to verify them but i can’t figure out how

const sqlite3 = require('sqlite3').verbose();
var sql;

//connect to db
const db = new sqlite3.Database('./test.db',sqlite3.OPEN_READWRITE,(err)=>{
  if (err) return console.error(err.message);
});

function create_table(){
  sql = 'CREATE TABLE users(id INTEGER PRIMARY KEY,name,city,password,email)';
  db.run(sql);
}

function query_data(){
  let data = [];
  sql = 'SELECT * FROM users';
  db.all(sql,[...arguments],(err,rows)=>{
    if (err) return console.error(err.message);
    rows.forEach(row=>{
      console.log(row);
      data.push(row);
    })
  })
  return data;
}

exports.query_data = query_data

the plan is to import this later in the node.js server file to do the verification

When I run the code, the variable data was empty, yet the rows where being printed

Is there another way this should be inplemented?

Why: my javascript functions do not trigger errors with audio elements loaded from HTML but do with audio elements added programmatically

Background

Stuff that’s always worked fine

I’ve got a series of automatically generated HTML pages that can have anywhere between 24 and 180 (or more) audio elements loading separate audio files. Each audio element has its own controls (play/pause button, replay button).

I’ve implemented a series of JavaScript functions and event handlers that take care of playing the audio files only once they’re ready and the UI of the buttons. I’ve used this script in production for months with no issues at all (see Code section).

New Feature

I’ve been building a feature so users can record audio as a response to about half of the audio elements already on the page. I’ve added to the original script, and the addition to the script

  • handles all the recording logic,
  • uploads the recorded blob to my server,
    • (which sends it to a cloud storage service, and the server returns a signed URL to the resource),
  • and creates another audio element to be added to the same container as the audio element the recording is in response to.

Problem

The programmatically added audio elements use all the same JS functions as the audio elements that are loaded in the initial HTML page, but now I’m getting errors when playing/pausing a puzzling variety of audio elements on the page (happens seemingly randomly, both with original audio elements and programmatically added audio elements).

Here is the error message I’m getting:

Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

Why am I getting the error message now but not before?

Speculations

  • Am I now getting this error message because the programmatically added audio elements don’t have preload="auto" set like the ones from the server have?
  • I can see that I’m not handling the .play() promise the same as is recommended in this Chrome Developer article, but also 1) I don’t see how I would integrate it and 2) don’t understand why it is an issue now but wasn’t before
    • Was my code never handling the interaction between the .play() promises and the .pause actions correctly but now that I’m increasing the number of audio elements by 50% the issue is coming cropping up somehow?

Code

HTML structure

The page mostly consists of a bunch of these <li> elements. Each <audio> element is within a container of class audioContainer, and my event handlers search within the parent audioContainer to find which audio element to play.

<li class="line int int-norm TR nonPowerLang" lang="es-US">
  <div class="lineLabelCtrlzWrapper">
    <h4 class="metaInfo">
      <span class="speakerTag">Int</span>
      <span class="trunkOrBranchTag">TR-</span><span class="dialogueID">11</span>
    </h4>
    <div>
      <div class="playAudioCtrlzContainer audioContainer">
        <audio
          id="TR-11"
          class="dialogueAudio"
          src="/static/audio/en/es/hear/tr-11.mp3"
          preload="auto"
        >
        </audio>
        <button type="button" name="playPauseBtn" class="svgBtn playPauseBtn playDialogueBtn" title="buffering..." disabled>
          <img height="22px" width="22px" class="playIcon spinny" src="/static/svg/buffer.svg" alt="buffering icon" />
        </button>
        <button type="button" name="replayBtn" class="svgBtn replayBtn poof" title="replay audio">
          <img height="22px" width="22px" class="replayIcon" src="/static/svg/replay_forward.svg" alt="replay icon" />
        </button>
      </div>
      <div class="recordAudioCtrlzContainer">
        <form action="" method="post" class="recordForm">
          <input type="hidden" name="csrfmiddlewaretoken" value="BLAHBLAHBLAHBLAHBLAH">
          <input type="hidden" class="line_id" value="713" />
          <button type="submit" name="recordBtn" id="record_713" class="svgBtn recordBtn poof" title="start recording" >
            <img height="28px" width="28px" class="recordIcon" src="/static/svg/mic.svg" alt="microphone icon" />
          </button>
          <button type="button" name="stopRecordBtn" id="stopRecord_713" class="svgBtn stopRecordBtn recordingPulse poof" title="stop recording" >
            <img height="20px" width="20px" class="stopIcon" src="/static/svg/stop.svg" alt="stop icon" />
          </button>
        </form>
        <div class="recordingIndicator">
          <div class="poof simpleCheckmarkContainer">
            <img height="30px" width="30px" class="simpleCheckIcon" src="/static/svg/simple_check.svg" alt="checkmark icon" />
          </div>
        </div>
      </div>
    </div>
  </div>
  <p class="poof dialogueText">¿Sr. López?</p>
  <div class="recordingPlayback audioContainer poof">
    <!-- here is where <audio> element from recording will get prepended -->
    <img height="28px" width="28px" class="recordingIcon" src="/static/svg/recording.svg" alt="tape recorder icon" />
    <button type="button" name="playPauseBtn" id="playRecording_713" class="svgBtn playPauseBtn playRecordingBtn poof" title="play audio" >
      <img height="22px" width="22px" class="playIcon" src="/static/svg/play.svg" alt="play icon" />
    </button>
    <button type="button" name="replayBtn" class="svgBtn replayBtn poof" title="replay audio">
      <img height="22px" width="22px" class="replayIcon" src="/static/svg/replay_forward.svg" alt="replay icon" />
    </button>
  </div>
</li>

Javascript

Original JavaScript (functions to play audio and handle UI)

const allPlayButtons = document.querySelectorAll(".playPauseBtn");
const allReplayButtons = document.querySelectorAll(".replayBtn");

/* Function to pause all audios */
const pauseAll = async function() {
  let allYeAudios = document.querySelectorAll("audio");
  allYeAudios.forEach((item, i) => {
    item.pause()
  });
};

/* Function for playing or pausing audio associated with play/pause button */
const playOrPause = async function(btn) {
  let soundByte = btn.closest('.audioContainer').querySelector('audio');
  
  if (!soundByte.loaded) {
    soundByte.load();
    soundByte.manuallyloaded = true;
  } else {
    if (soundByte.paused) {
      // pause other audios before playing
      await pauseAll();
      // play the audio
      soundByte.play();
    } else {
      soundByte.pause();
    }
  }
};

/* Function for playing audio from start when replay button is hit */
const playFromStart = async function(btn) {
  let soundByte = btn.closest('.audioContainer').querySelector('audio');

  if (!soundByte.loaded) {
    soundByte.load();
    soundByte.manuallyloaded = true;
  } else {
    // pause other audios before playing
    await pauseAll();
    soundByte.currentTime = 0;
    soundByte.play();
  }
};

/* Function for any click on an audio control btn */
const audioContainerClickHandler = function() {
  switch (this.name) {
    case 'playPauseBtn':
      playOrPause(this);
      break;
    case 'replayBtn':
      playFromStart(this);
      break;
  }
};

/* Function to:
--1) change play/pause button icon to play or pause symbol
--2) cause replay button to display while audio is playing
----------------*/
const changeAudioControlGraphics = async function(e) {
  let playPauseBtn = e.target.closest('.audioContainer').querySelector('.playPauseBtn');
  let replayBtn = e.target.closest('.audioContainer').querySelector('.replayBtn');
  switch (e.type) {
    case 'playing':
      changeAudioControlBtn(playPauseBtn, paTitle, paSVG, paAlt);
      replayBtn.classList.remove('poof');
      break;
    case 'pause':
    case 'canplay':
      if (e.target.manuallyloaded) {
        delete e.target.manuallyloaded;
        // pause other audios before playing
        await pauseAll();
        e.target.play();
        changeAudioControlBtn(playPauseBtn, paTitle, paSVG, paAlt);
        replayBtn.classList.remove('poof');
        e.target.loaded = true;
      } else if(e.type == 'canplay'){
        e.target.loaded = true;
      }
      changeAudioControlBtn(playPauseBtn, plTitle, plSVG, plAlt);
      break;
    case 'ended':
      if (e.target.manuallyloaded) {
        delete e.target.manuallyloaded;
        // pause other audios before playing
        await pauseAll();
        e.target.play();
        e.target.loaded = true;
      } else if(e.type == 'canplay'){
        e.target.loaded = true;
      }
      changeAudioControlBtn(playPauseBtn, reTitle, reSVG, reAlt);
      replayBtn.classList.add('poof');
      break;
    default:
      changeAudioControlBtn(playPauseBtn, buTitle, buSVG, buAlt, true);
      break;
  }
};

// look for clicks on audio control btns
allPlayButtons.forEach((item, i) => {
  item.addEventListener("click", audioContainerClickHandler);
});
allReplayButtons.forEach((item, i) => {
  item.addEventListener("click", audioContainerClickHandler);
});

// change visuals upon play and pause
dialogueSection.addEventListener("playing", changeAudioControlGraphics, true);
dialogueSection.addEventListener("pause", changeAudioControlGraphics, true);
// and these other 3 events
dialogueSection.addEventListener("canplay", changeAudioControlGraphics, true);
dialogueSection.addEventListener("emptied", changeAudioControlGraphics, true);
dialogueSection.addEventListener("ended", changeAudioControlGraphics, true);

Added JavaScript (record audio and create audio elements from the recorded audio)

Mostly pay attention to the if (response.ok) {} block within the uploadInterpretation() function because it is the code creating the audio element.

const allRecordForms = document.querySelectorAll(".recordForm");

// User media constraints
const constraints = {
  audio: true,
  video: false,
};

// sundry global variables for recording logic
var currentlyRecording = false;
var doneRecording = false;

// function to change UI for record button
const changeRecordBtnUI = async function(container) {
  const recordBtn = container.querySelector(".recordBtn");
  const stopBtn = container.querySelector(".stopRecordBtn");
  const checkMark = container.querySelector(".simpleCheckmarkContainer");

  if (currentlyRecording === false && doneRecording === false) { // recording is actually happening..
    changeAudioControlBtn(recordBtn, buTitle, buSVG, buAlt, true); // buffer icon for recordBtn
    allRecordButtons.forEach((btn, i) => { // disable all record btns
      if (btn !== recordBtn) {
        btn.disabled = true;
      }
    });
  } else if (currentlyRecording === false && doneRecording === true) { // if we done recording..
    changeAudioControlBtn(stopBtn, stopTitle, stopSVG, stopAlt); // take off buffer UI for stopBtn (i.e., reset)
    stopBtn.disabled = true;
    stopBtn.classList.add("poof", "done"); // disappear stopBtn (and give "done" class)
    checkMark.classList.remove("poof"); // appear checkmark
    allRecordButtons.forEach((btn, i) => { // un-disable all other record btns
      if (btn !== recordBtn && !btn.classList.contains("done")) {
        btn.disabled = false;
      }
    });
  } else if (currentlyRecording === true) { // once recording is actually happening..
    changeAudioControlBtn(recordBtn, recTitle, recSVG, recAlt); // take off buffer UI for recordBtn (i.e., reset)
    allRecordButtons.forEach((btn, i) => { // disable all record btns (including present company)
      if (btn !== recordBtn) {
        btn.disabled = true;
      }
    });
    recordBtn.classList.add("poof", "done"); // disappear record button and give it "done" class
    stopBtn.classList.remove("poof"); // appear stopBtn
  }
};

// declare mediaRecorder
var mediaRecorder;
// options for recorder
const recorderOptions = {
  audioBitsPerSecond: 44100,
};

const recordInterpretation = async function(stream) {
  return new Promise((resolve, reject) => {
    const chunks = [];
    mediaRecorder = new MediaRecorder(stream, recorderOptions);
    console.log("MediaRecorder initialized with state:", mediaRecorder.state);

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

    mediaRecorder.addEventListener('stop', () => {
      console.log("MediaRecorder stop event detected");
      const blob = new Blob(chunks, {type: "audio/webm",});
      stream.getTracks().forEach(track => track.stop());
      resolve(blob);
    });

    mediaRecorder.onerror = (err) => {
      console.error("MediaRecorder error:", err);
      reject(err);
    };

    mediaRecorder.start();
    console.log("MediaRecorder started with state:", mediaRecorder.state);
  });
};

const stopRecording = function() {
  console.log("stopRecording function has been called")
  return new Promise((resolve, reject) => {
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
      console.log("MediaRecorder state before stopping:", mediaRecorder.state);
      mediaRecorder.onstop = () => {
        console.log("MediaRecorder onstop event triggered");
        resolve();
      };
      mediaRecorder.stop();
    } else {
      console.log("MediaRecorder is either not initialized or already inactive");
      reject(new Error('No active recording to stop'));
    }
  });
};

const uploadInterpretation = async function(lineForm, blob) {
  const line_id = lineForm.querySelector("input.line_id").value;
  const intUploadEndpointFull = `bunchOfStuff/for/endpoint`;
  console.log(`Interpretation Creation endpoint is: ${intUploadEndpointFull}`);
  // append data
  const formData = new FormData();
  formData.append('audio_file', blob, 'interpretation.webm');
  for (let [key, value] of formData.entries()) {
    console.log(key, value);
  }

  // fetch request
  try {
    const response = await fetch(intUploadEndpointFull, {
      method: 'POST',
      headers: {
        'X-CSRFToken': lineForm.querySelector('[name=csrfmiddlewaretoken]').value,
      },
      body: formData
    });

    if (response.ok) {
      const data = await response.json();
      console.log('Interpretation uploaded successfully:', data);
      // attach returned audio url to a new audio element and place inside correct .audioContainer element
      const playback_audio_container = lineForm.closest("li.line").querySelector(".recordingPlayback");
      const playback_audio_element = document.createElement("audio");
      playback_audio_element.src = data.audio_file;
      playback_audio_element.classList.add("intPlaybackAudio");
      playback_audio_element.id = `intPlaybackAudio_${line_id}`;
      playback_audio_container.prepend(playback_audio_element);
      const playback_playBtn = playback_audio_container.querySelector(".playPauseBtn");
      const playback_replayBtn = playback_audio_container.querySelector(".replayBtn");
      playback_playBtn.addEventListener("click", audioContainerClickHandler);
      playback_replayBtn.addEventListener("click", audioContainerClickHandler);
      if (isItCurrentlyReviewMode === true) { // if in review mode, appear audio container
        playback_audio_container.classList.remove("poof");
      }
      return data;
    } else {
      throw new Error('Failed to upload interpretation');
    }
  } catch (error) {
    console.error('Error uploading interpretation:', error);
    throw error;
  }
};

const handleRecordingProcess = async function(event) {
  event.preventDefault();
  const lineForm = this;
  const lineWrapper = lineForm.closest("li.line");
  const recordInterpretationContainer = lineForm.closest(".recordAudioCtrlzContainer");
  const lineStopBtn = lineForm.querySelector(".stopRecordBtn");
  doneRecording = false;
  
  if (!currentlyRecording) {
    try {
      // this should change recordBtn to buffer icon
      await changeRecordBtnUI(recordInterpretationContainer);
      // then we start up the stream
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      // then we mark we are recording to change UI (disappear recordBtn, appear stopBtn)
      currentlyRecording = true;
      await changeRecordBtnUI(recordInterpretationContainer);
      analyzeAudio(stream, lineWrapper);
      // start the recording up
      const recordingPromise = recordInterpretation(stream);
      lineStopBtn.onclick = async () => {
        changeAudioControlBtn(lineStopBtn, buTitle, buSVG, buAlt, true); // buffer icon for stopBtn
        try {
          console.log("now trying to stop recording");
          // stop the recording and get the blob
          await stopRecording();
          // stop the UI jambly
          await stopAudioAnalysis();
          lineWrapper.classList.remove("recordingUnderway");
          if (lineWrapper.classList.contains("simul")) {
            lineWrapper.style.outline = "7px solid #feb01d";
          } else {
            lineWrapper.style.outline = "unset";
          }
          lineStopBtn.classList.remove("recordingPulse"); // get rid of pulsing for stopBtn (what indicates that it is recording)
          console.log("Recording stopped, now waiting for blob");
          // get the blob
          const blob = await recordingPromise;
          console.log("recording has now stopped. now trying to upload")
          
          // upload blob
          await uploadInterpretation(lineForm, blob);
          
          // change global variables (and UI accordingly to show file was uploaded successfully)
          currentlyRecording = false;
          doneRecording = true;
          await changeRecordBtnUI(recordInterpretationContainer);
          
        } catch (error) {
          console.error('Error stopping recording:', error);
        }
      };
    } catch (error) {
      console.error('Error in stopping recording or getting blob:', error);
    }
  } else {
    console.log('Already recording');
  }
};

allRecordForms.forEach((form, i) => {
  form.addEventListener("submit", handleRecordingProcess)
});

jquery validate make one field required if another field is not empty

I’m having some issues with jQuery.validate 1.11 , with .Net 4.8 and MVC 5 with Razor.

I have these two properties in my class:

[StringLength(500, ErrorMessage = "{0} can have a max of {1} characters")]
public string MyProperty { get; set; }

[StringLength(100, ErrorMessage = "{0} can have a max of {1} characters")]
public string MyOtherProperty { get; set; }

And on my Razor page I have this:

@Html.TextBoxFor( m => m.MyProperty )
@Html.TextBoxFor( m => m.MyOtherProperty  )

@using (Html.BeginScripts()) {
    <script src="@Url.Content( "~/Scripts/MyScriptFile.js" )" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            MyScriptModule.Init();
        }); // end of document.ready
    </script>
}

And then my Javascript file is like this:

var $form = $("#MyForm");
var $submit = $("#Save");

var MyScriptModule = (function () {

    var init = function () {
    
    $submit.bind("click", function () {
        HandleSubmitLogic();
    });
    
    // Initialize form validation
        $form.validate({
            ignore: [],
            rules: {
                MyOtherProperty: {
                    required: function (element) {
                        return $("#MyProperty").val().length > 0;
                    }
                } 
            },
            errorPlacement: function (error, element) {
                error.appendTo(element.parent());
            },
        });

    }; // end init 
    
    function HandleSubmitLogic() {

        $submit.prop("disabled", true);
        ResetFormValidation($form);
        $form.validate();
        if ($form.valid()) {
            $form.submit();
        }
        $submit.prop("disabled", false);
    }
}

So the length validation fires as expected, but I can’t get that rule to work, where MyOtherProperty is required IF MyProperty has a value. I got this from another StackOverflow link here, and it seems to fit with the online documentation here.

So what am I doing wrong?

Is there any way to get the detailed error behind “TypeError: Failed to fetch”?

I’m trying to debug why <2% of my users receive “TypeError: Failed to fetch” on a given endpoint. I’m seeing this error in Sentry, but I cannot reproduce it.

What I’ve figured out is that browsers will print a detailed error line in the console about what the actual error is (CORS policy, net::ERR_FAILED, net::ERR_INTERNET_DISCONNECTED, etc.), but there is no way to actually read this from the application. All I get is “TypeError: Failed to fetch”, no matter what I try in JS.

I believe the “replay” session debug tools won’t be able to capture this either.

Is there a way in JS to capture the detailed messages, or are they pretty much only visible on the client’s screen if the console is opened?

Create a AppScript Email trigger for a Google Sheet that is connected to a Datasource

Can’t create an automated email on Appscript each time my Google Sheet connected to a Big Query Table updates, meaning each time a new entry has been detected.

Please find my code below.

// Helper function to get the active sheet
function getActiveSheet(e) {
  if (!e) {
    Logger.log("No event object, this function should be triggered by an event.");
    return null;
  }
  return e.source.getActiveSheet();
}

// Function to send email
function sendEmail(e) {
  if (!e) {
    Logger.log("No event object, this function should be triggered by an event.");
    return;
  }

  var sheet = getActiveSheet(e);
  if (!sheet) {
    Logger.log("No active sheet found.");
    return; // Exit if no sheet is found
  }


  var range = e.range;
  // if (!range) {
  //   Logger.log("No range found.");
  //   return; // Exit if no range is found
  // }
  
  // Define email details
  var recipient = "[email protected]."; // Change this to your email
  var subject = "EOI Google Sheet Updated";
  var message = "Your Sheet link was updated: nn";
  
  // Get the updated values
  // var values = range.getValues();
  // for (var i = 0; i < values.length; i++) {
  //   for (var j = 0; j < values[i].length; j++) {
  //     message += values[i][j] + " ";
  //   }
  //   message += "n";
  // }
  
  // Send the email
  MailApp.sendEmail(recipient, subject, message);
}

// Function to create a trigger for the sendEmail function
function createEditTrigger() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  ScriptApp.newTrigger('sendEmail')
    .forSpreadsheet(sheet)
    .onChange()
    .create();
}

I’m a DataAnalyst, but I’ve faced an issue I’m determined to solve.
I have a Google Sheet that I have connected to a Google BigQuery (BQ) Table through a Query.
The Query runs every hour and if a new entry has entered the table, that entry populates into the sheet.

Now I’m trying to use AppScript to create a trigger that sends out an email each time there has been a change in the Google Sheet, meaning a new entry. I struggle mainly with the notification that its Data Sources aren’t supported. However throughout my attempts I had various different notifications.

As of now I’ve commented out the Range part, as AppScript struggles to read Datasource sheets.

Java Script Nested Loop [closed]

How can I achieve this achieve this using nested Loop in Javascript. I’ve been trying to get it done, I was stocked

I don’t know much about nested loop, just learning. It was an assignment. I would love if anyone can assist me with it.

Why not-found.tsx doesn’t work on specific route?

I created not-found.tsx for the /blogs/[id] route, but for some reason it does not work exactly on that route. For the rest application global not-found.tsx works properly. Maybe it is because /blogs/[id] has a parallel route and there is something wrong with default.tsx ?

enter image description here

There error screenshot:

enter image description here

Code from layout.tsx:

import { fetchBlogById } from '@/app/lib/data';
import { notFound } from 'next/navigation';
import type { Metadata } from 'next';

interface Props {
  params: { id: string };
}

export async function generateMetadata({ params: { id } }: Props): Promise<Metadata> {
  const blog = await fetchBlogById(id);

  if (!blog) notFound();

  return {
    title: {
      template: `%s | ${blog.title}`,
      default: blog.title,
    },
  };
}

export default function Layout({
  children,
  modal,
}: {
  children: React.ReactNode;
  modal: React.ReactNode;
}) {
  return (
    <div>
      {children}
      {modal}
    </div>
  );
}

How can I fix this bug?

How to Init Flowbite functions when using it through CDN

I’m working on a website that is basically a CRUD. Since it’s hosted on a managed server, I’m using HTML, Tailwind CSS/JS, Flowbite CSS/JS, jQuery with AJAX and PHP. Here’s the structure of my page with all the appropriate references:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>My Page</title>

    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/flowbite.min.css" rel="stylesheet" />
</head>

<body class="customers">

    <!-- Table with data -->
    <div class="relative overflow-x-auto rounded-lg">
        <table id="CustomersTable" class="min-w-full text-sm text-left rtl:text-right text-black">
            <thead class="text-xs text-center uppercase bg-gray-200">
                <tr>
                    <th scope="col" class="border-r border-gray-400 px-6 py-3">
                        Name
                    </th>
                    <th scope="col" class="border-r border-gray-400 px-6 py-3">
                        Web
                    </th>
                    <th scope="col" class="border-r border-gray-400 px-6 py-3">
                        Email
                    </th>
                </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>

    <!-- Main modal -->
    <div id="customer_modal" tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
        <div class="relative p-4 w-full max-w-4xl max-h-full">
            <!-- Modal content -->
            <div class="relative bg-white rounded-lg shadow">
                <!-- Modal header -->
                <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t">
                    <button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center" data-modal-toggle="customer_modal">
                        <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
                            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
                        </svg>
                        <span class="sr-only">Close modal</span>
                    </button>
                </div>
                <!-- Modal body -->
                <form class="p-4 md:p-5">
                    <div class="grid gap-4 mb-4 grid-cols-2">
                        <div>
                            <label for="name" class="block mb-2 text-sm font-medium text-black">Name</label>
                            <input type="text" id="name" class="bg-gray-50 border border-gray-300 text-black text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" required />
                        </div>
                        <div>
                            <label for="web" class="block mb-2 text-sm font-medium text-black">Web</label>
                            <input type="text" id="web" class="bg-gray-50 border border-gray-300 text-black text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" required />
                        </div>
                        <div>
                            <label for="email" class="block mb-2 text-sm font-medium text-black">Email</label>
                            <input type="email" id="email" class="bg-gray-50 border border-gray-300 text-black text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" required />
                        </div>
                    <button type="submit" class="text-white inline-flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center">
                        Save
                    </button>
                </form>
            </div>
        </div>
    </div> 

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/flowbite.min.js"></script>
    <script src="/scripts/app.js"></script>
</body>
</html>

I dynamically populate the table body based on the response from the server using jQuery and AJAX using the following code:

$(document).ready(function() {  
    if ($('body').hasClass('customers')) {
        fetchCustomers();

        function fetchCustomers() {
            let requestData = {
                action: "CustomerTable"
            };

            $.ajax({
                url: '/customers',
                type: 'POST',
                data: requestData,
                dataType: 'json',
                success: function(response) {
                    let tableBody = $('#CustomersTable tbody');
                    tableBody.empty();

                    response.forEach(function(customer) {
                        let row = $('<tr class="odd:bg-white even:bg-gray-100 border-b hover:bg-gray-200 whitespace-nowrap"></tr>');
                        row.append($('<td class="px-6 py-4" data-modal-target="customer_modal" data-modal-show="customer_modal"></td>').text(customer.name));
                        row.append($('<td class="px-6 py-4"></td>').text(customer.web));
                        row.append($('<td class="px-6 py-4"></td>').text(customer.email));
                        tableBody.append(row);
                    });
                }
            });
        }
    }
});

This works great. However, I’d also like to allow the user to click on any row of the column Name and open the modal form included in my HTML code. For this, the jQuery code adds the attributes data-modal-target="customer_modal" data-modal-show="customer_modal" to each customer name on the table. However, since this happens after the page is loaded, Flowbite doesn’t recognize the new data-* attributes and nothing happens.

I’ve searched the documentation and found that you can reinitialize Flowbite to properly identify all data attributes after the page has loaded (Tailwind CSS JavaScript – Flowbite). I’m supposed to just do something like initFlowbite(); at the end of my JavaScript code. Unfortunately, when trying to do so the problem persists and I get a console log saying that initFlowbite(); is not defined. I believe the code import { initFlowbite } from 'flowbite' is only compatible when you are working with modules and have access to the command line of the server.

Could anyone please help me fix this problem? I greatly appreciate any suggestions to be able to successfully reinitialize Flowbite event handlers whenever needed based on my current set up.

Chrome Extensions only working for certain websites

so I am making a chrome extension that displays a box overlayed on the tabs displaying the current spotify song you are playing. I have gotten everything to work except for the fact that when I click on the tab to display the box, only certain websites like chatgpt and my own localhost show the box, with all other websites (like stackoverflow and youtube) not showing anything. Below, I’ve attached my manifest.json and script.js files which should have the necessary permissions to modify the tabs and the code itself but any advice and help would be appreciated. In the code below I attached some code ti display the error if the tab doesn’t allow the box and this is the error that appears:”Cannot access contents of the page. Extension manifest must request permission to access the respective host.” The amount of hello’s I have in this code is because of me using hello to display the box before I integrated the Spotify API so I apologize if that causes some confusion. Thank you.

manifest.json file
{
  "manifest_version": 3,
  "name": "Spotify Song Shower",
  "version": "1.0",
  "type": "module",
  "description": "A simple Chrome extension that displays the current song playing from Spotify in the top left corner of the window.",
  "action": {
    "default_popup": "index.html"
  },
  "dependencies": {
    "express": "^4.17.1",
    "node-fetch": "^3.0.0",
    "querystring": "^0.2.0"
  },
  "permissions": ["tabs", "scripting", "activeTab", "notifications"],
  "background": {
    "service_worker": "background.js"
  },
  "host_permissions": ["<all_urls>", "http://*/*", "https://*/*"],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["script.js"]
    }
  ]
}

script.js file (the file that runs and displays the box)

async function addbox(TrackName) {
  // Creating and styling the box. It is on the top left of the screen and should show the current song playing
  const helloBox = document.createElement("div");
  helloBox.id = "hello-box";
  helloBox.style.position = "fixed";
  helloBox.style.top = "0px";
  helloBox.style.left = "0px";
  helloBox.style.padding = "5px 10px 5px 10px";
  helloBox.style.backgroundColor = "black";
  helloBox.style.color = "green"; // Font color of the text
  helloBox.style.zIndex = "1000";
  helloBox.style.borderRadius = "0 0 10px 0"; // Rounded bottom-right corner
  helloBox.style.fontSize = "16px";
  helloBox.style.textAlign = "center";
  helloBox.style.whiteSpace = "nowrap";
  helloBox.style.display = "inline-block"; // Size the box based on content width

  //console.log(typeof TrackName);
  //console.log(TrackName);
  helloBox.innerText = "Song: " + TrackName;
  document.body.appendChild(helloBox);
}
// When the button in index.html is clicked this is triggered causing the events inside to happen
document.addEventListener("DOMContentLoaded", () => {
  document.getElementById("showHello").addEventListener("click", async () => {
    chrome.tabs.query({}, (tabs) => {
      for (let tab of tabs) {
        // Loops through every tab that is open
        console.log("Testing track name: " + currentTrackName); // Logging in console current song playing
        chrome.scripting.executeScript(
          // Adds the box to the tab
          {
            target: { tabId: tab.id },
            func: addbox,
            args: [currentTrackName],
          },
          (results) => {
            // Returns console log on if box is added to tab or not
            if (chrome.runtime.lastError) {
              console.error(chrome.runtime.lastError); **// This is where all the error message is coming up from**
            } else {
              console.log("Script executed on tab ID:", tab.id);
            }
          }
        );
      }
    });
 });
});

React Native why is my screen not scrolling on Iphone 11 but it works on Iphone7?

<SafeAreaView style={styles.container}>
  <FlatList
    data={postList}
    keyExtractor={(item) => item.id}
    renderItem={({ item }) => (
      <Card
        title={item.title}
        difficulty={item.difficulty}
        image={item.image}
      />
    )}
    ItemSeparatorComponent={<View style={{ height: 16 }} />}
    ListEmptyComponent={<Text>No items found</Text>}
    contentContainerStyle={styles.contentContainerStyle}
  />
</SafeAreaView>


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#f5f5f5",
    marginTop: StatusBar.currentHeight,
  },
  card: {
    backgroundColor: "#fff",
    borderRadius: 8,
    overflow: "hidden",
    borderWidth: 1,
    marginBottom: 15,
    shadowColor: "#333",
    shadowOpacity: 0.1,
    shadowOffset: { width: 0, height: 2 },
    shadowRadius: 8,
    elevation: 3,
  },
  cardImage: {
    width: "100%",
  },
  cardContent: {
    padding: 15,
  },
  cardTitle: {
    fontSize: 18,
    fontWeight: "bold",
    marginBottom: 5,
  },
  cardDifficulty: {
    fontSize: 14,
    color: "#777",
  }
});

Hello, i just started React Native last weekend, and trying to build my own app for the first time!

So i fetched cocktails data from Rapid Api and rendered them, they are all displayed on screen (about 100 of different objects) but the problem is i am able to scroll down the screen on Iphone 7 but I cannot do that on Iphone 11.. What is the problem here? I could not find any solution related to mine

Loading .wasm file compiled from Rust gives “CompileError: wasm validation error: at offset 184: function body too big”

I was trying to create my web assembly module using Rust`s wasm-pack and use it within the .html file. I tried to use replit.com to generate the .wasm .

I created a new blank repl, installed rustup and wasm-pack, added wasm32-unknown-unknown target, ran cargo init, created src/lib.rs and put this code in there:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn sum_3(p1: u8, p2: u8, p3: u8) -> u8 {
    p1 + p2 + p3
}

Here is how my Cargo.toml file looked like:

[package]
name = "test"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
target = "2.1.0"
wasm-bindgen = "0.2.92"

Then I ran these two commands:

rustup default stable
wasm-pack build --target web

I got the wasm file and put it into the new folder where this html was located too:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Wasm</title>
</head>
<body>

    <script>
        function process(e) {
            
        }

        WebAssembly.instantiateStreaming(fetch("./my.wasm", {mode: 'no-cors'}), {}).then(result => {
            process(result.instance.exports);
        })
    </script>

</body>
</html>

The html was served with the running of this python file:

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

app = FastAPI()

app.mount("/", StaticFiles(directory="myf"), name="stat")

with this command: fastapi dev server.py.
After opening html in the browser in the console I saw: Uncaught (in promise) CompileError: wasm validation error: at offset 184: function body too big.

The .wasm file weights like 13kb.
Here is the link to my repl: https://replit.com/@benjaminaugustb/testnew. You can fork it and test everything yourself.
Here is the link to a zip with the folder I served: https://github.com/user-attachments/files/16354465/myf.zip.

Am I doing something wrong? Does web assembly js api have any limits related to size?

What is a better pattern for typing a callback that shares types with something else? (Wrapper function vs directly typed)

Which is a better pattern for the onSubmit handler in this React/Typescript code in terms of dev experience, maintainability, and readability? (The key is how the type-safety is provided to the onSubmit function’s parameters.)

//Pattern Alpha:
const { methods, handleSubmit } = useForm<FormValues>();
const onSubmit = handleSubmit((values) => {
  console.log('Form data: ', values);
});
return (<Form onSubmit={onSubmit}/>);

//Pattern Bravo:
const methods = useForm<FormValues>();
const onSubmit: SubmitHandler<FormValues> = (values) => {
  console.log('Form data: ', values);
};
return (<Form onSubmit={onSubmit}/>);

Both provide equivalent type-safety in my testing. If I initialize my callback outside of handleSubmit in Alpha, I must still strongly type it so it’s not super helpful in that case. The separation of concerns seems better in Bravo.