Browser extension breaking event listener

Current setup is a PHP form which customers put in an iframe with a submit button. Chrome browser extensions like TopCashBack are sending message events like:

{message: 'ACK_FRAME', targetId: 'bef025c4-852a-4b55-2ced-fcf777c43091'}

The fields sent come into this function:

function postFields(msg){
    var receiver = document.getElementById('iframe-content').contentWindow;
    receiver.postMessage(msg, 'https://my.websitecom');
}

Which this eventlistener is picking up.

        if (window.addEventListener) {
            window.addEventListener("SecureMessage", receiveMessage);
        }

Thinking that I need to be checking the origin of the browser, or somehow block extension interactions with this page?

Can we use apollo client without npm (on shopify theme basically)

I am trying to implement apollo client in our shopify theme using vanilla js. almost all the documentation and guides use npm to install the apollo client package. while on shopify we don’t use npm but instead use either cdn or locally served asset files. is there a way to use apollo in this scenario? or suggest any alternate for caching.

tried both of these ways but not working

console.log("inside apollo-client.js")
// const { ApolloClient, InMemoryCache, gql, HttpLink } = window['@apollo/client/core'];
import { ApolloClient, InMemoryCache, gql, HttpLink } from "https://unpkg.com/@apollo/[email protected]/core/core.cjs.js"

const client = new ApolloClient({
  link: new HttpLink({
    uri: 'https://my-shopify-store.myshopify.com/api/2023-07/graphql.json',
    headers: {
      'X-Shopify-Storefront-Access-Token': '******************'
    }
  }),
  cache: new InMemoryCache()
});

console.log("The client in apollo-client is: ", client)

// Make client globally accessible
window.apolloClient = client;

Angular: CSS and JavaScript Not Applying Correctly in a Specific Component When Fetching Data from an External API

I’m facing an issue in my Angular application where CSS and JavaScript don’t apply correctly to a carousel component when fetching data from an external API. The data retrieval process takes a significant amount of time, and as a result, the carousel’s styles are not applied properly when the component first loads.

Here’s the situation:

Initial Load: The component takes a long time to fetch data from the API, causing the CSS for the carousel to not apply correctly.
Page Reload: When I reload the page, the carousel works perfectly, with the data loading from the cache and the CSS applying as it should.
I’ve attached screenshots below to show the difference in behavior between the initial load and after reloading the page.

Has anyone experienced a similar issue, and can you suggest any solutions to ensure that the CSS and JavaScript for the carousel are applied correctly even during the first load?first time when data fetched from external api ,
when reloading the page

I’ve tried loading the script in the ngAfterViewInit lifecycle hook, but the CSS for the carousel doesn’t load correctly on the first attempt. However, when I reload the page, everything works as expected (the data loads from the cache, and there’s no delay).

Fetch request “Load failed” error in Safari on iOS devices. (Stimulus)

I have been having issues with a fetch request in my Stimulus controller. Whenever we try to send a fetch request we get a network error “Load failed” error.

The fetch request is supposed to send answers to questions from the front end to the back end and everything was working fine until we started testing it in Safari on iPhones in production. I have also tried using axios which yielded the same result. This does not happeen on all iPhones only on some devices (trying to collect data regarding software versions etc.). All works fine on laptops/desktops, Android devices and in other browsers on iPhones.

