How to add movement restriction with transform translate?

I am making an editor on React. Canvas elements are generated using html. I added a function for moving around the canvas using transform translate. Now I can’t figure out how to add a limitation if the user has scrolled to the canvas border, now he can scroll endlessly.

The size of the screen in which the canvas is located can be different depending on the screen size. The size of the canvas itself is always 1920 by 1080 (almost always larger than the parent div).

Here is the code for moving and my attempts to add a limitation + jsx markup:

// drag
const [space, setSpace] = useState(false);
const [origin, setOrigin] = useState({ x: 0, y: 0 });
const [translate, setTranslate] = useState({ x: 0, y: 0 });

useEffect(() => {
  const scrollDown = (event: KeyboardEvent): void => {
    if (event.code === 'Space') {
      setSpace(true);
    }
  };

  const scrollUp = (event: KeyboardEvent): void => {
    if (event.code === 'Space') {
      setSpace(false);
    }
  };
  window.addEventListener('keydown', scrollDown);
  window.addEventListener('keyup',   scrollUp);
  return () => {
    window.removeEventListener('keydown', scrollDown);
    window.removeEventListener('keyup',   scrollUp);
  };
}, []);

const clampTranslate = 
  ( x: number, y: number ): 
  { x: number; y: number } | false => {
  const wrapper = scrollWrapperRef.current;
  const canvasWrapper = canvas.current;
  if (!wrapper && !canvasWrapper) return { x, y };

  const rect = wrapper.getBoundingClientRect();
  const canvasRect = canvasWrapper.getBoundingClientRect();

  const rectMaxX = rect.left + 50; // left
  const rectMinX = rect.right + 50; // right
  const rectMaxY = rect.top + 50; // top
  const rectMinY = rect.bottom + 50; // bottom

  console.log(rectMaxX, rectMinX, rectMaxY, rectMinY, x, y, canvasRect);

  if (canvasRect.right < rectMinX) {
    console.log('You have gone beyond the right edge');
  }

  if (canvasRect.left > rectMaxX) {
    console.log('You have gone beyond the left edge');
  }

  if (canvasRect.top > rectMaxY) {
    console.log('You have gone beyond the top edge.');
  }

  if (canvasRect.bottom < rectMinY) {
    console.log('You have gone beyond the bottom edge');
  }

  console.log(maxX, minX, maxY, minY);
  
  return {
    x: x,
    y: y,
  };
};

// trackpad
const handleWheel = (event: React.WheelEvent): void => {
  setIsDragging(true);

  setTranslate((prev) => {
    const next = { x: prev.x - event.deltaX, y: prev.y - event.deltaY };
    return clampTranslate(next.x, next.y);
  });
};

const handleMouseDown = (event: React.MouseEvent): void => {
  if (!space) return;
  setIsDragging(true);
  setOrigin({ x: event.clientX - translate.x, y: event.clientY - translate.y });

  event.preventDefault();
};

const handleMouseMove = (event: React.MouseEvent): void => {
  if (!space) return;
  if (!isDragging) return;
  const newX = event.clientX - origin.x;
  const newY = event.clientY - origin.y;
  
  setTranslate(clampTranslate(newX, newY));
};

const handleMouseUp = (): void => {
  setIsDragging(false);
};

<StyledEditorPageContent>
  <StyledEditorWrapper
    ref={scrollWrapperRef}
    onWheel={handleWheel}
    onMouseDown={handleMouseDown}
    onMouseMove={handleMouseMove}
    onMouseUp={handleMouseUp}
    onMouseLeave={handleMouseUp}
  >
    <StyledEditorCanvasWrapper
      key={artBoard?.id}
      id={canvasId}
      style={{
        transform: `translate(${translate.x}px, ${translate.y}px)`,
      }}
    >
      <StyledEditorCanvas
        ref={canvas}
        id={"canvas-content"}
        isHorizontal={currentOrientationCanvas === orientationsIds.horizontal}
        cursor={getCursorCanvas()}
        onClick={handleCanvasClick}
      >
        {(draft || [])?.map((item, index) => {
          return (
            <EditorLayer
              key={`${item.id}-${index}`}
              {...item}
              onClick={(): void => {
                handleLayerClick(item.id);
              }}
              index={index}
              disableDragging={isDragging}
            />
          );
        })}
      </StyledEditorCanvas>
    </StyledEditorCanvasWrapper>
  </StyledEditorWrapper>
</StyledEditorPageContent>;

In the clampTranslate function I can use the coordinates of the parent div and canvas to find out if the user has crossed the border, but I can’t figure out how to restrict the movement. If I add return false, the movement will be blocked.

NPM package – difference in running npx command vs npm command

