Can @typedef describe objects partially

I have a message object that can have all kinds of keys, some of which I know, some of them I can’t know.

// @ts-check
/**
 * @typedef {Object} Message
 * @property {String} sender
 * @property {String} receiver
*/

/** @type {Message} */
let msg = {
  sender: "preference-manager",
  receiver: "user-manager",
  deletePref: "refresh-rate"
}

I get an error message:

Object literal may only specify known properties, and ‘deletePref’ does not exist in type ‘Message’.ts(2353)

Is there a way to define an incomplete type so that TypeScript compiler won’t complain?

P.S. I use tsc to improve type safety of the JS code, but it still has to be valid JS.

Ambiguous information about WebGL clip space

I am reading about WebGL clip space, I think it basically should mean the same thing as coordinate system. The same site specifies ambiguous, information.
In WebGL basics is specified left hand system, where z aux goes from -1 to 1:
WebGL basics clip space
enter image description here.

But in WebGL game development basics the coordinate system is specified as right handed, like in OpenGL where z axis goes in opposite direction, from 1 to -1:
WegGL game development coordinate system.
enter image description here
Which variant is the correct one? What I’ve practically seen so far, it was consistent with left handed.

Custom WordPress Customizer Control for Typography Presets renders blank section or fallback , despite correct class registration

Problem
I’m building a WordPress theme and want a Global → Typography → Font Presets control in the Customizer that shows a grid of clickable cards (each card previews a heading/body Google-Font pair). Instead of my custom card UI, the section is either blank or falls back to a basic <select> (or radio list) control. I’ve tried many variations of register_control_type(), direct instantiation, OPcache resets, and cleanup of duplicate classes, but no luck.

What I’ve Done
Autoloader in functions.php (recursively includes /inc/ files):

// in functions.php
$rii = new RecursiveIteratorIterator(
  new RecursiveDirectoryIterator( __DIR__ . '/inc' )
);
foreach ( $rii as $file ) {
  if ( ! $file->isDir() && $file->getExtension() === 'php' ) {
    require_once $file->getPathname();
  }
}

Bootstrap singleton in inc/class-zero-customizer.php:

<?php
if ( ! defined( 'ABSPATH' ) ) exit;

class Zero_Customizer {
  private static $instance = null;

  public static function get_instance() {
    if ( null === self::$instance ) {
      self::$instance = new self();
      self::$instance->hooks();
    }
    return self::$instance;
  }

  private function hooks() {
    error_log( 'Zero: hooks() running' );
    add_action( 'customize_register',                [ $this, 'register_typography_control' ] );
    add_action( 'customize_controls_enqueue_scripts',[ $this, 'enqueue_control_assets' ] );
    add_action( 'customize_preview_init',            [ $this, 'enqueue_preview_assets' ] );
  }

  public function register_typography_control( $wp_customize ) {
    error_log( 'Zero: register_typography_control() fired' );
    require_once __DIR__ . '/customizer/controls/class-zero-control-typography.php';

    // Panel & section
    if ( ! $wp_customize->get_panel( 'zero_global_panel' ) ) {
      $wp_customize->add_panel( 'zero_global_panel', [
        'title'    => __( 'Global Settings', 'zero' ),
        'priority' => 10,
      ] );
    }
    $wp_customize->add_section( 'zero_typography_section', [
      'title'    => __( 'Typography', 'zero' ),
      'panel'    => 'zero_global_panel',
      'priority' => 10,
    ] );
    error_log( 'Zero: added section zero_typography_section' );

    // Presets & setting
    $presets = [
      'playfair-open-sans'         => esc_html__( 'Playfair Display / Open Sans', 'zero' ),
      /* …other 9 pairs… */
    ];
    $wp_customize->add_setting( 'zero_typography_preset', [
      'default'           => 'playfair-open-sans',
      'sanitize_callback' => function( $val ) use ( $presets ) {
        return isset( $presets[ $val ] ) ? $val : 'playfair-open-sans';
      },
      'transport'         => 'postMessage',
    ] );

    // Direct instantiation of custom control
    $wp_customize->add_control( new Zero_Control_Typography(
      $wp_customize,
      'zero_typography_preset',
      [
        'label'       => __( 'Font Presets', 'zero' ),
        'description' => __( 'Click a card to choose your Heading/Body pair.', 'zero' ),
        'section'     => 'zero_typography_section',
        'choices'     => $presets,
      ]
    ) );
    error_log( 'Zero: added custom-control for zero_typography_preset' );
  }