Please see my full Stimulus controller below.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static get targets() {
    return ["question", "submit", "next", "back", "source", "preview", "error", "loading"];
  }

  static get values() {
    return { responseDetailsPath: String };
  }


  initialize() {
    console.log("Questionnaire controller initialized test for 24/06/2024")
    this.showCurrentQuestion(0);
    this.lastSelectedImages = {};
    this.hasUnsavedChanges = false;
    this.initInputListeners();
  }

  initInputListeners() {
    this.questionTargets.forEach((question) => {
      const inputs = question.querySelectorAll("input, select, textarea");
      inputs.forEach((input) => {
        input.addEventListener("change", () => {
          this.hasUnsavedChanges = true;
        });
      });
    });
  }

  displayLoadingAnimation(show) {
    if (show) {
      this.loadingTarget.classList.remove("d-none");
    } else {
      this.loadingTarget.classList.add("d-none");
    }
  }

  async next() {
    if (!this.validateResponse()) {
      return;
    }
    if (this.hasUnsavedChanges) {
      this.displayLoadingAnimation(true);
      try {
        await this.sendResponse();
      } catch (error) {
        this.displayLoadingAnimation(false);
        return;
      }
    }
    const currentIndex = this.currentQuestionIndex();
    if (currentIndex < this.questionTargets.length - 1) {
      this.showCurrentQuestion(currentIndex + 1);
    }
    this.updateButtonVisibility();
  }

  async previous() {
    const currentIndex = this.currentQuestionIndex();

    if (!this.validateResponse()) {
      if (currentIndex > 0) {
        this.showCurrentQuestion(currentIndex - 1);
      }
      this.updateButtonVisibility();
      return;
    }
    if (this.hasUnsavedChanges) {
      this.displayLoadingAnimation(true);
      try {
        await this.sendResponse();
      } catch (error) {
        this.displayLoadingAnimation(false);
        return;
      }
    }
    if (currentIndex > 0) {
      this.showCurrentQuestion(currentIndex - 1);
    }
    this.updateButtonVisibility();
  }

  updateButtonVisibility() {
    const currentIndex = this.currentQuestionIndex();
    this.backTarget.classList.toggle("d-none", currentIndex === 0);
    this.nextTarget.classList.toggle("d-none", currentIndex === this.questionTargets.length - 1);
    this.submitTarget.classList.toggle("d-none", currentIndex !== this.questionTargets.length - 1);
  }

  validateResponse() {
    const currentIndex = this.currentQuestionIndex();
    const currentQuestion = this.questionTargets[currentIndex];
    const input = currentQuestion.querySelector("input, select, textarea");
    const isRequired = input.required;
    const inputType = input.getAttribute("type");
    let isValid;

    if (inputType !== "file") {
      isValid = input.value.trim() !== "";
    } else {
      const fileSelected = input.files.length > 0;
      const existingImage = currentQuestion.dataset.existingImage && currentQuestion.dataset.existingImage.trim() !== "";
      const lastSelectedImage = this.lastSelectedImages[currentQuestion.dataset.itemQuestionId];
      isValid = fileSelected || existingImage || this.lastSelectedImages[currentQuestion.dataset.itemQuestionId];
    }

    const errorMessageDiv = this.errorTargets[currentIndex];
    if (!isValid && isRequired) {
      errorMessageDiv.style.display = "block";
      errorMessageDiv.textContent = "Пожалуйста, дайте ответ на текущий вопрос.";
      return false
    } else {
      errorMessageDiv.style.display = "none";
      return true
    }
  }

  showCurrentQuestion(index) {
    this.questionTargets.forEach((element, i) => {
      element.classList.toggle("d-none", i !== index);
      const errorMessageDiv = this.errorTargets[i];
      if (errorMessageDiv) {
        errorMessageDiv.style.display = "none";
      }
      if (i === index && element.dataset.existingImage) {
        this.updateImagePreview(element);
      }
    });
    this.hasUnsavedChanges = false;
  }

  updateImagePreview(questionElement) {
    const existingImageUrl = questionElement.dataset.existingImage;
    const previewTarget = questionElement.querySelector("[data-questionnaire-target='preview");
    if (existingImageUrl) {
      previewTarget.innerHTML = `<img src="${existingImageUrl}">`;
    } else {
      previewTarget.innerHTML = '';
    }
  }

  currentQuestionIndex() {
    return this.questionTargets.findIndex((element) => !element.classList.contains("d-none"));
  }

  async show(event) {
    const index = this.sourceTargets.indexOf(event.target);
    const previewTarget = this.previewTargets[index];
    const file = event.target.files[0];
    const currentIndex = this.currentQuestionIndex();
    const currentQuestion = this.questionTargets[currentIndex];

    if (file && file.type.match('image')) {
      try {
        const resizedFile = await this.resizeImage(file);
        const reader = new FileReader();
        reader.onload = function(e) {
          previewTarget.innerHTML = `<img src="${e.target.result}">`
        };
        reader.readAsDataURL(resizedFile);
        this.lastSelectedImages[currentQuestion.dataset.itemQuestionId] = resizedFile;
        this.hasUnsavedChanges = true;
      } catch (error) {
        console.error("Error resizing image:", error);
      }
    }
  }

  async submit(event) {
    event.preventDefault();
    if (!this.validateResponse()) {
      return;
    }
    this.displayLoadingAnimation(true);

    try {
      const isFinal = true;
      await this.sendResponse(isFinal);
      window.location.href = "/success";
    } catch (error) {
      this.displayLoadingAnimation(false);
    }
  }

  async sendResponse(isFinal = false) {
    const currentIndex = this.currentQuestionIndex();
    const currentQuestion = this.questionTargets[currentIndex];
    const input = currentQuestion.querySelector("input, select, textarea");
    const name = input.name;
    const value = input.value;

    let payload = {
      question_id: currentQuestion.dataset.itemQuestionId,
      hardware_id: currentQuestion.dataset.itemHardwareId,
      questionnaire_id: currentQuestion.dataset.itemQuestionnaireId,
      answer: value,
    };

    if (isFinal) {
      payload.is_final = true;
    }

    if (input.type === "file") {
      let file = input.files[0];
      if (file) {
        try {
          file = await this.resizeImage(file);
          payload.answer = await this.fileToBase64(file);
        } catch (error) {
          console.error("Error resizing or converting image:", error);
        }
      } else if (this.lastSelectedImages[currentQuestion.dataset.itemQuestionId]) {
        payload.answer = await this.fileToBase64(this.lastSelectedImages[currentQuestion.dataset.itemQuestionId]);
        this.lastSelectedImages[currentQuestion.dataset.itemQuestionId] = null;
      } else if (currentQuestion.dataset.existingImage) {
        payload.keep_existing_image = true;
      }
    }

    try {
      const response = await fetch(this.responseDetailsPathValue, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': document.querySelector("[name='csrf-token']").content,
        },
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.error || `HTTP Status ${response.status}`);
      }

      this.hasUnsavedChanges = false;
      return response;

    } catch (error) {
      console.error("Error sending response:", error);
      this.displayErrorMessage(currentQuestion, error.message);
      throw error;
    } finally {
      this.displayLoadingAnimation(false);
    }
  }

  fileToBase64(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = function (e) {
        resolve(e.target.result);
      };
      reader.onerror = function (error) {
        reject(error);
      };
      reader.readAsDataURL(file);
    });
  }

  displayErrorMessage(questionElement, message) {
    const errorMessageDiv = questionElement.querySelector("[data-questionnaire-target='error']");
    if (errorMessageDiv) {
      errorMessageDiv.style.display = "block";
      errorMessageDiv.textContent = message;
    }
  }

  findQuestionIndex(input) {
    let parentQuestion = input.closest("[data-questionnaire-target='question']");
    return this.questionTargets.indexOf(parentQuestion);
  }

  resizeImage(file, maxWidth = 1024, maxHeight = 1024, quality = 1) {
    return new Promise((resolve, reject) => {
      const img = document.createElement("img");
      const reader = new FileReader();

      reader.onload = function(e) {
        img.src = e.target.result;

        img.onload = function() {
          let width = img.width;
          let height = img.height;

          if (width > height) {
            if (width > maxWidth) {
              height *= maxWidth / width;
              width = maxWidth;
            }
          } else {
            if (height > maxHeight) {
              width *= maxHeight / height;
              height = maxHeight;
            }
          }

          const canvas = document.createElement("canvas");
          canvas.width = width;
          canvas.height = height;
          const ctx = canvas.getContext("2d");
          ctx.drawImage(img, 0, 0, width, height);

          canvas.toBlob((blob) => {
            resolve(new File([blob], file.name, { type: file.type, lastModified: Date.now() }));
          }, file.type, quality);
        };

        img.onerror = function(err) {
          reject(err);
        };
      };

      reader.onerror = function(err) {
        reject(err);
      };

      reader.readAsDataURL(file);
    });
  }
}

