How to Start Screen Recording Without Using getDisplayMedia in JavaScript?

I am working on a web application where I need to implement screen recording functionality, similar to how Microsoft Teams handles screen sharing and recording during meetings. Typically, getDisplayMedia is used to capture the screen, but in my case, I’m looking for alternative solutions. This could be due to browser restrictions or the need for more control over the capture process.

Does anyone know of a way to achieve this without using getDisplayMedia? For example, could it be done using WebRTC, third-party libraries, or lower-level browser APIs? I’m also open to solutions involving browser extensions or native apps, similar to how Microsoft Teams might handle screen recording.

Any guidance or alternative approaches would be greatly appreciated!

Aes-256-GCM OpenSSL > nodeJS

I’m trying to decrypt data that have been encrypted using C++/OpenSSL Aes-256-GCM from nodejs javascript.

C++ encryption implementation:

#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include <iostream>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/buffer.h> 

std::string base64Encode(const unsigned char* input, int length)
{
    BIO *bio, *b64;
    BUF_MEM *bufferPtr;

    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);

    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
    BIO_write(bio, input, length);
    BIO_flush(bio);
    BIO_get_mem_ptr(bio, &bufferPtr);
    
    std::string result(bufferPtr->data, bufferPtr->length);

    BIO_free_all(bio);

    return result;
}

std::string bytesToHexString(const unsigned char* data, int len)
{
    std::stringstream ss;
    ss << std::hex << std::setfill('0');
    for (int i = 0; i < len; ++i)
    {
        ss << std::setw(2) << static_cast<int>(data[i]);
    }
    return ss.str();
}

bool encrypt(std::string& data, const std::vector<unsigned char>& password)
{
    constexpr int KEY_SIZE        = 32;  // AES-256
    constexpr int IV_SIZE         = 16;
    constexpr int TAG_SIZE        = 16;
    constexpr int ITERATION_COUNT = 10000;

    std::vector<unsigned char> key(KEY_SIZE);
    std::vector<unsigned char> iv(IV_SIZE);    
    std::vector<unsigned char> salt(16);
    RAND_bytes(salt.data(), 16);
 
    // PBKDF2 for key derivation
    if (PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(password.data()), password.size(),
        salt.data(), salt.size(), ITERATION_COUNT,
        EVP_sha256(), KEY_SIZE, key.data()) != 1)
        return false;

    if (RAND_bytes(iv.data(), IV_SIZE) != 1)
        return false;
    
    // encryption context
    std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)> ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
    if (!ctx)
        return false;
    
    if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr, key.data(), iv.data()) != 1)
        return false;

    std::vector<unsigned char> ciphertext(data.size() + EVP_MAX_BLOCK_LENGTH);
    int outLen1 = 0, outLen2 = 0;
    
    if (EVP_EncryptUpdate(ctx.get(), ciphertext.data(), &outLen1,
        reinterpret_cast<const unsigned char*>(data.data()),
        data.size()) != 1)
        return false;
    
    if (EVP_EncryptFinal_ex(ctx.get(), ciphertext.data() + outLen1, &outLen2) != 1)
        return false;
    
    //tag
    std::vector<unsigned char> tag(TAG_SIZE);
    if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag.data()) != 1)
        return false;
    
    // debug:
    std::cout << "nSalt:n"           << bytesToHexString(salt.data(), salt.size())             << std::endl;
    std::cout << "nPassword (hex):n" << bytesToHexString(password.data(), password.size())     << std::endl;
    std::cout << "nDerived key:n"    << bytesToHexString(key.data(), KEY_SIZE)                 << std::endl;
    std::cout << "nIV:n"             << bytesToHexString(iv.data(),  IV_SIZE)                  << std::endl;
    std::cout << "nTAG:n"            << bytesToHexString(tag.data(), TAG_SIZE)                 << std::endl;
    std::cout << "nCiphertext:n"     << bytesToHexString(ciphertext.data(), outLen1 + outLen2) << std::endl;

    // combined: salt, IV, ciphertext, and tag
    std::vector<unsigned char> result;
    result.insert(result.end(), salt.begin(), salt.end());
    result.insert(result.end(), iv.begin(), iv.end());
    result.insert(result.end(), ciphertext.begin(), ciphertext.begin() + outLen1 + outLen2);
    result.insert(result.end(), tag.begin(), tag.end());
    
    data = base64Encode(result.data(), result.size());
    
    // erase buffers...
    return true;
}