  public function enqueue_control_assets() {
    // Load panel CSS & JS
    wp_enqueue_style(
      'zero-customizer-controls',
      get_stylesheet_directory_uri() . '/assets/dist/css/main.min.css',
      [], filemtime( get_stylesheet_directory() . '/assets/dist/css/main.min.css' )
    );
    wp_enqueue_script(
      'zero-customizer-controls',
      get_stylesheet_directory_uri() . '/assets/dist/js/customizer.bundle.js',
      [ 'jquery','customize-controls' ],
      filemtime( get_stylesheet_directory() . '/assets/dist/js/customizer.bundle.js' ),
      true
    );
  }

  public function enqueue_preview_assets() {
    // Load iframe JS for live preview
    wp_enqueue_script(
      'zero-customizer-preview',
      get_stylesheet_directory_uri() . '/assets/dist/js/customizer.bundle.js',
      [ 'jquery','customize-preview' ],
      filemtime( get_stylesheet_directory() . '/assets/dist/js/customizer.bundle.js' ),
      true
    );
  }
}

add_action( 'after_setup_theme', [ 'Zero_Customizer', 'get_instance' ] );

Custom Control in inc/customizer/controls/class-zero-control-typography.php:

<?php
if ( ! class_exists( 'WP_Customize_Control' ) ) {
  return;
}
if ( ! class_exists( 'Zero_Control_Typography' ) ) {
  class Zero_Control_Typography extends WP_Customize_Control {
    public $type = 'typography';

    public function render_content() {
      error_log( 'Zero: Zero_Control_Typography::render_content()' );
      if ( empty( $this->choices ) ) {
        return;
      }

      echo '<span class="customize-control-title">' . esc_html( $this->label ) . '</span>';
      if ( $this->description ) {
        echo '<span class="description customize-control-description">'
             . esc_html( $this->description ) . '</span>';
      }

      echo '<ul>';
      foreach ( $this->choices as $slug => $name ) {
        $checked = checked( $this->value(), $slug, false );
        list( $h, $b ) = explode( '-', $slug, 2 );
        printf(
          '<li><label class="preset-card">'
          . '<input type="radio" data-customize-setting-link="%1$s" value="%2$s"%3$s />'
          . '<span class="preset-card__heading" style="font-family:'%4$s';">Heading</span>'
          . '<span class="preset-card__body"    style="font-family:'%5$s';">Body text</span>'
          . '</label></li>',
          esc_attr( $this->id ), esc_attr( $slug ), $checked,
          esc_attr( ucwords( str_replace('-', ' ', $h)) ),
          esc_attr( ucwords( str_replace('-', ' ', $b)) )
        );
      }
      echo '</ul>';
    }
  }
}

SCSS & JS

  • Imported into my normal assets/css/sass/main.scss and assets/js/customizer.js builds.
  • Enqueued in the panel via customize_controls_enqueue_scripts and preview via customize_preview_init.

Errors & Symptoms

  • Blank Typography section, despite register_typography_control() firing in the logs.

  • If I try array‐style or register_control_type(), it instead renders a plain <select> or radio list.

  • Encountered duplicate‐class “Cannot declare class Zero_Control_Typography” until I deleted old files.

  • Tried OPcache resets, restarting Docker, multiple include patterns—still no card UI.

Questions

  • Why is WP not rendering my Zero_Control_Typography::render_content() output?
  • Is there a necessary hook priority or missing argument I’m overlooking?
  • What’s the minimal, fool-proof way to ensure WP uses my custom control subclass rather than falling back?
  • Are there any Astra‐style patterns (specific enqueue hooks, control registration order) I should mimic?