P.S. if some things in the code, such as the way I have written my static declarations or the fact that I am conveerting images to base64 strings, seem strange, these aree just my multiple attempts of fixing the issue. Please ignore those issues as I initially had a very simple fetch request written and was getting the same error. I specifically want some help in figuring out what exactly could be causing the issue so that I can atteempt to fix it.

Thanks a lot for your help!

Making entering different text lead to different locations not working

I’m trying to make a page that when you enter different words, they lead you to different pages. (inspired by thisisnotawebsitedotcom.com) However, I can’t seem to get it working. I’m new to coding and not sure what I’m doing wrong or how to fix it.

Here’s what I’ve got:

<!DOCTYPE html>
<html><head>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>&#9734;</title>
<link href="/style.css" rel="stylesheet" type="text/css" media="all">
<script>
if(document.getElementById('text').value == 'hi'){
    alert('hi :)');}
if(document.getElementById('text').value == 'link'){
  location.href = "http://google.com";
    else{
      return false;}
</script>
</head>
<body>
<center>
<form method="get" onclick="document.getElementByID('text')">
<input type="text" id="text">
</form>
</center>
</body>

Whenever I actually try it out, no matter what I enter, whether it be “hi”, “link”, or something else, it just takes me to the same page but adds /? to the end of the link.

Next.JS ReferenceError variable is not defined

Inside server-side page.tsx I have client-side component SelectType.tsx. And should work like this:

  1. User changes value of select component
  2. It triggers function inside page.tsx
  3. The function should change object called downloadParams, but it doesn’t

Here is code
page.tsx

import {SelectType} from "@/components/SelectType";

export default async function DownloadWithParams ({ params }: { params: { slug: string } }) {

    let downloadParams: DlParameters = {}

    const updateDlParams = async (newParams: DlParameters) => {
        "use server"
        downloadParams = newParams
        console.log(downloadParams)
    }

    return(
        <div className="bg-white w-[80%] min-h-[500px] rounded-2xl shadow-lg p-10 text-zinc-800">
            <div className="parameters-container w-full px-[100px]">
                <form className="flex">
                    <div className="choosetype-container mr-10 grow-[1] flex flex-col">
                        <label className="font-semibold block mb-2">Choose a type:</label>
                        <SelectType dlParams={downloadParams}
                                    updateDlParams={updateDlParams}
                        />
                    </div>
                </form>
            </div>
        </div>
    );
}

SelectType.tsx

'use client'

import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select";
import {DlParameters} from "@/types";

type HandleFnc = (newParams: DlParameters) => void

export function SelectType({dlParams, updateDlParams} : {dlParams : DlParameters, updateDlParams : HandleFnc}) {
    return (
        <Select defaultValue={dlParams?.type || ""}
                onValueChange={async (value: "video" | "audio") => {
                    dlParams.type = value || undefined;
                    await updateDlParams(dlParams);
                }}>
            <SelectTrigger className="grow border-2 border-gray-300 rounded-2xl font-semibold">
                <SelectValue placeholder="Type" />
            </SelectTrigger>
            <SelectContent className="font-semibold" >
                <SelectItem value="video">Video</SelectItem>
                <SelectItem value="audio">Audio</SelectItem>
            </SelectContent>
        </Select>
    );
}

Error message


Error: downloadParams is not defined

Source
srcapp[slug]page.tsx (25:9) @ downloadParams

  23 |     const updateDlParams = async (newParams: DlParameters) => {
  24 |         "use server"
> 25 |         downloadParams = newParams
     |         ^
  26 |         console.log(downloadParams)
  27 |     }
  28 |

I just wanna understand why variable is out of the function`s scope and how to make it works

Has macOS recently changed how it handles popup windows that open, print and close?

I’d implented a pop up window to print some javascript generated content, using code based on this old question.

The key bit of the code is

var mywindow = window.open('', 'PRINT', 'height=800,width=800');
mywindow.focus(); 
mywindow.print();
mywindow.close();

This was working, but I’ve just been given bug reports that it has stopped working on macOS, on both desktop Safari and Chrome. I can’t replicate the issue on a PC, so I assume it is an Apple-specific issue. I don’t have a desktop Mac to test on.

If you remove the mywindow.close(); then I’m told it works, but you have to close the window manually.

Is there a specific update which has stopped this working? If so, what are the limitations it has added?

lucia auth get data from from different table

This is my auth.ts file located in utils folder (I use nuxt 3)

auth.ts

import { Lucia } from "lucia"
import { D1Adapter } from "@lucia-auth/adapter-sqlite"

export function initializeLucia(D1: D1Database) {
  const adapter = new D1Adapter(D1, {
    user: "users",
    session: "session",
  })
  return new Lucia(adapter, {
    sessionCookie: {
      attributes: {
        secure: !import.meta.dev,
      },
    },
    getUserAttributes: (attributes) => {
      return {
        firstname: attributes.first_name,
        lastname: attributes.last_name,
        email: attributes.email,
        username: attributes.username,
        country: attributes.country,
        gender: attributes.gender,
        date_of_birth: attributes.date_of_birth,
        selectedPhoneCode: attributes.selectedPhoneCode,
        phone: attributes.phone,
      }
    },
  })
}


declare module "lucia" {
  interface Register {
    Lucia: ReturnType<typeof initializeLucia>
    DatabaseUserAttributes: DatabaseUserAttributes
  }
}

interface DatabaseUserAttributes {
  first_name: string
  last_name: string
  email: string
  username: string
  country: string
  gender: string
  date_of_birth: string
  selectedPhoneCode: string
  phone: string
}

I need to get user attribute called email_verified which stores string data. The problem is that the current attributes are picking data from table called users but I need to pick data as well from table called account_verification which has row called email_verified which I need.

Click on item inside dynamic accordion using Puppeteer for nodejs

I’m struggling to find click on an item inside an dynamic loaded accordion.
When the page opens, the first thing i do is click on the accordion button to expand its items. So far so good, i managed to click on it and open the table.

However, i can’t find a way to click on a radio button inside there.
I managed to do it with Selenium, by doing the following:

  1. Get into the selector (div > spaui-datatable > table)

  2. Inside the selector, get all css selector “tr”

  3. Search the tr for the one with an specific item i wanted (numero acordo)
    This is how i did on Selenium:

     var tabelaAcordos = driver.FindElement(By.CssSelector("div > spaui-datatable > table"));
     var linhasTabelaAcordos = tabelaAcordos.FindElements(By.CssSelector("tr"));
     for (int i = 0; i < linhasTabelaAcordos.Count; i++)
     {
     var itensAcordo = HelperMethods.FormataString(linhasTabelaAcordos[i].Text);
     if (itensAcordo[2].Equals(numAcordo))
     {                        
     var acordoTr = new WebDriverWait(driver, TimeSpan.FromSeconds(10))                            .Until(ExpectedConditions.ElementExists(By.XPath("//div[contains(@class, 'spaui-radio-helper-hidden')]//input[@type='radio']")));
    

    acordoTr.SendKeys(Keys.Space);
    }
    }

However i can’t replicate it to puppeteer on nodejs.
I don’t know if its related to the page not being readyloaded or something like that. If i scroll down the page (on the session opened) i can see the items there. But the console.log shows nothing also.

One post i think may have something to do with my question is this one:
Accordions clicked with puppeteer not revealing tables after being clicked

But i couldn’t replicate what was done there =(

This is the accordion i’m trying to click:
Identifier

Green is the item i’m using as an unique identifier. When i did this with Selenium, i was just getting the line with this number, finding its related radio button and sending an space key (so it would be selected).

HTML

This is the HTML code of the part i’m trying to reach. There are others items on this accordion, but already managed to get the one i need.

Any input is really appreciated. Thanks a lot for your attention.

My code:

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({ 
        headless: false,
        args: [
            '--window-size=800,600',
            '--disable-gpu',
            '--no-sandbox',
            '--disable-dev-shm-usage',
            '--disable-software-rasterizer'
        ]
    });
    const numAcordo = "235247368";
    const page = await browser.newPage();
    await page.setViewport({ width: 800, height: 600 });

   //Begin navigation. Go to the URL, type login and password, press enter and login
    await page.goto('https://www.santandernegocios.com.br/portaldenegocios/#/externo');
    
    await page.waitForSelector('#userLogin__input'); 
    await page.waitForSelector('#userPassword__input'); 
    await page.type('#userLogin__input', 'EX108593'); 
    await page.type('#userPassword__input', '@BARC02');  
   await page.focus('#userPassword__input');
   await page.keyboard.press('Enter')

   //Waiting until it finishes loading the page
    await page.waitForNavigation();

   
    await page.waitForSelector('input[name="inputSearch"]');
    await page.type('input[name="inputSearch"]', '32877625000122');
    await page.focus('input[name="inputSearch"]');
    await page.keyboard.press('Enter')
    await page.waitForNavigation();
    
   
   
   
 
   //Trying to reach the button
   await page.evaluate(() => {
    document.querySelector('div.avatar-letters').click();

    
});

await page.evaluate(() => {
    
    const sessionMenu = document.querySelector('div.session-menu');

    if (sessionMenu) {
        // Find the <ul> inside this <div>
        const ul = sessionMenu.querySelector('ul');

        if (ul) {
           
            const link = Array.from(ul.querySelectorAll('li a')).find(anchor => anchor.textContent.trim() === 'Acordo Pj' || anchor.textContent.trim() === 'Acordo Pf');

            if (link) {
                
                link.click();
            } else {
                console.error('Acordo pf or pj not found');
            }
        } else {
            console.error('No <ul> found');
        }
    } else {
        console.error('No session-menu div found');
    }
});

await page.waitForNavigation();


await page.evaluate(() => {
    document.querySelector('#accordioAcordosPendentes > div.accordion-tab > div > div > h4 > span.accordion-tab-button').click();

    
});
await page.waitForNavigation();
let accordions = document.querySelectorAll("div.accordion-tab-body")    
    console.log("qtos eu achei");
    console.log("n" + accordions.length)

/*
await page.evaluate(() => {
    console.log("clicking");
    let accordions = document.querySelectorAll("div.accordion-tab-body")    
    console.log("qtos eu achei");
    console.log("n" + accordions.length)
    accordions.forEach(accordion => {
        console.log(accordion)
    })
})
*/

/*
await page.evaluate(() => {
    // Find all spaui-datatable elements
    const datatables = Array.from(document.querySelectorAll('spaui-datatable'));

    // Log if any spaui-datatable elements are found
    if (datatables.length > 0) {
        console.log(`Found ${datatables.length} spaui-datatable elements.`);
        
        datatables.forEach((datatable, index) => {
            // Find the table element inside each spaui-datatable
            const table = datatable.querySelector('table');
            
            if (table) {
                console.log(`Table found in spaui-datatable element ${index + 1}`);
            } else {
                console.error(`No table found in spaui-datatable element ${index + 1}`);
            }
        });
    } else {
        console.error('No spaui-datatable elements found');
    }
});

*/

})();

Again, thanks for your attention.

Safari browser and iPhone not displaying video thumbnail

I’m facing an issue where the video thumbnail is not displaying in Safari browser in mobile view or not showing iPhones as well. The thumbnail shows up perfectly on Android phones and Windows browsers, but not on Safari.

I want to display the thumbnail from 30 seconds into the video without using the poster attribute or enabling autoplay. Here’s the code I’m using:

{isSafari ? (
  <video
    ref={playerRef}
    playsInline={false}
    muted={true}
    autoPlay={false}
    loop={false}
    controls={false}
    preload='metadata'
    width='100%'
    height='100%'
    className='pointer-events-none h-full w-full select-none overflow-hidden object-cover'>
    <source src={`${parseUrlFromModel(data)}#t=0.001`} type='video/mp4' />
  </video>
) : (
  <video
    ref={playerRef}
    src={parseUrlFromModel(data)}
    width='100%'
    height='100%'
    preload='metadata'
    muted={isMuted}
    style={{
      position: 'absolute',
      top: 0,
      left: 0,
      objectFit: 'cover',
    }}
  />
)}
const getDefaultStartTime = () => {
  if (timeStamps && timeStamps.length >= 3) {
    return timeStringToSeconds(timeStamps[2].startTime) + 30;
  } else {
    return duration / 2;
  }
};