I have bootstrapped a NPM package using npm create vite@latest and am having trouble with getting it to generate the index.d.ts file.

In my package.json I have my build script as vue-tsc -p tsconfig.build.json && vite build. Running this gives:

$ npm run build

> [email protected] build
> npx vue-tsc -p tsconfig.build.json && vite build

vite v7.0.3 building for production...
✓ 5 modules transformed.
dist/npm-package.css  0.04 kB │ gzip: 0.06 kB
dist/index.es.js      1.64 kB │ gzip: 0.81 kB │ map: 1.78 kB
dist/npm-package.css  0.04 kB │ gzip: 0.06 kB
dist/index.umd.js     1.69 kB │ gzip: 0.84 kB │ map: 1.72 kB
✓ built in 205ms

$ ls dist/
index.es.js  index.es.js.map  index.umd.js  index.umd.js.map  npm-package.css  vite.svg
$ npx vue-tsc -p tsconfig.build.json ; ls dist/
App.vue.d.ts  components/  index.d.ts  index.es.js  index.es.js.map  index.umd.js  index.umd.js.map  main.d.ts  npm-package.css  vite.svg

Placeholder inside doesnt show when i reload the page, but shows every other time

I’m new to web development and I am learning backend development of SPA using vanilla js html and css. My <textarea> in html has a placeholder that says “Let’s begin writing”. I use app.js for frontend and server.js for the main backend, and notes.js as router. When I reload the page or I run the server for the first time, when I click the create button, the textarea placeholder is empty. (Although the text placeholder is showing every time). When I click back and re-click on create button, the textarea placeholder is active. I can’t seem to figure out why this happens or how to fix it

Here is my index.html file’s textarea placeholder is

<input type="text" placeholder="What's this note about?" id="title"
            class="w-full font-bold focus:outline-none text-3xl mt-4 mb-4 text-center font-mono">

The full file:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    <title>Minimalist Note Taker</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link
        href="https://fonts.googleapis.com/css2?family=Inconsolata:[email protected]&family=Josefin+Sans:ital,wght@0,100..700;1,100..700&family=Martel+Sans:wght@200;300;400;600;700;800;900&display=swap"
        rel="stylesheet">
    <style>
        .font-inter {
            font-family: 'Josefin sans', sans-serif;
        }

        textarea {
            scrollbar-width: thin;
            scrollbar-color: rgba(156, 163, 175, 0.3) transparent;
        }

        textarea::-webkit-scrollbar {
            width: 6px;
        }

        textarea::-webkit-scrollbar-thumb {
            background-color: rgba(156, 163, 175, 0.3);
            /* Tailwind's gray-400 */
            border-radius: 6px;
        }

        textarea::-webkit-scrollbar-track {
            background: transparent;
        }
    </style>
</head>

<body class="bg-black hidden">
    <main id="home" class="h-screen flex flex-col justify-center items-center space-y-10">
        <h1 class="text-white text-3xl font-inter">Welcome! Ready to start noting today?</h1>
        <div class="flex items-center">
            <button id="createBtn"
                class="p-3 flex flex-col items-center justify-center w-20 rounded-md hover:scale-150 group transition-all ease-in-out duration-300">
                <img src="./assets/addnote.svg" alt="New" class="h-10">
                <span
                    class="text-[0.6rem] mt-2 text-white font-inter invisible opacity-0 group-hover:opacity-100 group-hover:visible delay-200 duration-300">NEW</span>
            </button>
            <button id="viewBtn"
                class="p-3 flex flex-col items-center justify-center w-20 rounded-md hover:scale-150 group transition-all ease-in-out duration-300">
                <img src="./assets/seenotes.svg" alt="View" class="h-10">
                <span
                    class="text-[0.6rem] mt-2 text-white font-inter invisible opacity-0 group-hover:opacity-100 group-hover:visible delay-200 duration-300">VIEW</span>
            </button>
        </div>
    </main>
    <section id="create"
        class="hidden opacity-0 scale-50 duration-150 transition-all ease-in-out text-white max-w-2xl h-[80vh] mx-auto mt-20 p-8 border border-gray-700 rounded-2xl shadow-[0_0_40px_15px_rgba(156,163,175,0.3)] flex flex-col">
        <input type="text" placeholder="What's this note about?" id="title"
            class="w-full font-bold focus:outline-none text-3xl mt-4 mb-4 text-center font-mono">
        <div class="mx-auto w-[80%] h-[1px] bg-gray-400"></div>
        <textarea name="textarea" id="textSpace" placeholder="Let's begin writing!"
            class="h-full m-8 focus:outline-none text-xl resize-none font-mono">
        </textarea>

        <div id="btnContainer" class="flex space-x-8 justify-center">
            <button id="backBtn"
                class="w-20 hover:scale-110 py-2 rounded-md text-white border-2 border-white/20 hover:border-white/60 transition ease-in-out duration-300 font-mono">BACK</button>
            <button id="saveBtn"
                class="w-20 hover:scale-110 py-2 rounded-md text-white border-2 border-white/20 hover:border-white/60 transition ease-in-out duration-300 font-mono">SAVE</button>
        </div>
    </section>

    <script src="app.js"></script>