int main()
{
    std::vector<unsigned char> password(9);
    RAND_bytes(password.data(), 9);

    std::string base64Password = base64Encode(password.data(), password.size());
    std::cout << "Password: " << base64Password << std::endl;

    std::string data = "Hello, World!";
    encrypt(data, password);

    std::cout << "nEncrypted data:n" << data;
    return 0;
}

javascript decryption implementation:

function decrypt(encryptedBase64, passwordBase64, SALT_SIZE) {
    const KEY_SIZE        = 32;  // AES-256
    const IV_SIZE         = 16;
    const TAG_SIZE        = 16;
    const ITERATION_COUNT = 10000;

    // Decode the base64 encrypted data
    const encryptedBuffer = Buffer.from(encryptedBase64, 'base64');    
    // Decode the base64 password
    const passwordBuffer  = Buffer.from(passwordBase64, 'base64');

    // Extract salt, IV, ciphertext, and tag
    const salt       = encryptedBuffer.slice(0, SALT_SIZE);
    const iv         = encryptedBuffer.slice(SALT_SIZE, SALT_SIZE + IV_SIZE);
    const tag        = encryptedBuffer.slice(-TAG_SIZE);
    const ciphertext = encryptedBuffer.slice(SALT_SIZE + IV_SIZE, -TAG_SIZE);

    // Derive the key using PBKDF2
    const key = crypto.pbkdf2Sync(passwordBuffer, salt, ITERATION_COUNT, KEY_SIZE, 'sha256');

    console.log('nSalt:n',             salt.toString('hex'));
    console.log('nPassword (hex):n',   passwordBuffer.toString('hex'));
    console.log('nDerived key:n',      key.toString('hex'));
    console.log('nIV:n',               iv.toString('hex'));
    console.log('nTAG:n',              tag.toString('hex'));
    console.log('nCiphertext:n',       ciphertext.toString('hex'));

    const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
    decipher.setAuthTag(tag);

    let decrypted = decipher.update(ciphertext);
    decipher.final()

    return decrypted.toString('utf8');
}