useEffect(() => {
  const startTime = getDefaultStartTime();
  if (playerRef.current) {
    playerRef.current.currentTime = startTime;
    playerRef.current.onloadeddata = () => {
      captureThumbnail(startTime);
    };
  }
}, [timeStamps]);

const captureThumbnail = () => {
  try {
    const canvas = document.createElement('canvas');
    canvas.width = playerRef.current.videoWidth;
    canvas.height = playerRef.current.videoHeight;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(playerRef.current, 0, 0, canvas.width, canvas.height);
    setThumbnailUrl(canvas.toDataURL());
    console.log('thumb' + thumbnailUrl);
  } catch (error) {
    return error;
  }
};

const isSafariBrowser = /^((?!chrome|android).)*safari/i.test(
  navigator.userAgent
);
setIsSafari(isSafariBrowser);
console.log('Safari browser ' + isSafariBrowser);

I verified that the thumbnail is generated correctly on other devices and browsers.
I ensured that the video is loading and the currentTime is set correctly.
I tried different approaches for detecting Safari, but the issue persists.

Expected: The thumbnail should display for the video in Safari on iPhones.
Actual: The thumbnail does not appear, but works fine on other browsers and devices.

How to get the tree structure data of class/property/method in tree-sitter?

How to get the tree structure data of class/property/method in tree-sitter:

I can only match the class like below:

const Parser = require("tree-sitter")
const JavaScript = require("tree-sitter-javascript")
const { Query } = Parser 


const parser = new Parser()
parser.setLanguage(JavaScript)

const query = new Query(
  JavaScript,
  `
    (class_declaration name: (identifier) @class-name)
  `
);


const tree = parser.parse(`
class Person {}
 
const TestPerson = class {}

class Person2 {}
 
const TestPerson2 = class {}
  `);
const matches = query.matches(tree.rootNode);

matches.forEach(item => {
  console.log(item.captures[0])
})

there I can get the classnames of a file.

but you see the GitHub page: I want to get the tree structure data of AST:

enter image description here

1、please help with how to match the AST tree data?
2、you see the snapshot display a 3-layer depth tree data, how to control the matched tree data depth?

Playwright – Issue with asserting (expect) iframe inside the shadow-root

My html code looks like:

 #shadow-root (closed) == $0
<iframe src="https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/g/turnstile/if/ov2/av0/rcv0/0/q9nst/0x4AAAAAAAVlQeNrI_m-kb9K/auto/fbE/normal/auto/" allow="cross-origin-isolated; fullscreen; autoplay" sandbox="allow-same-origin allow-scripts allow-popups" id="cf-chl-widget-q9nst" tabindex="0" title="Widget containing a Cloudflare security challenge" style="border: none; overflow: hidden; width: 300px; height: 65px;"></iframe>