</body>

</html>

app.js

const main = document.getElementById('home');
const create = document.getElementById('create');
// const view = document.getElementById('view');

const createBtn = document.getElementById('createBtn');
const viewBtn = document.getElementById('viewBtn');

const saveBtn = document.getElementById('saveBtn');
const backBtn = document.getElementById('backBtn');

function goHome(){
    main.classList.remove('hidden');
    create.classList.add('hidden');
}

function createPage() {
    main.classList.add('hidden');
    create.classList.remove('hidden');
    
    requestAnimationFrame(() => {
        create.classList.remove('opacity-0', 'scale-50');
        create.classList.add('opacity-100', 'scale-100');
    })
}

//route handler
function handleRoute(path){
    if(path === '/create') createPage();
    else goHome();
}

createBtn.addEventListener("click", () => {
    history.pushState({ page: 'create' }, '', '/create');
    handleRoute('/create');
})

saveBtn.addEventListener('click',async () =>  {
    const title = document.getElementById('title').value;
    const noteBody = document.getElementById('textSpace').value;
    
    const response = await fetch('/api/notes', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title, noteBody})
    })

    const result = await response.text();
    console.log(result);
})

backBtn.addEventListener("click", () => {
    create.classList.remove('opacity-100', 'scale-100');
    create.classList.add('opacity-0', 'scale-50');

    setTimeout(() => {
        history.back();
        
        document.querySelector('#create input').value = '';
        document.querySelector('#create textarea').value = '';
    }, 150);
})

//controlling browser buttons as we add to history stack using pushstate
window.addEventListener('popstate', () => handleRoute(window.location.pathname));

//page load for manual traversal or reload
//why? app js is loaded from top down everytime when these scenarios happen
//so browser should navigate to that place before user can see the dom
handleRoute(window.location.pathname);

//show the DOM only after setting up DOM (JS reads from top to bottom, 
//sets everything above this, and then onnly unhides body)
document.body.classList.remove("hidden");

server.js

const express = require('express');
const path = require('path');
const app = express();
app.use(express.json()); //makes express talented to understand the json requests sent to it

app.use(express.static(path.join(__dirname, 'public'))); //serves all static files from the public directory

const notesRouter = require('./routes/notes');
app.use('/api/notes', notesRouter);

app.get('/{*splat}', (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'index.html'));
})

app.listen(3000, console.log("listening"));

notes.js

const express = require('express');
const fs = require('fs');
const path = require('path');
const router = express.Router();
const notesPath = path.join(__dirname, '../data.js');

function saveNotes(newNote){
    const notes = fs.readFileSync(notesPath, 'utf-8');
    const notesArray = JSON.parse(notes);
    notesArray.push(newNote);
    fs.writeFileSync(notesPath, JSON.stringify(notesArray, '', 2));
}

router.post('/', (req, res) => {
    const id = Date.now();
    const title = req.body.title.trim();
    const noteBody = req.body.noteBody.trim();
    saveNotes({ id, title, noteBody });
    res.status(200).send('Note received');
});

module.exports = router;

The app is incomplete as i’m proceeding with the other features now
the File structure is given below

enter image description here

I tried to ask AI this issue and chatgpt said its the browser optimising itself as it considers textarea to be irrelevant during DOM loading. It then added another requestAnimationFrame inside the already active one.. yet that too didnt work.

How to load darkmode.js file dynamically?

I have a toggle button inside src/app/user-list/user-list.html, namely:

  <div class="btn-group">
    <button class="btn btn-secondary btn-sm"
            type="button"
            data-bs-theme-value="dark"
            aria-pressed="false">
      Dark
    </button>
    <button class="btn btn-light btn-sm"
            type="button"
            data-bs-theme-value="light"
            aria-pressed="false">
      Light
    </button>
  </div>

Loading it like this in src/index.html works:

<!doctype html>
<html lang="en">
  <head>...</head>
  <body>
    <app-root></app-root>
    <script src="assets/js/darkmodetoggle.js"></script>
  </body>
</html>

However, I would like to load it like this in src/app/user-list/user-list.html:

export class UserList implements OnInit {
  constructor(private renderer: Renderer2) {
  }

  ngOnInit(): void {
    this.loadScript();
  }

