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.

Inertiajs & Vue Component Library

I recently embarked on creating a custom component library in Vue 3, driven by the desire to repurpose some meticulously crafted UI components from a previous project I developed using the Laravel + Inertia + Vue 3 stack. In that project, I invested significant time and effort into refining the user interface, and I was so pleased with the outcome that I decided to extract these components into a standalone library. The goal was to ensure that the same high-quality, well-designed components could be easily reused across different projects without needing to start from scratch each time.

However, I’ve encountered a problem while integrating the library into my main project. Specifically, when I attempt to use Inertia’s <Link /> component, it throws an error, halting the process. This issue has become a roadblock, and I’m trying to understand how to resolve it so that I can fully leverage the components I’ve worked so hard to perfect.
Error when I click a link

This is my Link.vue component from the vue-inertia-core library.


<script setup>
import { Link } from "@inertiajs/vue3";
</script>

<template>
    <Link class="text-sm font-bold leading-tight">
        <slot></slot>
    </Link>
</template>

<style scoped></style>

This is the vite.config.js file of the vue-inertia-core library:

import { resolve } from "path";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": "/src",
      "@assets": "/src/assets",
    },
  },
  css: {
    postcss: resolve(__dirname, "postcss.config.js"),
  },
  build: {
    lib: {
      entry: resolve(__dirname, "src/index.js"),
      name: "VueInertiaCore",
      fileName: "vue-inertia-core",
    },
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
});

and this is the vite.config.js file from the original project where I linked this package.

import laravel from "laravel-vite-plugin";
import vue from "@vitejs/plugin-vue";

const inDevelopment = process.env.NODE_ENV === 'development';

export default defineConfig({
    plugins: [
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
        laravel({
            input: [
                "resources/inertia/css/app.css",
                "resources/inertia/js/app.js",
            ],
            refresh: true,
        }),
    ],
    resolve: {
        alias: {
            "@": "/resources/inertia/js",
            "@assets": "/resources/inertia/assets",
            "@mosaict/vue-inertia-core": inDevelopment ? "@mosaict/vue-inertia-core-dev" : "@mosaict/vue-inertia-core",
            vue: "vue/dist/vue.esm-bundler.js",
        },
    },
});

Any help would be much appreciated. If you need more information, please tell me.

I tried to resolve those components manually but I don’t know what to do. I just want the component from the library to be able to work properly.

Set cursor pos in contenteditable innerHTML

I saw this question

Contenteditable Div – Cursor position in terms of innerHTML position

with an answer that worked perfectly, but now I just need something that can set cursor position while including length of element tags, or maybe something that would just count and add the length of tags before the pos I’m trying to set the cursor.

I tried using the regular method of setting cursor pos in a contenteditable but it didn’t work obviously as it doesn’t consider element tag lengths.

redo and undo functions are not working properly

I am working on drawing app project but when i added redo and undo functions to the app which did not work and undo is working but redo is not working

I tried to solve this problem and I changed the code of undo and redo and also save state function however still redo is not working properly