enter image description here

I am trying to assert (expect) that this Cloudflare window is visible using Playwright and js.

But, I am not even able to access the element using Chrome console with:

document.querySelector("iframe[title='Widget containing a Cloudflare security challenge']");

enter image description here

Why my iframe code is not visible neither in the automation script nor in the Chrome console?

note:

  1. When starting the script I am using:

    launchOptions: {
    args: [‘–disable-web-security’],
    }

How to loop within an array to pull on ids

I am struggling in try to display all marketids from a json. At the moment I have a foreach to return each event id and all its related data from within markets array like so:

export async function generateData() {
  const matchArray = [];
  try {
    const data = await get(dataEndpoint);
    data ? data.forEach((item) => {
      if (item.type== 'MATCH'){
      matchArray.push({ eventId: item.id, markets: [item.markets]});
      } 
    }) : console.log(`No data received ${data}`);
    await writeJSON(matchFilePath, matchArray);
  } catch (error) {
    throw error;
  }        
}

It writes the following in the json file:

[
  {
    "eventId": "b312bea8-c25b-43f2-85a3-1c6caa5230e4",
    "markets": [
      [
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d26",
          "createdAt": "2024-08-05T10:31:58.288Z"
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d25",
          "createdAt": "2024-08-05T10:31:58.288Z"
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d21",
          "createdAt": "2024-08-05T10:31:58.288Z"
        }
      ]
    ]
  },
  {
    "eventId": "b312bea8-c25b-43f2-85a3-1c6caa5230e4",
    "markets": [
      [
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d16",
          "createdAt": "2024-08-05T10:31:58.288Z"
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d15",
          "createdAt": "2024-08-05T10:31:58.288Z"
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597121",
          "createdAt": "2024-08-05T10:31:58.288Z"
        }
      ]
    ]
  }
]

But ideally what I want is only all the ids within markets[] for each event, so based on the above json example I want it to be displayed like this:

[
  {
    "eventId": "b312bea8-c25b-43f2-85a3-1c6caa5230e4",
    "markets": [
      [
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d26",
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d25",
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d21",
        }
      ]
    ]
  },
  {
    "eventId": "b312bea8-c25b-43f2-85a3-1c6caa5230e4",
    "markets": [
      [
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d16",
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597d15",
        },
        {
          "id": "28e53502-8a44-467e-a5bc-d1d613597121",
        }
      ]
    ]
  }
]

I’m not sure how pull only the market ids within the markets[] array. Curious to know how to do this.

How to Configure CSP in Next.js to Allow Only Specific Scripts and Block All Others?

I am working on a Next.js (Pages Router) application and need to configure Content Security Policy (CSP) to allow only specific scripts and blocking all others. The challenge is that my application dynamically loads scripts from various sources, including ads and third-party integrations. I want to set up CSP in such a way that only scripts from a defined list of trusted sources are allowed, and all other scripts are blocked.

I tried nonce but if i set it it also block my internal scripts.