  loadScript() {
    if (document.getElementById('darkmode-toggle-script')) {
      console.log('Script already loaded');
      return;
    }

    const script = this.renderer.createElement('script');
    script.id = 'darkmode-toggle-script';
    script.src = 'assets/js/darkmodetoggle.js';
    script.type = 'text/javascript';
    script.onload = () => console.log('Dark Mode Script loaded dynamically');
    script.onerror = () => console.error('Error loading Dark Mode Script');

    this.renderer.appendChild(document.body, script);
  }
}

It appears inside the html in the form:

<script _ngcontent-ng-c1923262244="" id="darkmode-toggle-script" src="assets/js/darkmodetoggle.js" type="text/javascript"></script>

But the button doesn’t toggle anymore. Any idea why?

Connect to a SQLite database from a JavaScript function [closed]

I have been trying to make a connection with a database named superheroes.db in SQLite format. I need to use a custom JavaScript function to do it (I’m working on a environment named Flowise), Though for now I can’t get it to work even if it compiles.

const sqlite3 = require('sqlite3').verbose();
const path = require('path');

async function getSuperheroesSchema() {
  const dbPath = path.resolve(__dirname, 'superheroes.db');
  const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READONLY);

  const tableName = 'superheroes';

  function getColumns() {
    return new Promise((resolve, reject) => {
      db.all(`PRAGMA table_info(${tableName});`, (err, rows) => {
        if (err) return reject(err);
        const columns = rows.map(row => {
          const notNull = row.notnull ? 'NOT NULL' : '';
          return `${row.name} ${row.type.toUpperCase()} ${notNull}`;
        });
        const columnNames = rows.map(r => r.name);
        resolve({ columns, columnNames });
      });
    });
  }

  function getSampleData(columnNames) {
    return new Promise((resolve, reject) => {
      db.all(`SELECT * FROM ${tableName} LIMIT 3;`, (err, rows) => {
        if (err) return resolve(['[ERROR FETCHING ROWS]']);
        const lines = rows.map(row =>
          columnNames.map(col => row[col]).join(' ')
        );
        resolve(lines);
      });
    });
  }

  try {
    const { columns, columnNames } = await getColumns();
    const sampleRows = await getSampleData(columnNames);

    const createStatement = `CREATE TABLE ${tableName} (${columns.join(', ')})`;
    const selectStatement = `SELECT * FROM ${tableName} LIMIT 3`;

    let output = '';
    output += `${createStatement}n`;
    output += `${selectStatement}n`;
    output += `${columnNames.join(' ')}n`;
    output += `${sampleRows.join('n')}n`;

    return output;
  } catch (err) {
    return `[ERROR] ${err.message}`;
  }
}
return await getSuperheroesSchema();


This is what I have for now. I don’t know if its me or that flowise doesn’t allow anyone to use imports for sqlite3. It should be able to establish a connection and give an agent the information about the database.

Need help connecting to a SQLite database from a JavaScript function

I have been trying for the last couple of days to make a connection with a data base named superheroes.db in SQLite format. I need to use a custom JavaScript function to do it (I’m working on a enviorment named Flowise), tho for now I cant get to make it work even if it compiles.

const sqlite3 = require('sqlite3').verbose();
const path = require('path');

async function getSuperheroesSchema() {
  const dbPath = path.resolve(__dirname, 'superheroes.db');
  const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READONLY);

  const tableName = 'superheroes';

  function getColumns() {
    return new Promise((resolve, reject) => {
      db.all(`PRAGMA table_info(${tableName});`, (err, rows) => {
        if (err) return reject(err);
        const columns = rows.map(row => {
          const notNull = row.notnull ? 'NOT NULL' : '';
          return `${row.name} ${row.type.toUpperCase()} ${notNull}`;
        });
        const columnNames = rows.map(r => r.name);
        resolve({ columns, columnNames });
      });
    });
  }

  function getSampleData(columnNames) {
    return new Promise((resolve, reject) => {
      db.all(`SELECT * FROM ${tableName} LIMIT 3;`, (err, rows) => {
        if (err) return resolve(['[ERROR FETCHING ROWS]']);
        const lines = rows.map(row =>
          columnNames.map(col => row[col]).join(' ')
        );
        resolve(lines);
      });
    });
  }

  try {
    const { columns, columnNames } = await getColumns();
    const sampleRows = await getSampleData(columnNames);

    const createStatement = `CREATE TABLE ${tableName} (${columns.join(', ')})`;
    const selectStatement = `SELECT * FROM ${tableName} LIMIT 3`;

    let output = '';
    output += `${createStatement}n`;
    output += `${selectStatement}n`;
    output += `${columnNames.join(' ')}n`;
    output += `${sampleRows.join('n')}n`;

    return output;
  } catch (err) {
    return `[ERROR] ${err.message}`;
  }
}
return await getSuperheroesSchema();