Any guidance or working minimal example would be hugely appreciated—thanks!

bimber theme is not activating even i have purchased code [closed]

I have bimber WordPress theme which i bought in 2019 I have a license code, even when i try to put the code it says error you can see in attach picture

enter image description here

error : Token Registration
When automatic registration fails, please unlock the theme using this token method. Click the following link to get your individual token and enter it below. Generate token

when i click generate token, it gives error 404 on this link https://api.bringthepixel.com/?action=register&theme=bimber&purchase_code=5b8dff06-e999-4021-8d75-1e828fa50a10&site_url=https%3A%2F%2Fpakistantopstories.com

as the website is no longer available any help on that

any one help on that so can i fix it manually by any way

IMAP message_id not visible in some messages, php says it’s an empty string [closed]

The IMAP message_id in some messages has a nonzero strlen (e.g., 62) but the text is not visible if I echo it, and var_dump says it’s an empty string. If I use ord and chr to duplicate the string character by character it looks like a legit message_id but the reconstructed string is still not visible if I echo it, and var_dump still says it’s an empty string. Has anyone else encountered this? It’s like a ghost message_id. It’s there but it’s not there and I can’t do anything with it.

array_map and filter_var return unexpected results

I have the following code when submitting a form

$data['item_cost'] = ( isset( $_POST['item-cost'] ) ? array_map( "filter_var", array_filter( $_POST['item-cost'] ), array( FILTER_VALIDATE_FLOAT ) ) : "" );

but the result returns the first item as valid and the other items as false. Here’s an example of the $_POST[‘item-cost’] value

array(3) {
  [0]=>
  string(4) "6.15"
  [1]=>
  string(4) "6.15"
  [2]=>
  string(4) "0.50"
}

and the resulting $data[‘item-cost’] value:

array(3) {
  [0]=>
  float(6.15)
  [1]=>
  bool(false)
  [2]=>
  bool(false)
}

I feel like I’m missing something obvious here? Thanks.

PHPUnit on Apache – how to capture “console” output?

I’m implementing the server API (for geni.com) in PHP. The server requires OAuth authentication, so I need a browser because this requires user input (to permit access to their account). THIS all works fine.

Now I want to use PHPUnit to test the whole thing. My index.php calls the testsuite, and I THINK the tests are running (no errors in log, and it continues running past the call). Obviously there is no console for the output.

So HOW can I capture the test results?

skip number +=2. why? [closed]

I want to go to next number of my page. When I select for example row 10 every thing is ok and 20 as well. But when I select 10 or 20 or 50, and then change to another number of row, my page number skip +=2.

My problem is occurred when I shift to another row number for showing numbers. this project is the page for numbers and has 189 rows and you can see the numbers by 10 rows or 20 rows or 50 rows. I create the right angle for next and left angle for previous. I want to go 1 by 1 when I click on “>”or “<“