(async () =>
{
    const encryptedBase64 = 'p4lx3wi2bstgBR/puZBYOKcJU4Ua41spBbeR9etV9K7BaRWGsUqKUIymO+vaQ1PAlv/M1e9OxExVykGNzQ=='
    const password = 'Et5Q/1E6iTg5'
    try
    {
        const decryptedData = decrypt(encryptedBase64, password, 16)
        console.log('Decrypted data:', decryptedData)
    } catch (error)
    {
        console.error('Decryption failed:', error.message)
    }
}

I confirmed that on the javascript function everything matches the ones generated from the C++, i mean, the password, salt, iv, derived key, ciphertext, but the function fails at decipher.final()
with the error:

Error: Unsupported state or unable to authenticate data
    at Decipheriv.final 

My javascript implementation was mostly based on this question.

What i’m missing?

Access destructured value inside function body in vue

In the docs for vue’s v-model modifiers, they give this example and there is a playground link as well.

<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

This code can be edited so that the modifiers variable is now foo. What kind of pattern is this and how is this achievable (with pseudocode) since the value of const [model, foo] = ... is in a different scope than foo.capitalize?

<script setup>
const [model, foo] = defineModel({
//            ^^^
  set(value) {
    if (foo.capitalize) {
//      ^^^
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

Showing records/data from another database table based on the id in laravel

Hello Please I am trying to view the records of a user based on the user id I used as a foreign key in another table in laravel. Basically I want the name of the userID to show.

This is my Controller

    public function index()
    {
       
        
        $id = User::all();
        $organisedTrips = organisedTrip::where('userID', '=', $id)->get();
    
        $organisedTrips = organisedTrip::paginate(4);
        return view('welcome', compact('organisedTrips'));
        
    }

The user table

The table where I made the userID a foreign key from the user's table

PHP Laravel, error screen shows sensitive information

I have a PHP application using Laravel, whenever there is an error, the system will open a screen containing the error details with db connection details, the database name even the password. How can I prevent the application from showing this sensitive information.
Thank you

OpenSwoole: use UDP server to push messages into a channel

I’m trying to get started with OpenSwoole and I’m using the built-in UDP server. I’d like to push any received messages into a channel so that another coroutine can process them. I’ve Googled extensively and can’t find an obvious way of doing it.

This is the code that I currently have:

// Create a channel with space for 1000 messages
$chan = new OpenSwooleCoroutineChannel(1000);

co::run(function () use ($chan){

    // Listener
    go(function() use ($chan) {
        // Read from channel
        while (1) {
            $data_read = $chan->pop();
            echo ("Data read: $data_readn");
        }
    });
});

// UDP server

// Set coroutine options before the server is started
OpenSwooleCoroutine::set([
        'enable_coroutine' => true
]);

// Start a new UDP server on 12.0.0.1, listening on port 9502
$server = new OpenSwooleServer('127.0.0.1', 9502, OpenSwooleServer::POOL_MODE, OpenSwooleConstant::SOCK_UDP);

// Setup the incoming data event callback, called 'Packet'
$server->on('Packet', function ($server, $data, $clientInfo) use ($chan)
{
    echo ("Data written: $datan");
    $chan->push($data);
});

// Start the server and begin accepting incoming requests
$server->start();

But when I run it I get the error:

===================================================================
 [FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
===================================================================

How do I wrap the UDP server up into a coroutine ? I thought that it already ran as one or have I missed something obvious ?

How to make curl to the same server lightning fast?

I’m trying to create a proxy site AAA.com and relay the traffic to BBB.com in the backend via PHP cURL, and again relay the response from BBB.com to AAA.com visitors. Both sites are on the same server. Below is the code:

$proxied_site = 'https://BBB.com';

$proxied_site_parsed = parse_url($proxied_site);

$ch = curl_init();

$proxied_url = $proxied_site . $_SERVER['REQUEST_URI'];

curl_setopt($ch, CURLOPT_URL, $proxied_url);

curl_setopt($ch, CURLOPT_RESOLVE, array(
    "{$proxied_site_parsed['host']}:443:170.249.199.178",
));

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $_SERVER['REQUEST_METHOD']);
$requestHeaders = [];
foreach (getallheaders() as $name => $value) {
    if ($name == 'Host') {
        $value = $proxied_site_parsed['host'];
    }
    $requestHeaders[] = "$name: $value";
}

curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);

if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT', 'DELETE'])) {
    curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents('php://input'));
}

curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);

$response = curl_exec($ch);

$response_header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$responseHeaders = substr($response, 0, $response_header_size);
$responseBody = substr($response, $response_header_size);

foreach (explode("rn", $responseHeaders) as $header_line) {
    
    if (stripos($header_line, 'HTTP/') === 0 || stripos($header_line, 'Set-Cookie:') === 0) {
        header($header_line, false);
    } else {
        header($header_line);
    }
}

curl_close($ch);

echo $responseBody;

After some benchmarking, cURL still needs about 0.006 seconds of network time to get to the site BBB.com on the same server.

My question is, is it possible to make it faster? Can I make it lightning-fast and as fast as 0.00006 since they are both on the same server?

I tried using IP:

$ch = curl_init('XXX.XXX.XXX.XXX');

And CURLOPT_RESOLVE:

curl_setopt($ch, CURLOPT_RESOLVE, array(
    "{$proxied_site_parsed['host']}:443:XXX.XXX.XXX.XXX",
));

But neither worked and the network around time was still about 0.006s.

Is this possible with cURL at all? Or at least make it 0.0006s?

If not, why?

Adding initialize to body tag if I am using a specific ACF block

I am making a ACF block that includes a google map and I need to add:

onload="initialize()"

to the body tag.
Can I use PHP to add that code conditionally if a unique ACF block is being used on the page?

I tried this:

function check_if_block_exist($block_handle) {
  $post = get_post(); 

  if(has_blocks($post->post_content)) {
    $blocks = parse_blocks($post->post_content);

    foreach( $blocks as $block ) {
      if($block['blockName'] === $block_handle) {
        return true;
      }
    }
    return false;
  }
}

But it didn’t work.

How do I mock Ora with Jest? I can’t get it to validate that start, succeed, info, stop were called

I’ve been trying for quite a while to create a mock implementation of Ora and then use jest to test that it calls several functions from it like start, stop, info. Also, I’m doing this with ES6.

Module:

import ora from 'ora'

export async function myModule({

  const spinner = ora({
    text: "this is a test",
  }).start();

  spinner.info('continue the test)

  spinner.stop()
});

Test:

import { beforeEach, describe, jest } from '@jest/globals'

jest.unstable_mockModule('ora', () => ({
  default: jest.fn(() => ({
    start: jest.fn().mockReturnThis(),
    info: jest.fn().mockReturnThis(),
    succeed: jest.fn().mockReturnThis(),
    fail: jest.fn().mockReturnThis(),
    stop: jest.fn().mockReturnThis(),
  })),
}));

const { default: ora } = await import('ora');
const { myModule } = await import('./myModule.js')

describe('my_test', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  const test = await myModule()
  
  expect(ora.start).toHaveBeenCalled();

I was eventually able to copy what someone else had done and it did work with this code below, but I don’t understand WHY this works. I would like to understand why this works so that I can apply that information to other modules that I may need to mock, and I want to do it with as little code as necessary.

import { beforeEach, describe, jest } from '@jest/globals'

const mockOra = {
  fail: jest.fn(),
  succeed: jest.fn(),
  info: jest.fn(),
  warn: jest.fn(),
  stop: jest.fn(),
};
mockOra.start = jest.fn(() => mockOra);
jest.mock('ora', () => jest.fn(() => mockOra));

const { default: ora } = await import('ora');
const { myModule } = await import('./myModule.js')

describe('my_test', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  const test = await myModule()
  
  expect(ora.start).toHaveBeenCalled();

Child Component function firing before parent state is updated

I have been trying to make a dropdown component that is reusable and decided to put 2 inputs in there so I can validate the range of value. The validation happens but the state passed as a prop does not update before setIsOpen function is fired.

// states
const { data, error, isLoading } = useRegionsData();
  const {
    filters,
    setFilters,
  } = useFilter();

  const [localFilters, setLocalFilters] = useState<FilterValues>({
    price: { min: '', max: '' },
    region: [],
    area: { min: '', max: '' },
    bedroom: '',
  });

  const [localErrors, setLocalErrors] = useState<FilterErrors>({
    area: false,
    bedroom: false,
    price: false,
  });

  console.log(localFilters.price);
  console.log(localErrors);

  /* this useffect initilizes local filter regions to look like a object {id,name,checked} */
  useEffect(() => {
    const savedFilters = localStorage.getItem('filters');
    if (savedFilters) {
      const filterData = JSON.parse(savedFilters) as FilterValues;
      setLocalFilters(filterData);
    } else if (data) {
      const regionData = data.map((region) => ({
        id: region.id,
        name: region.name,
        checked: false,
      }));

      setLocalFilters((prevState) => ({
        ...prevState,
        region: regionData,
      }));
    }
  }, [data, setLocalFilters]);

// update functions
const handlePriceConfirmClick = () => {
    if (!localFilters.price.min || !localFilters.price.max) {
      setLocalErrors((prevErrors) => ({
        ...prevErrors,
        price: true,
      }));

      return;
    }

    if (Number(localFilters.price.min) > Number(localFilters.price.max)) {
      setLocalErrors((prevErrors) => ({
        ...prevErrors,
        price: true,
      }));

      return;
    }

    // If everything is okay, submit the form
    setFilters(localFilters);
    localStorage.setItem('filters', JSON.stringify(localFilters));
  };

  

  const handlePriceChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;

    setLocalFilters((prevState) => {
      const updatedPrice = {
        ...prevState.price,
        [name]: value,
      };

      const minPrice = Number(updatedPrice.min);
      const maxPrice = Number(updatedPrice.max);

      const hasError = minPrice >= maxPrice;
      setLocalErrors((prevErrors) => ({
        ...prevErrors,
        price: hasError,
      }));

      return {
        ...prevState,
        price: updatedPrice,
      };
    });
  };

so what i am interested in is NewDropdown component when handleSubmit happends the error should stop the function from compleating but for some reason the previous value of state is passed to it.

// dropdown component where error is suppose to decide if it closes it
import { useEffect, useRef, useState } from 'react';
import upIcon from '../../assets/images/DropdownIconUp.svg';
import downIcon from '../../assets/images/DropdownIconDown.svg';
import Button from '../button/Button';

type Props = {
  children: React.ReactNode;
  buttonText: string;
  dropdownTitle: string;
  onSubmit: () => void;
  error?: boolean;
};

const NewDropdown = ({
  children,
  dropdownTitle,
  buttonText,
  onSubmit,
  error = false,
}: Props) => {
  const [isOpen, setIsOpen] = useState(false);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);

  /* content outside of dropdown will trigger setIsOpen(false) */
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        buttonRef.current &&
        !buttonRef.current.contains(event.target as Node) &&
        dropdownRef.current &&
        !dropdownRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, []);

  const handleClick = () => {
    setIsOpen((prevState) => !prevState);
  };

  const handleSubmit = () => {
    console.log('err', error);
    onSubmit();
    if (!error) {
      setIsOpen(false);
    }
  };

  return (
    <div className='relative'>
      <button
        ref={buttonRef}
        onClick={handleClick}
        className={`rounded-md py-2 px-[14px] flex justify-center items-center gap-1 text-text font-medium ${
          isOpen ? 'bg-selected' : 'bg-transparent'
        }`}
      >
        {buttonText}
        <span>
          <img
            src={isOpen ? upIcon : downIcon}
            alt={isOpen ? 'menu open icon' : 'menu closed icon'}
          />
        </span>
      </button>
      {isOpen && (
        <div
          ref={dropdownRef}
          className='absolute bottom-0 transform translate-y-full left-0 p-6 rounded-[10px] border border-border bg-white z-20'
        >
          <p className='font-firago font-medium mb-6'>{dropdownTitle}</p>
          {children}
          <div className='flex justify-end mt-[32px]'>
            <Button
              className='bg-primary text-white py-2 px-[14px] rounded-lg font-firago font-medium transition-colors duration-200 ease-linear hover:bg-primaryHover'
              onClick={handleSubmit}
            >
              არჩევა
            </Button>
          </div>
        </div>
      )}
    </div>
  );
};

export default NewDropdown;

My guess was that the state was old so I used let variable instead but with that the error does not update at all because it is not a react state

Is storing socket objects in Map can cause issues in a production environment with larger amount of clients?

I’m using ocpp-rpc package to run an OCPP server, currently I’m using Map to store the connected clients object, I want to reference them later.

I’m storing them like below

const connectedChargers = new Map();

server.on('client', async (client) => {
    console.log(`${client.identity} connected!`);

    connectedChargers.set(client.identity, client); // storing client reference
});

I want to know is this a best practice to do? Is there any better way to achieve this?
My system going to have thousands of clients that connecting to the server, so I need optimal way to handle this.

Also I tried to save them in the Redis, but it fails due to circular references.

Basically I need to know that my aproach is good or bad and if it is bad a better way to achieve this.

I tried to save them in the Redis, but it fails due to circular references. I want

Cannot create entry or view entry list inside the Code Journal

I am making a code journal to write down entries on a virtual journal and make them viewable, editable, and deletable. The error I am getting is:

main.js:71 Uncaught Error: No entries or entry list!
at toggleNoEntries (main.js:71:15)
at HTMLFormElement.<anonymous> (main.js:28:5) .
Can someone tell me what I am missing or doing wrong?

HTML: HTML:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Code Journal</title>
    <link rel="stylesheet" href="css/reset.css" />
    <link rel="stylesheet" href="css/layout.css" />
    <link rel="stylesheet" href="css/styles.css" />
  </head>
   <body>
    <header>
      <div class="container">
        <div class="row">
          <div class="column-full navbar">
            <h1 class="code-journal">Code Journal</h1>
            <div>
              <a href="#" id="entries-link">Entries</a>
            </div>
          </div>
        </div>
      </div>
    </header>
    <main class="container">
      <div data-view="entry-form">
        <div class="row">
          <div class="column-full">
            <h1 class="new-entry">New Entry</h1>
          </div>
        </div>

        <form id="entry-form">
          <div class="row">
            <div class="column-half">
              <img
                id="url-preview"
                src="/images/placeholder-image-square.jpg"
                alt="Image preview"
                class="url-preview" />
            </div>
            <div class="column-half">
              <div class="input">
                <label for="title">Title</label>
                <input type="text" id="title" required />
              </div>
              <div class="input">
                <label for="photo-url">Photo URL</label>
                <input type="url" id="photo-url" required />
              </div>
            </div>
          </div>
          <div class="row">
            <div class="column-full">
              <label for="content">Notes</label>
              <textarea id="content" cols="30" rows="10" required></textarea>
            </div>
          </div>
          <div class="row">
            <div class="column-full button-container">
              <button type="submit">SAVE</button>
            </div>
          </div>
        </form>
      </div>
      <div data-view="entries" class="hidden">
        <div class="row">
          <div class="column-full entries-heading">
            <h1>Entries</h1>
            <p class="no-entries">No entries</p>
            <a href="#" id="new-entry-button" class="new-entry-button">NEW</a>
          </div>
        </div>
        <ul class="entry-list"></ul>
      </div>
    </main>
    <script src="js/data.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>

Typescript:

const $form = document.querySelector('#entry-form') as HTMLFormElement;
const $urlPreview = document.querySelector('#url-preview') as HTMLImageElement;
const $photoUrlInput = document.querySelector('#photo-url') as HTMLInputElement;

if (!$form) throw new Error('$form query failed!');
if (!$urlPreview) throw new Error('$urlPreview query failed!');
if (!$photoUrlInput) throw new Error('$photoUrlInput query failed!');

$photoUrlInput.addEventListener('input', function (event: Event) {
  const target = event.target as HTMLInputElement;
  $urlPreview.src = target.value || 'images/placeholder-image-square.jpg';
});

$form.addEventListener('submit', function (event: Event) {
  event.preventDefault();

  const newEntry = {
    entryId: data.nextEntryId,
    title: ($form.elements.namedItem('title') as HTMLInputElement).value,
    photoUrl: $photoUrlInput.value,
    content: ($form.elements.namedItem('content') as HTMLTextAreaElement).value,
  };
  const $newEntryElement = renderEntry(newEntry);
  const $entryList = document.getElementById('entry-list');

  if ($entryList && $newEntryElement) {
    $entryList.appendChild($newEntryElement);
  }

  toggleNoEntries();

  data.nextEntryId++;
  data.entries.unshift(newEntry);

  writeData();

  $form.reset();
  $urlPreview.src = 'images/placeholder-image-square.jpg';
});

function renderEntry(entry: JournalEntry): HTMLElement {
  const $li = document.createElement('li');
  $li.classList.add('row');

  const $imgWrapper = document.createElement('div');
  $imgWrapper.classList.add('column-half');

  const $img = document.createElement('img');
  $img.src = entry.photoUrl;
  $img.alt = `${entry.title}`;
  $img.classList.add('url-preview');

  const $div = document.createElement('div');
  $div.classList.add('column-half');

  const $h2 = document.createElement('h2');
  $h2.textContent = entry.title;

  const $p = document.createElement('p');
  $p.textContent = entry.content;

  $li.appendChild($imgWrapper);
  $li.appendChild($div);
  $div.appendChild($h2);
  $div.appendChild($p);

  return $li;
}

document.addEventListener('DOMContentLoaded', function () {
  const $ul = document.querySelector('ul');
  if (!$ul) throw new Error('$ul query has failed!');

  data.entries.forEach((entry) => {
    const entryElement = renderEntry(entry);
    $ul.appendChild(entryElement);
  });
});

function toggleNoEntries(): void {
  const $noEntries = document.getElementById(
    'no-entries',
  ) as HTMLParagraphElement;
  // const $entryList = document.getElementById('.entry-list');

  if (!$noEntries) throw new Error('No entries!');

  if (data.entries.length === 0) {
    $noEntries.style.display = 'block';
  } else {
    $noEntries.style.display = 'none';
  }
}

function viewSwap(view: 'entries' | 'entry-form'): void {
  const $entriesView = document.querySelector(
    '[data-view="entries"]',
  ) as HTMLElement;
  const $entryFormView = document.querySelector(
    '[data-view="entry-form"]',
  ) as HTMLElement;

  if (!$entriesView || !$entryFormView)
    throw new Error('View elements not found!');

  if (view === 'entries') {
    $entriesView.classList.remove('hidden');
    $entryFormView.classList.add('hidden');
  } else if (view === 'entry-form') {
    $entryFormView.classList.remove('hidden');
    $entriesView.classList.add('hidden');
  }

  data.view = view;
}

const $entriesLink = document.getElementById(
  'entries-link',
) as HTMLAnchorElement;

if (!$entriesLink) throw new Error('$entriesLink query failed!');

$entriesLink.addEventListener('click', function (event: Event) {
  event.preventDefault();
  viewSwap('entries');
});

const $newEntryButton = document.getElementById(
  'new-entry-button',
) as HTMLAnchorElement;

if (!$newEntryButton) throw new Error('$newEntryButton query failed!');

$newEntryButton.addEventListener('click', function (event: Event) {
  event.preventDefault();
  viewSwap('entry-form');
});

I don’t need $entryList, but if I were to delete it, I would lose the content of the title and notes of when I press the entries button inside of the header. Could it also be something wrong I did in my html?

Hamburger Menu Only Works on index.html, Not Other Pages in My Portfolio Website

I’m working on a personal portfolio website and have implemented a hamburger menu for mobile views. The hamburger menu works perfectly on my index.html page, but it doesn’t function on any of the other pages like about.html or research.html.

The hamburger menu in my index.html works as expected, but when I navigate to any other page (e.g., about.html), clicking the menu doesn’t do anything. I use the same HTML structure and link to the same external JavaScript file (scripts.js) for all pages.

Here’s my setup:
index.html (Header part):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Portfolio | Home</title>
    <link rel="stylesheet" href="styles.css"> <!-- Link to CSS -->
    <script defer src="scripts.js"></script> <!-- Link to JavaScript -->
    <link rel="icon" href="images/logos/favicon.png" type="image/png">
</head>
<body>
    <!-- Navigation Bar -->
    <header>
        <div class="nav-container">
            <div class="logo">
                <a href="index.html">
                    <img src="images/logos/logo.png" alt="Logo">
                </a>
            </div>
            <nav class="nav-menu">
                <a href="about.html">About</a>
                <a href="research.html">Research</a>
                <a href="blog.html">Blog</a>
                <a href="publications.html">Publications</a>
            </nav>
            <div class="hamburger-menu">
                <span></span>
                <span></span>
                <span></span>
            </div>
        </div>
    </header>
</body>
</html>

about.html (Same structure as index.html for the header):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Portfolio | About</title>
    <link rel="stylesheet" href="styles.css"> <!-- Link to CSS -->
    <script defer src="scripts.js"></script> <!-- Link to JavaScript -->
    <link rel="icon" href="images/logos/favicon.png" type="image/png">
</head>
<body>
    <!-- Navigation Bar -->
    <header>
        <div class="nav-container">
            <div class="logo">
                <a href="index.html">
                    <img src="images/logos/logo.png" alt="Logo">
                </a>
            </div>
            <nav class="nav-menu">
                <a href="about.html">About</a>
                <a href="research.html">Research</a>
                <a href="blog.html">Blog</a>
                <a href="publications.html">Publications</a>
            </nav>
            <div class="hamburger-menu">
                <span></span>
                <span></span>
                <span></span>
            </div>
        </div>
    </header>
</body>
</html>

JavaScript (scripts.js):

document.addEventListener('DOMContentLoaded', () => {
    const texts = [
        "where we explore the evolution and pharmacology of proteins.",
        "where we investigate the expansion of genes.",
        "where we conduct studies.",
        "where we study structure.",
        "where we learn new tools and explore visualization."
    ];

    let index = 0;
    const animatedTextElement = document.getElementById('animated-text');
    console.log('Animated text element:', animatedTextElement);

    function typeWriter(text, callback) {
        let i = 0;
        const speed = 50;

        function typing() {
            if (i < text.length) {
                animatedTextElement.textContent += text.charAt(i);
                i++;
                setTimeout(typing, speed);
            } else if (callback) {
                setTimeout(callback, 1000);
            }
        }

        typing();
    }

    function deleteText(callback) {
        let i = animatedTextElement.textContent.length;
        const speed = 30;

        function deleting() {
            if (i > 0) {
                animatedTextElement.textContent = animatedTextElement.textContent.substring(0, i - 1);
                i--;
                setTimeout(deleting, speed);
            } else if (callback) {
                setTimeout(callback, 500);
            }
        }

        deleting();
    }

    function cycleTexts() {
        typeWriter(texts[index], () => {
            deleteText(() => {
                index = (index + 1) % texts.length;
                cycleTexts();
            });
        });
    }

    cycleTexts();

    // Smooth scrolling for a specific section
    const videoSection = document.querySelector('.specific-section');
    if (videoSection) {
        const videoLink = document.querySelector('.scroll-to-section');
        if (videoLink) {
            videoLink.addEventListener('click', (event) => {
                event.preventDefault();
                videoSection.scrollIntoView({ behavior: 'smooth' });
            });
        }
    }

    // Form validation
    function validateForm(event) {
        const name = document.getElementById("name").value.trim();
        const email = document.getElementById("email").value.trim();
        const message = document.getElementById("message").value.trim();

        if (name === "" || email === "" || message === "") {
            alert("Please fill in all the required fields.");
            event.preventDefault(); // Prevent form submission if validation fails
            return false;
        }

        return true;
    }

    const form = document.getElementById("formId");
    if (form) {
        form.addEventListener("submit", validateForm);
    }

    // Hamburger menu toggle
    const hamburgerMenu = document.querySelector('.hamburger-menu');
    const navMenu = document.querySelector('.nav-menu');

    console.log('Hamburger menu:', hamburgerMenu);
    console.log('Nav menu:', navMenu);

    if (hamburgerMenu && navMenu) {
        hamburgerMenu.addEventListener('click', () => {
            navMenu.classList.toggle('active');
        });
    }
});

What I’ve Tried:

  1. Verified that the external JavaScript file is linked correctly on all pages (scripts.js is loaded).
  2. The HTML structure for the navigation bar is the same on both index.html and about.html.
  3. Checked for JavaScript errors in the console on about.html – no errors are shown.
  4. The JavaScript works on index.html but not on other pages.

My Expected Behavior:

I want the hamburger menu to toggle the .nav-menu on and off when clicked, across all pages, not just on the homepage (index.html).

What Could Be Causing the Issue?

  1. Could it be related to how I’m referencing the JavaScript or HTML structure across pages?
  2. Is there an issue with the JavaScript being loaded on other pages?

Any help or insights would be appreciated! Thanks in advance!

Application alert pop-up not appearing when browser launched via playwright

self.browser = self.playwright.chromium.launch(
                headless = False,
                slow_mo = 2000,
                devtools= True,
        args = [
            
            r"--user-data-dir=C:UsersuserAppDataLocalTempchrome_profile",
             "--allow-pre-commit-input" ,
        "--disable-background-networking","--disable-backgrounding-occluded-windows","--disable-blink-features=AutomationControlled",
        "--disable-browser-side-navigation","--disable-client-side-phishing-detection","--disable-default-apps" ,"--disable-dev-shm-usage","--disable-extensions",
        "--disable-features=VizDisplayCompositor","--disable-gpu","--disable-hang-monitor" ,"--disable-infobars" ,
        "--disable-popup-blocking" ,"--disable-prompt-on-repost","--disable-setuid-sandbox" ,"--disable-software-rasterizer","--disable-sync","--disable-web-security","--enable-automation",
        "--enable-logging ","--ignore-certificate-errors" ,"--log-level=0 "," --no-first-run",
        "--no-sandbox","--no-service-autorun","--password-store=basic","--proxy-bypass-list=*" ,"--proxy-server='direct://'","--remote-debugging-port=0" ,"--test-type" ,
        "--use-mock-keychain","--user-data-"
        ]
        self._browser = BrowserType.create_browser(browser_type)
        self._context = self._browser.new_context(              
                no_viewport = True,
                accept_downloads=True,
                bypass_csp=True,
                ignore_https_errors=True,
                 permissions=["geolocation", "notifications"],
            )
        self._context.clear_cookies()
         self._context.add_cookies([{
         'name': 'name',
         'value': 'value',
         'domain': 'domain',
         'path': '/'
         }])
  
        self._page = self._context.new_page()
<!-- BUTTONS START -->
<br>
&nbsp;
<input type="button" id="rules" name="rules" value="Rules" class="button-raised-primary" onclick="execute(this.form, 'rules');" accesskey="" style="">
&nbsp;
<input type="button" id="marketReport" name="marketReport" value="Launch market report" class="button-raised-primary" onclick="execute(this.form, 'marketReport');" accesskey="" style="">
&nbsp;
<input type="button" id="factReport" name="factReport" value="Launch fact report" class="button-raised-primary" onclick="execute(this.form, 'factReport');" accesskey="" style="">
</tr>
</tbody></table>
</div>
<!-- BUTTONS END -->

This is how i am launching the playwright browser and navigating to pages and when clicked on certain buttons the expected alert pop-up is not coming but if i refresh the browser manually by pausing the execution the pop-up starts appearing on those button click.
Also have provided the HTML of those buttons
say When i click to marketReport button the alert pop-up should appear but through playwright browser nothing is happening.Also in console execute function is not searchable which if i search through manually launched browser it works fine.
Button clicks should throw alert pop-up every time.

I have tried modifying the args that we pass to browser during launch but it didnt work.the alert pop-up should open on clicking buttons without manual intervention

How can I use Cloudflare Pages as an API server like Cloudflare Workers?

I’m currently using Cloudflare Workers as an API endpoint to return data to my application when I call the Worker URL. I’d like to achieve the same functionality using Cloudflare Pages. How can I configure Cloudflare Pages to return JSON data to my application instead of displaying web pages?
Any guidance on how to set up Cloudflare Pages to function as an API server would be greatly appreciated.