This is what I have for now. I dont know if its me or that flowise dont allow anyone to use imports for sqlite3. It should be able to establish a connection and give an agent the information about the database.

Why does submitting a form in React 19 reset checkbox inputs but not text inputs?

It appears that when a callback is supplied to a form’s action prop and the form is submitted, checkbox inputs get reset while text inputs do not.

Consider the following example:

import React, { useState } from 'react';
import { createRoot } from 'react-dom/client'

function App() {
  const [value, setValue] = useState('')
  const [checked, setChecked] = useState(false)
  
  return <form action={() => {}}>
    <input
      type="text"
      value={value}
      onChange={({ target }) => setValue(target.value)}
    />
    <input
      type="checkbox"
      checked={checked}
      onChange={({ target }) => setChecked(target.checked)}
    />
    <button>Submit</button>
  </form>
}

createRoot(document.getElementById('root')).render(<App />)

You can see a live example here.

To replicate the issue, perform the following steps:

  1. Add some text to the text input
  2. Check the checkbox
  3. Click “Submit”

Once you submit the form, the text input will have retained its value while the checkbox input will have been unchecked.

What’s going on here?

Datatables Plugin Not Working with no error or hint

I have already installed DataTables on my web app , i have configured its JS dan CSS as below :

here is the head JS include

<!--   Core JS Files   -->
<script src="<?= base_url('assets/js/core/jquery-3.7.1.min.js') ?>"></script>

<!-- Custom Plugins Sweetalert, Cookies, Etc -->
<script src="<?= base_url('assets/js/plugins.js') ?>" type="text/javascript"></script>
<script src="<?= base_url('assets/js/core/bootstrap.bundle.min.js') ?>"></script>
<script src="<?= base_url('assets/js/core/popper.min.js') ?>"></script>
<script src="<?= base_url('assets/js/core/bootstrap-material-design.min.js') ?>"></script>

<!-- DataTables JavaScript -->
<script src="<?= base_url('assets/js/core/datatables.min.js') ?>"></script>
<script src="<?= base_url('assets/js/core/dataTables.bootstrap5.js') ?>"></script>

<script src="<?= base_url('assets/js/plugins/perfect-scrollbar.jquery.min.js') ?>"></script>
<!--  Plugin for the Sliders, full documentation here: http://refreshless.com/nouislider/ -->
<script src="<?= base_url('assets/js/plugins/nouislider.min.js') ?>"></script>
<!-- Control Center for Material Dashboard: parallax effects, scripts for the example pages etc -->
<script src="<?= base_url('assets/js/material-dashboard.js') ?>" type="text/javascript"></script>
<!-- Custom JS App -->
<script src="<?= base_url('assets/js/plugins/file-uploader/js/jquery.dm-uploader.min.js'); ?>"></script>
<script src="<?= base_url('assets/js/plugins/file-uploader/js/ui.js'); ?>"></script>

<script src="<?= base_url('assets/js/custom.js') ?>" type="text/javascript"></script>

the CSS file

<!-- CSS Files -->
<link href="<?= base_url('assets/css/dataTables.bootstrap5.css'); ?>" rel="stylesheet" />
<link href="<?= base_url('assets/css/bootstrap.min.css'); ?>" rel="stylesheet" />
<link href="<?= base_url('assets/fonts/fonts.css?v=1.0.0'); ?>" rel="stylesheet" />
<link href="<?= base_url('assets/css/material-dashboard.css'); ?>" rel="stylesheet" />
<link href="<?= base_url('assets/css/style.css?v=1.0.0'); ?>" rel="stylesheet" />
<link rel="stylesheet" href="<?= base_url('assets/js/plugins/file-uploader/css/jquery.dm-uploader.min.css'); ?>" />
<link rel="stylesheet" href="<?= base_url('assets/js/plugins/file-uploader/css/styles-1.0.css'); ?>" />

<link rel="apple-touch-icon" sizes="76x76" href="<?= base_url('assets/img/apple-icon.png'); ?>">
<link rel="icon" type="image/png" href="<?= base_url('assets/img/favicon.png'); ?>">

the script on the head :

<script>
     $(document).ready(function() {
         $('#example').DataTable({
            responsive: true
        });
    });
</script>

the Data Table Section with id “example” :