// this code is related to bottom of mobile number page for showing the number of rows
const toggleVisibility = () => {
    let tfootTdInput = document.querySelector(".tfoot-td-input"); // the number between <>
    tfootTdInput.value = "1";
    let tfootRow = document.getElementById("tfoot-row");
    let selectedValue = tfootRow.value;
    let hidden1 = document.querySelectorAll(".hidden1-10");
    let hidden11 = document.querySelectorAll(".hidden11-20");
    let hidden111 = document.querySelectorAll(".hidden111-50");



    if (selectedValue == 10) {

        hidden1.forEach(tr => {
            tr.style.display = "table-row"; //  show rows
        });

        let currentStartRow = 1; // the number for starting row
        const rowsPerPage = 10; // count of roes' number in each page
        const totalRows = 388; // number of all rows
        const rightAngleClick = document.querySelector("#tfootangleRight");
        const leftAngleClick = document.querySelector("#tfootangleLeft");
        const skipFirstPageNumber = document.querySelector("#skipFirstPageNumber");
        const skipLastPageNumber = document.querySelector("#skipLastPageNumber");


        const updateRowVisibility = () => {
            // hide rows
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });

            // counting new rows for showing
            const endRow = Math.min(currentStartRow + rowsPerPage - 1);
            for (let i = currentStartRow; i <= endRow; i++) {
                const rowToShow = document.querySelector(`.hidden${i}`);
                if (rowToShow) {
                    rowToShow.style.display = 'table-row'; // show row
                }

            }
            if (tfootTdInput.value == "1") {
                leftAngleClick.style.visibility = "hidden";
                skipFirstPageNumber.style.visibility = "hidden";
            }
            else if (tfootTdInput.value == "18") {
                rightAngleClick.style.visibility = "visible";
                skipLastPageNumber.style.visibility = "visible";
            }

            else {
                leftAngleClick.style.visibility = "visible";
                skipFirstPageNumber.style.visibility = "visible";

            }


        };

        // this function is for (>) button
            rightAngleClick.addEventListener("click", () => {
                // extend the number of row

                currentStartRow += rowsPerPage;
                currentStartRow > totalRows ? currentStartRow = totalRows : currentStartRow; // for avoiding of becomming row number bigger than number row(388)
                tfootTdInput.value ++;

                if (tfootTdInput.value == "19 ") {
                    rightAngleClick.style.visibility = "hidden";
                    skipLastPageNumber.style.visibility = "hidden";
                }

                updateRowVisibility(); // updating the view of number page
            });

        // this function is for (<) button
        leftAngleClick.addEventListener("click", () => {

            currentStartRow -= rowsPerPage;

            if (currentStartRow < 1) {
                currentStartRow = 1; // for avoiding of becomming row number smaller than 1

            }
            tfootTdInput.value--;


            updateRowVisibility(); // updating the view of number page

        });

        // at first updating the view of number page
        updateRowVisibility();

        skipFirstPageNumber.addEventListener('click', () => {    //skip to first page of numbers

            leftAngleClick.style.visibility = "hidden";
            skipFirstPageNumber.style.visibility = "hidden";
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });
            tfootTdInput.value = 1;
            hidden1.forEach(tr => {

                tr.style.display = "table-row"
            });
            rightAngleClick.style.visibility = "visible";
            skipLastPageNumber.style.visibility = "visible";
        })

        skipLastPageNumber.addEventListener('click', () => {     //skip to last page of numbers

            rightAngleClick.style.visibility = "hidden";
            skipLastPageNumber.style.visibility = "hidden";
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });
            tfootTdInput.value = 19;
            leftAngleClick.style.visibility = "visible";
            skipFirstPageNumber.style.visibility = "visible";
            const lastPageNum10 = document.querySelectorAll(".hidden181-189");
            lastPageNum10.forEach(tr => {
                tr.style.display = "table-row"
            })

        })
        










    }
    else if (selectedValue == 20) {
        hidden11.forEach(tr => {
            tr.style.display = "table-row"; // نمایش hidden11
        });





        let tfootTdInput = document.querySelector(".tfoot-td-input"); // the number between <>
        let currentStartRow = 1; // the number for starting row
        const rowsPerPage2 = 20; // count of roes' number in each page
        const totalRows = 388; // number of all rows
        const rightAngleClick = document.querySelector("#tfootangleRight");

        const updateRowVisibility = () => {
            // hide rows
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });

            // counting new rows for showing
            const endRow = Math.min(currentStartRow + rowsPerPage2 - 1);
            for (let i = currentStartRow; i <= endRow; i++) {
                const rowToShow = document.querySelector(`.hidden${i}`);
                if (rowToShow) {
                    rowToShow.style.display = 'table-row'; // show row
                }

            }
            if (tfootTdInput.value == "1") {
                tfootangleLeft.style.visibility = "hidden";
                skipFirstPageNumber.style.visibility = "hidden";
            }
            else if (tfootTdInput.value == "10") {
                rightAngleClick.style.visibility = "hidden";
                skipLastPageNumber.style.visibility = "hidden";
            }

            else if (tfootTdInput.value == "9") {
                rightAngleClick.style.visibility = "visible";
                skipLastPageNumber.style.visibility = "visible";
            }

            else {
                tfootangleLeft.style.visibility = "visible";
                skipFirstPageNumber.style.visibility = "visible";

            }



        };

        // this function is for (>) button
        rightAngleClick.addEventListener("click", () => {
            // extend the number of row
            currentStartRow += rowsPerPage2;
            if (currentStartRow > totalRows) {
                currentStartRow = totalRows; // for avoiding of becomming row number bigger than number row(388)
            }
            tfootTdInput.value++;


            updateRowVisibility(); // updating the view of number page
        });

        // this function is for (<) button
        tfootangleLeft.addEventListener("click", () => {

            currentStartRow -= rowsPerPage2;

            if (currentStartRow < 1) {
                currentStartRow = 1; // for avoiding of becomming row number smaller than 1

            }
            tfootTdInput.value--;

            updateRowVisibility(); // updating the view of number page

        });

        // at first updating the view of number page
        updateRowVisibility();


        skipFirstPageNumber.addEventListener('click', () => {    //skip to first page of numbers

            leftAngleClick.style.visibility = "hidden";
            skipFirstPageNumber.style.visibility = "hidden";
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });
            tfootTdInput.value = 1;
            hidden1.forEach(tr => {

                tr.style.display = "table-row"
            });
            rightAngleClick.style.visibility = "visible";
            skipLastPageNumber.style.visibility = "visible";
        })

        skipLastPageNumber.addEventListener('click', () => {     //skip to last page of numbers

            rightAngleClick.style.visibility = "hidden";
            skipLastPageNumber.style.visibility = "hidden";
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });
            tfootTdInput.value = 10;
            leftAngleClick.style.visibility = "visible";
            skipFirstPageNumber.style.visibility = "visible";
            const lastPageNum20 = document.querySelectorAll(".hidden181-189");
            lastPageNum20.forEach(tr => {
                tr.style.display = "table-row"
            })

        })





    }
    else if (selectedValue == 50) {
        hidden111.forEach(tr => {
            tr.style.display = "table-row"; // نمایش hidden111
        });




        let tfootTdInput = document.querySelector(".tfoot-td-input"); // the number between <>
        let currentStartRow = 1; // the number for starting row
        const rowsPerPage3 = 50; // count of roes' number in each page
        const totalRows = 388; // number of all rows
        const rightAngleClick = document.querySelector("#tfootangleRight");

        const updateRowVisibility = () => {
            // hide rows
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });

            // counting new rows for showing
            const endRow = Math.min(currentStartRow + rowsPerPage3 - 1);
            for (let i = currentStartRow; i <= endRow; i++) {
                const rowToShow = document.querySelector(`.hidden${i}`);
                if (rowToShow) {
                    rowToShow.style.display = 'table-row'; // show row
                }

            }
            if (tfootTdInput.value == "1") {
                tfootangleLeft.style.visibility = "hidden";
                skipFirstPageNumber.style.visibility = "hidden";
            }
            else if (tfootTdInput.value == "4") {
                rightAngleClick.style.visibility = "hidden";
                skipLastPageNumber.style.visibility = "hidden";
            }

            else if (tfootTdInput.value == "3") {
                rightAngleClick.style.visibility = "visible";
                skipLastPageNumber.style.visibility = "visible";
            }

            else {
                tfootangleLeft.style.visibility = "visible";
                skipFirstPageNumber.style.visibility = "visible";

            }


        };

        // this function is for (>) button
        rightAngleClick.addEventListener("click", () => {
            // extend the number of row
            currentStartRow += rowsPerPage3;
            if (currentStartRow > totalRows) {
                currentStartRow = totalRows; // for avoiding of becomming row number bigger than number row(388)
            }
            tfootTdInput.value++;


            updateRowVisibility(); // updating the view of number page
        });

        // this function is for (<) button
        tfootangleLeft.addEventListener("click", () => {

            currentStartRow -= rowsPerPage3;

            if (currentStartRow < 1) {
                currentStartRow = 1; // for avoiding of becomming row number smaller than 1

            }
            tfootTdInput.value--;

            updateRowVisibility(); // updating the view of number page

        });

        // at first updating the view of number page
        updateRowVisibility();

    }
    else {
        hidden1.forEach(tr => {
            tr.style.display = "none"; // نمایش hidden111
        });
        hidden11.forEach(tr => {
            tr.style.display = "none"; // نمایش hidden111
        });
        hidden111.forEach(tr => {
            tr.style.display = "none"; // نمایش hidden111
        });

        skipFirstPageNumber.addEventListener('click', () => {    //skip to first page of numbers

            leftAngleClick.style.visibility = "hidden";
            skipFirstPageNumber.style.visibility = "hidden";
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });
            tfootTdInput.value = 1;
            hidden1.forEach(tr => {

                tr.style.display = "table-row"
            });
            rightAngleClick.style.visibility = "visible";
            skipLastPageNumber.style.visibility = "visible";
        })

        skipLastPageNumber.addEventListener('click', () => {     //skip to last page of numbers

            rightAngleClick.style.visibility = "hidden";
            skipLastPageNumber.style.visibility = "hidden";
            const allRows = document.querySelectorAll('tr.display-none');
            allRows.forEach(td => {
                td.style.display = 'none';
            });
            tfootTdInput.value = 4;
            leftAngleClick.style.visibility = "visible";
            skipFirstPageNumber.style.visibility = "visible";
            const lastPageNum50 = document.querySelectorAll(".hidden151-189");
            lastPageNum50.forEach(tr => {
                tr.style.display = "table-row"
            })

        })

    };

};