<div class="card-body">
   <?php if (!$empty) : ?>
      <table class="table table-striped" id="example">
         <thead class="text-primary">
            <th width="20"><input type="checkbox" class="checkbox-table" id="checkAll"></th>
            <th><b>No</b></th>
            <th><b>#</b></th>
            <th><b>NIS</b></th>
            <th><b>Nama Siswa</b></th>
            <th><b>Jenis Kelamin</b></th>
            <th><b>Kelas</b></th>
            <th><b>Jurusan</b></th>
            <th><b>No HP</b></th>
            <th width="1%"><b>Aksi</b></th>
         </thead>
         <tbody>
            <?php $i = 1;
            
            foreach ($data as $value) : 
            
            $photo = $value['photo'];
            if($photo == NULL || $photo == '' || empty($photo)){
                $photo = "profil.png";
            }
            
            ?>
               <tr>
                  <td><input type="checkbox" name="checkbox-table" class="checkbox-table" value="<?= $value['id_siswa']; ?>"></td>
                  <td><?= $i; ?></td>
                  <td><img src="<?= base_url('uploads/photo/'.$photo) ?>" width="50px" height="50px"></td>
                  <td><?= $value['nis']; ?></td>
                  <td><b><?= $value['nama_siswa']; ?></b></td>
                  <td><?= $value['jenis_kelamin']; ?></td>
                  <td><?= $value['kelas']; ?></td>
                  <td><?= $value['jurusan']; ?></td>
                  <td><?= $value['no_hp']; ?></td>
                  <td>
                     <div class="d-flex justify-content-center">
                        <a title="Edit" href="<?= base_url('admin/siswa/edit/' . $value['id_siswa']); ?>" class="btn btn-primary p-2" id="<?= $value['nis']; ?>">
                           <i class="material-icons">edit</i>
                        </a>
                        <form action="<?= base_url('admin/siswa/delete/' . $value['id_siswa']); ?>" method="post" class="d-inline">
                           <?= csrf_field(); ?>
                           <input type="hidden" name="_method" value="DELETE">
                           <button title="Delete" onclick="return confirm('Konfirmasi untuk menghapus data');" type="submit" class="btn btn-danger p-2" id="<?= $value['nis']; ?>">
                              <i class="material-icons">delete_forever</i>
                           </button>
                        </form>
                        <a title="Download QR Code" href="<?= base_url('admin/qr/siswa/' . $value['id_siswa'] . '/download'); ?>" class="btn btn-success p-2">
                           <i class="material-icons">qr_code</i>
                        </a>
                     </div>
                  </td>
               </tr>
            <?php $i++;
            endforeach; ?>
         </tbody>
      </table>
   <?php else : ?>
      <div class="row">
         <div class="col">
            <h4 class="text-center text-danger">Data tidak ditemukan</h4>
         </div>
      </div>
   <?php endif; ?>
</div>

the html view still not work like this :

enter image description here

can somebody tell me what am i doing wrong ?

‘class name is already in use’ using Vich Uploader

I’m following VichUploader instructions to add a file upload to my form for the Item entity.
Now, if I go to any page of the site I get a raw error (without Symfony profiler and not pretty printed) about two entity names already in use :

Fatal error: Cannot declare class AppEntityItemCategory, because the name is already in use in /Users/corentoulf/DEV/boite-a-partage/src/Entity/ItemCategory.php on line 11.   
Fatal error: Cannot declare class AppEntityItemType, because the name is already in use in /Users/corentoulf/DEV/boite-a-partage/src/Entity/ItemType.php on line 11

If I go to the page where the concerned form is, I get a raw error + pretty Symofny error about only the ItemType entity:

Fatal error: Cannot declare class AppEntityItemType, because the name is already in use in /Users/corentoulf/DEV/boite-a-partage/src/Entity/ItemType.php on line 11

What am I missing in VichUploader configuration that causes such errors ?

Configuration
Vich version : 2.7.0
Symfony version : 7.3.1
PHP version : 8.3.6

Vich config file

vich_uploader:
    db_driver: orm

metadata:
    type: attribute
    auto_detection: true

mappings:
    items:
        uri_prefix: /images/items
        upload_destination: '%kernel.project_dir%/public/images/items'
        namer: VichUploaderBundleNamingSmartUniqueNamer

Item Entity

namespace AppEntity;

use AppRepositoryItemRepository;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;

use SymfonyComponentHttpFoundationFileFile;
use VichUploaderBundleMappingAnnotation as Vich;

#[ORMEntity(repositoryClass: ItemRepository::class)]
#[VichUploadable]
class Item
{
    #[ORMId]
    #[ORMGeneratedValue]
    #[ORMColumn]
    private ?int $id = null;

    #[ORMManyToOne(inversedBy: 'items')]
    #[ORMJoinColumn(nullable: false)]
    private ?User $owner = null;

    #[ORMColumn]
    private ?DateTimeImmutable $created_at = null;

    /**
     * @var Collection<int, ItemCircle>
     */
    #[ORMOneToMany(targetEntity: ItemCircle::class, mappedBy: 'item', cascade: ['persist'], orphanRemoval: true)]
    private Collection $itemCircles;

    #[ORMManyToOne(inversedBy: 'items')]
    private ?itemType $itemType = null;

    #[ORMColumn(length: 255, nullable: true)]
    private ?string $property_1 = null;

    #[ORMColumn(length: 255, nullable: true)]
    private ?string $property_2 = null;

    #[ORMColumn(length: 255, nullable: true)]
    private ?string $property_3 = null;

    #[ORMColumn(length: 255, nullable: true)]
    private ?string $property_4 = null;

    #[ORMColumn(length: 255, nullable: true)]
    private ?string $property_5 = null;

    // NOTE: This is not a mapped field of entity metadata, just a simple property.
    #[VichUploadableField(mapping: 'items', fileNameProperty: 'imageName', size: 'imageSize', mimeType: "imageMimeType")]
    private ?File $imageFile = null;

    #[ORMColumn(nullable: true)]
    private ?string $imageName = null;

    #[ORMColumn(nullable: true)]
    private ?int $imageSize = null;

    #[ORMColumn(nullable: true)]
    private ?int $imageMimeType = null;

    #[ORMColumn(nullable: true)]
    private ?DateTimeImmutable $updated_at = null;

    /**
     * If manually uploading a file (i.e. not using Symfony Form) ensure an instance
     * of 'UploadedFile' is injected into this setter to trigger the update. If this
     * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
     * must be able to accept an instance of 'File' as the bundle will inject one here
     * during Doctrine hydration.
     *
     * @param File|SymfonyComponentHttpFoundationFileUploadedFile|null $imageFile
     */
    public function setImageFile(?File $imageFile = null): void
    {
        $this->imageFile = $imageFile;

        if (null !== $imageFile) {
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updated_at = new DateTimeImmutable();
        }
    }

    public function getImageFile(): ?File
    {
        return $this->imageFile;
    }

    public function setImageName(?string $imageName): void
    {
        $this->imageName = $imageName;
    }

    public function getImageMimeType(): ?string
    {
        return $this->imageMimeType;
    }

    public function setImageMimeType(?string $imageMimeType): void
    {
        $this->imageMimeType = $imageMimeType;
    }

    public function getImageName(): ?string
    {
        return $this->imageName;
    }

    public function setImageSize(?int $imageSize): void
    {
        $this->imageSize = $imageSize;
    }

    public function getImageSize(): ?int
    {
        return $this->imageSize;
    }

    public function __construct()
    {
        $this->itemCircles = new ArrayCollection();
    }