I’ve changed some variables and numbers but wasn’t enough.

How to show only children that are not overflow from their parent?

I have a parent div with a certain width with some children items, I want to show as many as possible of children in the parent that are not overflow from the parent ?

For example in the code here –

https://jsfiddle.net/vk9256sp/10/

.parent {
  width: 200px;
  border: 2px solid black;
  display: flex;
  overflow: hidden
}

.item {
  margin: 5px;
  padding: 2px;
  border: 1px solid black;
}
<div class="parent">
  <div class="item">
    Hello1
  </div>
  <div class="item">
    Hello2
  </div>
  <div class="item">
    Hello3
  </div>
  <div class="item">
    Hello4
  </div>
  <div class="item">
    Hello5
  </div>
  <div class="item">
    Hello6
  </div>
</div>

I want the show the first 3 items, and stop show the children from the 4th one because they started to overflow

(The answer should be for any width of the parent and any number of children, also I only care about the overflow in the width)

Why is Postman response.json() method not working?

I have the below Pre-request script in my Postman that gets the authorisation token from loginRequest and appends to new requests each run:

const loginRequest = {
    url: `[url_to_authenticate]`,
    method: 'POST',
    header: {
        'Content-Type': 'application/json',
        'Accept': 'application/json, text/plain, */*'
    },
    body: {
        mode: 'application/json', // Should this already specify the response format?
        raw: JSON.stringify([
            { "AttributeID": 0, "AttributeKey": "string", "Value": "[key_info]" },
            { "AttributeID": 1, "AttributeKey": "string", "Value": "[key_info]" }
        ]
        )
    }
};