    public function __toString()
    {
        return $this->property_1;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getOwner(): ?User
    {
        return $this->owner;
    }

    public function setOwner(?User $owner): static
    {
        $this->owner = $owner;

        return $this;
    }

    public function getCreatedAt(): ?DateTimeImmutable
    {
        return $this->created_at;
    }

    public function setCreatedAt(DateTimeImmutable $created_at): static
    {
        $this->created_at = $created_at;

        return $this;
    }

    /**
     * @return Collection<int, ItemCircle>
     */
    public function getItemCircles(): Collection
    {
        return $this->itemCircles;
    }

    public function addItemCircle(ItemCircle $itemCircle): static
    {
        if (!$this->itemCircles->contains($itemCircle)) {
            $this->itemCircles->add($itemCircle);
            $itemCircle->setItem($this);
        }

        return $this;
    }

    public function removeItemCircle(ItemCircle $itemCircle): static
    {
        if ($this->itemCircles->removeElement($itemCircle)) {
            // set the owning side to null (unless already changed)
            if ($itemCircle->getItem() === $this) {
                $itemCircle->setItem(null);
            }
        }

        return $this;
    }

    public function getItemType(): ?itemType
    {
        return $this->itemType;
    }

    public function setItemType(?itemType $itemType): static
    {
        $this->itemType = $itemType;

        return $this;
    }

    public function getProperty1(): ?string
    {
        return $this->property_1;
    }

    public function setProperty1(?string $property_1): static
    {
        $this->property_1 = $property_1;

        return $this;
    }

    public function getProperty2(): ?string
    {
        return $this->property_2;
    }

    public function setProperty2(?string $property_2): static
    {
        $this->property_2 = $property_2;

        return $this;
    }

    public function getProperty3(): ?string
    {
        return $this->property_3;
    }

    public function setProperty3(?string $property_3): static
    {
        $this->property_3 = $property_3;

        return $this;
    }

    public function getProperty4(): ?string
    {
        return $this->property_4;
    }

    public function setProperty4(?string $property_4): static
    {
        $this->property_4 = $property_4;

        return $this;
    }

    public function getProperty5(): ?string
    {
        return $this->property_5;
    }

    public function setProperty5(?string $property_5): static
    {
        $this->property_5 = $property_5;

        return $this;
    }
}

preg_match_all only getting the first match [duplicate]

Here is my pattern:

/^(?:include|require)(?:_once)*[^"']*['"]([^'"]+)['"]/i

I want to find all three of these lines:

include MODX_CORE_PATH . 'test.php';
require_once MODX_CORE_PATH . 'components/dirwalker/model/dirwalker/dirwalker.class.php';
include MODX_CORE_PATH . 'aaaDummy/aaaDummy.txt';

The Rubular regex tester finds all three, but in my code I’m only getting the first one. I’m sure it’s something simple and obvious, but I can’t see it.

How to extend WordPress REST API to include custom meta fields for a custom post type?

I’m working on a custom WordPress project where I’ve registered a custom post type called parcel. It has several custom meta fields like pickup_pincode, drop_pincode, and delivery_type.

I want to expose these custom fields via the WordPress REST API when fetching the parcel posts (e.g., /wp-json/wp/v2/parcel).

I’ve registered the custom post type using register_post_type, and the meta fields using register_post_meta.

Here’s what I’ve tried in functions.php:

function register_parcel_meta_fields() {
    register_post_meta('parcel', 'pickup_pincode', [
        'show_in_rest' => true,
        'type'         => 'string',
        'single'       => true,
    ]);
}
add_action('init', 'register_parcel_meta_fields');

I registered the meta fields using register_post_meta() with 'show_in_rest' => true, expecting them to appear automatically in the REST API response for my custom post type parcel. However, when I fetch the data via /wp-json/wp/v2/parcel, the custom fields like pickup_pincode are missing. I expected them to be visible in the JSON response but they’re not showing up. I’m unsure if I need to do more or hook into a different filter.

How to fix “Search functionality must be placed within a landmark region” WCAG issue with input and icon?

I’m trying to fix a WCAG accessibility issue flagged by tools like axe/lighthouse:

Search functionality must be placed within a landmark region
input.v-input

  • The input is wrapped in a div with role=”search” — so I assume it’s already in a landmark.
  • There’s also an icon next to the input, and I suspected it might be causing the problem.
  • I tried setting both role=”presentation” and aria-hidden=”true” on the and its parent elements — but the issue still persists.

Is there a more semantic or reliable way to mark the search input so that it passes WCAG audits?

Here is a simplified version of my HTML:

<div role="search" class="v-input-with-icon-container trade-in-criteria__filter-input">
  <input
    type="search"
    aria-label="Type here to search for device"
    placeholder="Type here to search for device"
    class="v-input"
  >
  <span class="content v-input__icon" role="none" aria-hidden="true">
    <span>
      <img
        src="https://via.placeholder.com/16"
        alt=""
        role="presentation"
        aria-hidden="true"
      >
    </span>
  </span>
</div>

How can I hide all other images in a gallery without listing them individually?

I’m trying to make an image gallery for a personal website that will create a pop-up window from a thumbnail to a bigger image, and it more or less works, but the only way I’ve found that works requires that I individually list and set the display to none for every image I don’t want visible, and set the display to block for the one that I do.

This is what I’m trying:

function jvjponder(imgs) {
  var expandImg = document.getElementById("jvjponder");
  var imgText = document.getElementById("imgtext");
  expandImg.src.thmb = imgs.src;
  imgText.innerHTML = imgs.alt;
  expandImg.parentElement.style.display = "block";
  // the bit that isn't working 
  if (!document.getElementById('jvjponder')) {
    set.style.display = 'none';
  }
}

This is what works (except there are significantly more lines like this):

document.getElementById('jvjponder').style.display = 'block';
document.getElementById('jhangman').style.display = 'none';

(which takes the place of the ‘if’ statement)

I’m not very familiar with js, so most of this is copied and pasted from w3, except for the last bit. I’m trying to find a simpler/more condensed way to say “if it isn’t this image, set display to none” but what I have isn’t working, and instead all of the images are displayed at once. Can someone who understands javascript please tell me what I should do?

how can i get original file path in web enviroment? [closed]

I have a file upload feature in my web program, and after uploading, I want to delete the original file. However, due to browser restrictions and security reasons, JavaScript cannot send the original file path to the backend. Is there a way to do this? Preferably without using external programs.

I don’t want to separately ask users for the path or anything like that, I want it to work dynamically.

  • In addition, the server and the client at different enviroment.

Why did I think so, Our cell phones ask for the request for permissions and get permission from the app. Of course, it’s different from the web.

I’m just studying, so it’s hard, so please help me a little bit