pm.sendRequest(loginRequest, function (err, response) {
    console.log(response.json().ApiKey);
    if (response.json().ApiKey) {
        pm.request.headers.add({
            key: "apiKey"
            value: response.json().ApiKey,
            description: null,
            type: "text",
            enabled: true,
    }
});

For another project, this works fine (and I am not the one who set up the Backend). But my current one outputs the following error:

TypeError: Cannot read properties of undefined (reading ‘json’)

And when I try console.log(response), it outputs the following object (as an example):

{
     id: "16a8922b-e32a-419c-9d87-e6dded6cf8fa"
     status: "OK"
     code: 200
     header: [6]
     stream: {…}
     cookie: [0]
     responseTime: 55
     responseSize: 265
     downloadedBytes: 265
}

Issue with Injecting Text into WhatsApp Web Input via JavaScript Extension

I’m working on a JavaScript extension for WhatsApp Web, and I’m facing a problem I can’t seem to solve. The goal of my extension is to correct and manipulate the text in the message input of WhatsApp Web, but I’m stuck on an issue with text injection.

I can correctly retrieve the text from the last message in the input field using elements, but I’m unable to inject this text into the message input reliably. The text is retrieved fine, but the injection doesn’t work as expected.

Here’s the code I’m using to retrieve and inject the text:

Retrieval Code (getInputText):

function getInputText() {
// Select all spans containing text
const allSpans = document.querySelectorAll("span.selectable-text.copyable-text.false[data-lexical-text='true']");
// Take the last visible span (last written message)
const lastSpan = allSpans[allSpans.length - 1];
if (!lastSpan) {
return null;
}
const text = lastSpan.innerText.trim();
return text || null;
}

Injection Code (setInputText):

function setInputText(text) {
// Select the WhatsApp Web message input field where the text should be injected
const messageBox = document.querySelectorAll("[contenteditable='true']")[1];
if (!messageBox) {
return;
}
// Inject the text into the input field
messageBox.innerHTML = text.replace(/ /gm, ''); // Replace spaces if needed
}

The issue is that while I can correctly retrieve the text from the last message, the injection doesn’t work as expected. I’ve tried modifying the text directly in the innerHTML of the message input element, but the text doesn’t stay injected, probably due to the dynamic nature of the WhatsApp Web interface.

What I’ve tried:

  1. Using innerHTML to inject the text into the message input.
  2. Observing mutations with a MutationObserver to detect and re-inject the text if changes happen in the DOM.
  3. Modifying the content of the elements, but this doesn’t affect the message input.

I’m looking for a way to inject text into the WhatsApp Web input field without sending it — just replacing the old text with the new one.
If anyone has faced this issue or has an idea on how to work around this limitation, I would really appreciate your help!
Thanks in advance!

Swipeable actions misaligned or peeking when adding new items with padding in React Native using ReanimatedSwipeable

I’m using ReanimatedSwipeable from react-native-gesture-handler with React Native and Expo. Each to-do item in my FlatList has internal padding (e.g. px-4) for visual spacing. The issue is: When I add a new item, the swipeable right action buttons (e.g. edit/delete) briefly “peek out” or appear misaligned until I interact with the list again.

I’ve tried:

Wrapping everything in overflow-hidden

Matching the padding in both the row and the renderRightActions view

Explicitly set w-[96px] (or similar) to match the width of two buttons Although this kind of works, I feel like this is a cheap fix and I want to know how to do it the right way.

Here is the code:

import { View, TextInput, FlatList, Pressable } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context';
import React, { useState } from 'react'
import { Plus, Pencil, X } from 'lucide-react-native';
import ReanimatedSwipeable from 'react-native-gesture-handler/ReanimatedSwipeable';

const Home = () => {

    type Todo = {
        _id: string;
        text: string;
        completed: boolean;
      };
  
    const  [todos, setTodos] = useState<Todo[]>([]);

    const handleAddTodo = () => {

        const newTodo = {
            _id: Date.now().toString(),
            text: '',
            completed: false
        }

        setTodos(prev => [...prev, newTodo]);

  }

   const renderRightActions = () => (
     <View className="flex-row">
       <Pressable className="p-1 bg-blue-200 justify-center rounded">
         <Pencil size={20}/>
       </Pressable>
       <Pressable className="p-1 bg-red-200 justify-center rounded">
         <X size={20} />
       </Pressable>
     </View>
   );

   return (
     <SafeAreaView className="flex-1 relative bg-white">
             <FlatList
                 data={todos}  
                 keyExtractor={(item) => item._id}
                 ItemSeparatorComponent={() => <View style={{height: 10}} />}
                 renderItem={({ item }) => (
                     <ReanimatedSwipeable 
                         key={item._id}
                         renderRightActions={renderRightActions}
                     >
                         <View className="flex-row items-center rounded px-4">
                             <Pressable className="w-6 h-6 rounded-full border border-gray-400 mr-3" />
                             <TextInput
                                 className="flex-1 bg-red-300 rounded px-3 py-2"
                                 placeholder="To-do..."
                                 editable={true}
                                 multiline={true}
                                 value={item.text}
                                 onChangeText={(text) => {
                                     setTodos(prevTodos =>
                                     prevTodos.map(todo =>
                                         todo._id === item._id ? { ...todo, text } : todo
                                     )
                                     );
                                 }}
                             />
                         </View>
                     </ReanimatedSwipeable>
                 )}
             />

             <Pressable 
                 className="absolute bottom-6 right-6 w-12 h-12 bg-blue-600 rounded-full items-center justify-center"
                 onPress={handleAddTodo}
             >
                 <Plus size={24} color="white" />
             </Pressable>
         </SafeAreaView>
     )
}

export default Home

Есть ли возможность обойти блокировку google при аутентивикации с помощью puppeteer [closed]

Возникает ошибка на моменте ввода куловодом почты и нажатия кнопки next. Google выдает сообщения что браузер не безопасен

enter image description here

Использовал lambda-chrome, browser Endpoint, применял путь к исполняемому файлу, использовал плагин для проверки на робота ничего не помогло. Не знаю что еще можно использовать

TypeError: this.shouldEnforce is not a function error from bat.bing.com/bat.js on slow connections (3G)

We are encountering a JavaScript error related to the Microsoft Advertising tracking script https://bat.bing.com/bat.js.

Error message:

TypeError: this.shouldEnforce is not a function

Details:

  • The error occurs intermittently when the page is loaded on a slow network (e.g., 3G).
  • It appears to happen across multiple pages and even on some third-party websites that also load bat.js

Environment:

  • Browser: Chrome on macOS
  • Network throttling: 3G simulated using DevTools
  • The error occurs during the loading of bat.js

Has anyone else experienced this issue recently?

We tested the behavior using Chrome DevTools’ network throttling set to “Regular 3G” and observed that the error is reproducible when the script fails to fully load or initialize.
We also tried different browsers (Chrome, Safari) and confirmed that the error appears mostly under slow conditions.

We expected bat.js to load without errors and perform user tracking as intended, but instead it breaks execution with a TypeError, potentially interfering with other scripts on the page.

We have contacted Microsoft Advertising support, but so far, no known issues have been confirmed.

javaScript variable using JSP EL is marked as unused (gray) in IDE , why? [duplicate]

I’m using JSP and trying to pass a server-side value (sessionScope.userNickname) into a JavaScript variable.

Here is the code inside a JSP file:

<script type="text/javascript">
  const userNickname = "${sessionScope.userNickname}" || "상대방";

  const roomInfoElement = document.createElement("div");
  roomInfoElement.className = "join-message";
  roomInfoElement.innerHTML = `<i class="fas fa-info-circle"></i> ${userNickname}님과의 대화방입니다`;
  chatBox.appendChild(roomInfoElement);
</script>

I’m using IntelliJ IDEA, and userNickname is shown in gray, which usually means it’s declared but not used.

However, I am using it in the line:

roomInfoElement.innerHTML = `<i class="fas fa-info-circle"></i> ${userNickname}님과의 대화방입니다`;

If I add console.log(userNickname);, the gray color goes away. But if I remove it, it’s gray again.

I expected that ${sessionScope.userNickname} would be evaluated on the server and the userNickname variable would be recognized as used. However, the IDE marks it as unused (gray), and the warning only goes away when I add a console.log() statement. I’m trying to understand why this happens.