Why doesn’t the third grid row expand to fit its overflowing content when using `minmax(100px, 1fr)` in CSS Grid?

I’m using CSS Grid to lay out a fixed-height container with 8 rows. Each row is defined using:

grid-template-rows: repeat(auto-fit, minmax(100px, 1fr));

The container has a fixed height of 600px, and there are 8 .box items inside it. One of these items (the third one) contains a very large block of text, which clearly overflows its grid cell.

```css
.container {
  height: 600px;
  width: 500px;
  display: grid;
  grid-auto-flow: row;
  grid-template-rows: repeat(auto-fit, minmax(100px, 1fr));
}

.box {
  color: white;
  font-size: 1.5rem;
  text-align: center;
}
```
  <body>
<div class="container">
  <div class="box" style="background-color: #e53935">FIRST</div>
  <div class="box" style="background-color: #d81b60">SECOND</div>
  <div class="box" style="background-color: #8e24aa">
    Lorem ipsum, dolor sit amet consectetur adipisicing elit. Minus sed
    tempore saepe in voluptatem asperiores velit animi iure mollitia itaque
    atque distinctio blanditiis accusamus officiis, dolor iusto quis. Nemo,
    optio! Nemo quos provident, odit hic maiores obcaecati ut debitis
    placeat, sapiente tenetur perspiciatis praesentium in! Vero quos
    inventore illum perferendis odio quo eligendi consequatur beatae, libero
    repellat eaque esse. Error. Vero deleniti repellendus enim itaque
    sapiente dolor, esse eos dolorum nisi laudantium incidunt eligendi
    asperiores delectus laboriosam obcaecati ut. Atque natus non alias quae
    nesciunt magnam veniam ad culpa necessitatibus. Ea tenetur assumenda
    aspernatur rem consectetur quo pariatur amet quibusdam? Perferendis
    nobis ea odio laborum atque vel consectetur. Illo odit inventore quis
    eum quaerat! Optio totam velit autem nulla et. Possimus facilis quos
    voluptates hic. Accusamus reprehenderit nihil aliquid? Nisi ducimus
    minima eveniet quos rerum dicta, illo obcaecati excepturi nesciunt,
    voluptatibus non modi facere saepe minus necessitatibus, cum autem
    blanditiis?
  </div>
  <div class="box" style="background-color: #5e35b1">FOURTH</div>
  <div class="box" style="background-color: #3949ab">FIFTH</div>
  <div class="box" style="background-color: #1e88e5">SIXTH</div>
  <div class="box" style="background-color: #00acc1">SEVENTH</div>
  <div class="box" style="background-color: #00897b">EIGHTH</div>
</div>
  </body>

Question:

I expected the third row to expand vertically to fit its overflowing content. But instead, it stays fixed at 100px and overflows visually.

I am trying to understand the underlying concept here about how CSS Grid works.

Messages snapshot error: FirebaseError: Missing or insufficient permissions. Request when trying to make a messaging system for my website

Here’s the full console:

logindex.js:81  Messages snapshot error: FirebaseError: Missing or insufficient permissions.
eval @ index.js:81
eval @ index.esm2017.js:17548
setTimeout
pu @ index.esm2017.js:17547
error @ index.esm2017.js:17541
onError @ index.esm2017.js:15942
__PRIVATE_eventManagerOnWatchError @ index.esm2017.js:15889
__PRIVATE_removeAndCleanupTarget @ index.esm2017.js:16847
eval @ index.esm2017.js:16757
Promise.then
__PRIVATE_syncEngineRejectListen @ index.esm2017.js:16757
__PRIVATE_handleTargetError @ index.esm2017.js:15212
__PRIVATE_onWatchStreamChange @ index.esm2017.js:15221
onNext @ index.esm2017.js:14770
eval @ index.esm2017.js:14713
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:18943
eval @ index.esm2017.js:18976
Promise.then
Yu @ index.esm2017.js:18976
enqueue @ index.esm2017.js:18943
enqueueAndForget @ index.esm2017.js:18921
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:14713
i_ @ index.esm2017.js:14135
eval @ index.esm2017.js:14326
eval @ index.esm2017.js:14275
ab @ webchannel_blob_es2018.js:39
F @ webchannel_blob_es2018.js:37
Z.ta @ webchannel_blob_es2018.js:98
Rb @ webchannel_blob_es2018.js:53
M.Y @ webchannel_blob_es2018.js:47
M.ca @ webchannel_blob_es2018.js:44
ab @ webchannel_blob_es2018.js:39
F @ webchannel_blob_es2018.js:37
Wc @ webchannel_blob_es2018.js:76
h.bb @ webchannel_blob_es2018.js:75
h.Ea @ webchannel_blob_es2018.js:75
Lc @ webchannel_blob_es2018.js:71
h.Pa @ webchannel_blob_es2018.js:69
Promise.then
Nc @ webchannel_blob_es2018.js:69
h.Pa @ webchannel_blob_es2018.js:69
Promise.then
Nc @ webchannel_blob_es2018.js:69
h.Sa @ webchannel_blob_es2018.js:69
Promise.then
h.send @ webchannel_blob_es2018.js:66
h.ea @ webchannel_blob_es2018.js:74
Jb @ webchannel_blob_es2018.js:44
fd @ webchannel_blob_es2018.js:90
h.Fa @ webchannel_blob_es2018.js:89
Da @ webchannel_blob_es2018.js:28
Promise.then
x @ webchannel_blob_es2018.js:28
ec @ webchannel_blob_es2018.js:88
Rb @ webchannel_blob_es2018.js:53
M.Y @ webchannel_blob_es2018.js:47
M.ca @ webchannel_blob_es2018.js:44
ab @ webchannel_blob_es2018.js:39
F @ webchannel_blob_es2018.js:37
Wc @ webchannel_blob_es2018.js:76
h.bb @ webchannel_blob_es2018.js:75
h.Ea @ webchannel_blob_es2018.js:75
Lc @ webchannel_blob_es2018.js:71
h.Pa @ webchannel_blob_es2018.js:69
Promise.then
Nc @ webchannel_blob_es2018.js:69
h.Sa @ webchannel_blob_es2018.js:69
Promise.then
h.send @ webchannel_blob_es2018.js:66
h.ea @ webchannel_blob_es2018.js:74
Jb @ webchannel_blob_es2018.js:43
Hb @ webchannel_blob_es2018.js:42
h.Ga @ webchannel_blob_es2018.js:86
Da @ webchannel_blob_es2018.js:28
Promise.then
x @ webchannel_blob_es2018.js:28
fc @ webchannel_blob_es2018.js:84
h.connect @ webchannel_blob_es2018.js:82
Y.m @ webchannel_blob_es2018.js:96
Go @ index.esm2017.js:14266
send @ index.esm2017.js:14123
F_ @ index.esm2017.js:14626
U_ @ index.esm2017.js:14801
__PRIVATE_sendWatchRequest @ index.esm2017.js:15145
eval @ index.esm2017.js:15186
__PRIVATE_onWatchStreamOpen @ index.esm2017.js:15185
eval @ index.esm2017.js:14709
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:18943
eval @ index.esm2017.js:18976
Promise.then
Yu @ index.esm2017.js:18976
enqueue @ index.esm2017.js:18943
enqueueAndForget @ index.esm2017.js:18921
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:14708
n_ @ index.esm2017.js:14129
eval @ index.esm2017.js:14335
setTimeout
a_ @ index.esm2017.js:14330
k_ @ index.esm2017.js:14754
B_ @ index.esm2017.js:14705
eval @ index.esm2017.js:14695
Promise.then
auth @ index.esm2017.js:14686
start @ index.esm2017.js:14591
__PRIVATE_startWatchStream @ index.esm2017.js:15161
__PRIVATE_remoteStoreListen @ index.esm2017.js:15122
__PRIVATE_allocateTargetAndMaybeListen @ index.esm2017.js:16541
await in __PRIVATE_allocateTargetAndMaybeListen
__PRIVATE_syncEngineListen @ index.esm2017.js:16526
__PRIVATE_eventManagerListen @ index.esm2017.js:15824
eval @ index.esm2017.js:21633
await in eval
eval @ index.esm2017.js:18943
eval @ index.esm2017.js:18976
Promise.then
Yu @ index.esm2017.js:18976
enqueue @ index.esm2017.js:18943
enqueueAndForget @ index.esm2017.js:18921
__PRIVATE_firestoreClientListen @ index.esm2017.js:21633
onSnapshot @ index.esm2017.js:21637
eval @ index.js:70
eval @ index-68039fd7.js:3084
Promise.then
registerStateListener @ index-68039fd7.js:3080
onAuthStateChanged @ index-68039fd7.js:2943
onAuthStateChanged @ index-68039fd7.js:6987
eval @ index.js:50
./src/inbox/index.js @ inbox.bundle.js:279
__webpack_require__ @ inbox.bundle.js:313
(anonymous) @ inbox.bundle.js:382
(anonymous) @ inbox.bundle.js:384
index.js:81  Messages snapshot error: FirebaseError: Missing or insufficient permissions.
eval @ index.js:81
eval @ index.esm2017.js:17548
setTimeout
pu @ index.esm2017.js:17547
error @ index.esm2017.js:17541
onError @ index.esm2017.js:15942
__PRIVATE_eventManagerOnWatchError @ index.esm2017.js:15889
__PRIVATE_removeAndCleanupTarget @ index.esm2017.js:16847
eval @ index.esm2017.js:16757
Promise.then
__PRIVATE_syncEngineRejectListen @ index.esm2017.js:16757
__PRIVATE_handleTargetError @ index.esm2017.js:15212
__PRIVATE_onWatchStreamChange @ index.esm2017.js:15221
onNext @ index.esm2017.js:14770
eval @ index.esm2017.js:14713
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:18943
eval @ index.esm2017.js:18976
Promise.then
Yu @ index.esm2017.js:18976
enqueue @ index.esm2017.js:18943
enqueueAndForget @ index.esm2017.js:18921
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:14713
i_ @ index.esm2017.js:14135
eval @ index.esm2017.js:14326
eval @ index.esm2017.js:14275
ab @ webchannel_blob_es2018.js:39
F @ webchannel_blob_es2018.js:37
Z.ta @ webchannel_blob_es2018.js:98
Rb @ webchannel_blob_es2018.js:53
M.Y @ webchannel_blob_es2018.js:47
M.ca @ webchannel_blob_es2018.js:44
ab @ webchannel_blob_es2018.js:39
F @ webchannel_blob_es2018.js:37
Wc @ webchannel_blob_es2018.js:76
h.bb @ webchannel_blob_es2018.js:75
h.Ea @ webchannel_blob_es2018.js:75
Lc @ webchannel_blob_es2018.js:71
h.Pa @ webchannel_blob_es2018.js:69
Promise.then
Nc @ webchannel_blob_es2018.js:69
h.Sa @ webchannel_blob_es2018.js:69
Promise.then
h.send @ webchannel_blob_es2018.js:66
h.ea @ webchannel_blob_es2018.js:74
Jb @ webchannel_blob_es2018.js:44
fd @ webchannel_blob_es2018.js:90
h.ab @ webchannel_blob_es2018.js:89
eval @ webchannel_blob_es2018.js:40
setTimeout
ub @ webchannel_blob_es2018.js:40
h.Fa @ webchannel_blob_es2018.js:89
Da @ webchannel_blob_es2018.js:28
Promise.then
x @ webchannel_blob_es2018.js:28
ec @ webchannel_blob_es2018.js:88
Rb @ webchannel_blob_es2018.js:53
M.Y @ webchannel_blob_es2018.js:47
M.ca @ webchannel_blob_es2018.js:44
ab @ webchannel_blob_es2018.js:39
F @ webchannel_blob_es2018.js:37
Wc @ webchannel_blob_es2018.js:76
h.bb @ webchannel_blob_es2018.js:75
h.Ea @ webchannel_blob_es2018.js:75
Lc @ webchannel_blob_es2018.js:71
h.Pa @ webchannel_blob_es2018.js:69
Promise.then
Nc @ webchannel_blob_es2018.js:69
h.Sa @ webchannel_blob_es2018.js:69
Promise.then
h.send @ webchannel_blob_es2018.js:66
h.ea @ webchannel_blob_es2018.js:74
Jb @ webchannel_blob_es2018.js:43
Hb @ webchannel_blob_es2018.js:42
h.Ga @ webchannel_blob_es2018.js:86
Da @ webchannel_blob_es2018.js:28
Promise.then
x @ webchannel_blob_es2018.js:28
fc @ webchannel_blob_es2018.js:84
h.connect @ webchannel_blob_es2018.js:82
Y.m @ webchannel_blob_es2018.js:96
Go @ index.esm2017.js:14266
send @ index.esm2017.js:14123
F_ @ index.esm2017.js:14626
U_ @ index.esm2017.js:14801
__PRIVATE_sendWatchRequest @ index.esm2017.js:15145
eval @ index.esm2017.js:15186
__PRIVATE_onWatchStreamOpen @ index.esm2017.js:15185
eval @ index.esm2017.js:14709
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:18943
eval @ index.esm2017.js:18976
Promise.then
Yu @ index.esm2017.js:18976
enqueue @ index.esm2017.js:18943
enqueueAndForget @ index.esm2017.js:18921
eval @ index.esm2017.js:14736
eval @ index.esm2017.js:14708
n_ @ index.esm2017.js:14129
eval @ index.esm2017.js:14335
setTimeout
a_ @ index.esm2017.js:14330
k_ @ index.esm2017.js:14754
B_ @ index.esm2017.js:14705
eval @ index.esm2017.js:14695
Promise.then
auth @ index.esm2017.js:14686
start @ index.esm2017.js:14591
__PRIVATE_startWatchStream @ index.esm2017.js:15161
__PRIVATE_remoteStoreListen @ index.esm2017.js:15122
__PRIVATE_allocateTargetAndMaybeListen @ index.esm2017.js:16541
await in __PRIVATE_allocateTargetAndMaybeListen
__PRIVATE_syncEngineListen @ index.esm2017.js:16526
__PRIVATE_eventManagerListen @ index.esm2017.js:15824
eval @ index.esm2017.js:21633
await in eval
eval @ index.esm2017.js:18943
eval @ index.esm2017.js:18976
Promise.then
Yu @ index.esm2017.js:18976
enqueue @ index.esm2017.js:18943
enqueueAndForget @ index.esm2017.js:18921
__PRIVATE_firestoreClientListen @ index.esm2017.js:21633
onSnapshot @ index.esm2017.js:21637
eval @ index.js:70
eval @ index-68039fd7.js:3084
Promise.then
registerStateListener @ index-68039fd7.js:3080
onAuthStateChanged @ index-68039fd7.js:2943
onAuthStateChanged @ index-68039fd7.js:6987
eval @ index.js:50
./src/inbox/index.js @ VM6102 inbox.bundle.js:279
__webpack_require__ @ VM6102 inbox.bundle.js:313
(anonymous) @ VM6102 inbox.bundle.js:382
(anonymous) @ VM6102 inbox.bundle.js:384

I don’t know what’s causing it, my other Firestore services work, like writing and reading the files of one’s own file (I have all users on their own file with their own UID).
Here’s my firebase security rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // ——— messages collection ———
    match /messages/{messageId} {

      // Allow read only if authenticated user is in the participants array
      allow read: if request.auth != null &&
                  request.auth.uid in resource.data.participants;

      // Allow create only if authenticated user is in the participants array being created
      allow create: if request.auth != null &&
                    request.auth.uid in request.resource.data.participants;

      // Disallow updates and deletes
      allow update, delete: if false;
    }

    // ——— users collection ———
    match /users/{userId} {
      // Anyone authenticated can read any user document
      allow read: if request.auth != null;

      // Only allow a user to update their own document
      allow update: if request.auth != null && request.auth.uid == userId;
    }

  }
}

My code works if I make my rules public (like everyone can write and read), however the moment I try to put rules, my messaging system doesn’t work.

My query looks like this:

const chatQ = query(
  collection(db, 'messages'),
  where('participants', '==', participants),
  orderBy('timestamp', 'asc')
);

My current js file for my messaging page is here:

import '../css/styles.css';
import { btnLogout } from './ui.js';

import { initializeApp } from 'firebase/app';
import {
  getAuth,
  signOut,
  onAuthStateChanged,
} from 'firebase/auth';
import {
  getFirestore,
  collection,
  query,
  where,
  orderBy,
  onSnapshot,
  addDoc,
  Timestamp
} from 'firebase/firestore';

// ——— Firebase init ———
const firebaseApp = initializeApp({
  apiKey:    "AIzaSyA_SIYh8CCbC12BmFOYS1VBSJLVnCBNu0c",
  authDomain:"citysurfer-609ab.firebaseapp.com",
  projectId: "citysurfer-609ab",
  storageBucket: "citysurfer-609ab.appspot.com",
  messagingSenderId: "736165172289",
  appId:     "1:736165172289:web:0f75f82abf121cdb06e2c0",
  measurementId: "G-7LHT92W2NX"
});
const auth = getAuth(firebaseApp);
const db   = getFirestore(firebaseApp);

// ——— UI refs ———
const msgForm     = document.getElementById('messageForm');
const msgInput    = document.getElementById('messageInput');
const msgList     = document.getElementById('messageList');
const params      = new URLSearchParams(window.location.search);
const recipientId = params.get('uid');

let chatInitialized = false;

// ——— Logout ———
btnLogout?.addEventListener('click', async () => {
  await signOut(auth);
  window.location.replace('login.html');
});

// ——— Main listener ———
onAuthStateChanged(auth, user => {
  if (!user) {
    return window.location.replace('login.html');
  }
  if (!recipientId) {
    return console.error('Missing recipient UID in URL');
  }
  if (chatInitialized) return;
  chatInitialized = true;

  // Create sorted participants array for consistent ordering
  const participants = [user.uid, recipientId].sort();

  // Query messages where participants match (array equality)
  const chatQ = query(
    collection(db, 'messages'),
    where('participants', '==', participants),
    orderBy('timestamp', 'asc')
  );

  onSnapshot(chatQ,
    snap => {
      msgList.innerHTML = '';
      snap.forEach(docSnap => {
        const m = docSnap.data();
        const li = document.createElement('li');
        li.textContent = `${m.from === user.uid ? 'You' : 'Them'}: ${m.text}`;
        msgList.appendChild(li);
      });
    },
    err => {
      console.error('Messages snapshot error:', err);
      msgList.innerHTML = `<li class="text-red-600">Error loading chat.</li>`;
    }
  );

  // — Send new messages — 
  msgForm?.addEventListener('submit', async e => {
    e.preventDefault();
    const text = msgInput.value.trim();
    if (!text) return;

    try {
      await addDoc(collection(db, 'messages'), {
        from:         user.uid,
        to:           recipientId,
        participants: participants,  // <--- Added participants array here
        text,
        timestamp:    Timestamp.now()
      });
      msgInput.value = '';
    } catch (writeErr) {
      console.error('Send message error:', writeErr);
      alert('Failed to send message.');
    }
  });
});

Why are the last two grid rows only 27px high when using `grid-template-rows: repeat(auto-fit, minmax(100px, 1fr))`?

I’m working with a CSS Grid layout and trying to evenly distribute rows inside a fixed-height container using:

grid-template-rows: repeat(auto-fit, minmax(100px, 1fr));

Here’s the full CSS and minimal HTML:

.container {
  height: 600px;
  width: 500px;
  margin: 200px auto;
  background-color: black;
  box-shadow: 0 6px 20px rgb(0 0 0 / 0.2);
  display: grid;
  grid-auto-flow: row;
  grid-template-rows: repeat(auto-fit, minmax(100px, 1fr));
}

.box {
  color: white;
  font-size: 1.5rem;
  text-align: center;
}
<body>
  <div class="container">
<div class="box" style="background-color: #e53935">FIRST</div>
<div class="box" style="background-color: #d81b60">SECOND</div>
<div class="box" style="background-color: #8e24aa">THIRD</div>
<div class="box" style="background-color: #5e35b1">FOURTH</div>
<div class="box" style="background-color: #3949ab">FIFTH</div>
<div class="box" style="background-color: #1e88e5">SIXTH</div>
<div class="box" style="background-color: #00acc1">SEVENTH</div>
<div class="box" style="background-color: #00897b">EIGHTH</div>
  </div>
</body>

Problem:

The container has a fixed height of 600px and contains 8 items. Since each row uses minmax(100px, 1fr), I expected each of the 8 rows to get at least 100px.

However, the last two items (SEVENTH and EIGHTH) are only getting about 27px height each. Why is this happening?

How to fix a circular loop for Monaco Editor in JavaScript

I am trying to make an offline code editor, when I don’t have VSCode. I have run into a problem where the file system emulator (just an object called ‘files’) becomes circular because of Monaco’s editor. When I link it up to the file to get outputs from it, through _contributions it loops back to itself.

I have no idea how I’m supposed to solve this problem as I can’t get rid of it because I might double link a file with two editors, and I can’t get the value of the editors without it.

I have the code in this JSFiddle fiddle.
https://jsfiddle.net/fu9e5hky/

let files = {};
class File {
  constructor(type, name, uniqueId) {
    this.uniqueId = uniqueId;
    this.name = name;
    this.type = type;
    this.element = document.createElement('div');
    this.element.classList.add('file');
    this.element.id = `editor-${name.replace('.', '-')}`;
    this.editor = null;
    inputDiv.append(this.element);
  }

  createMonacoEditor() {
    // will be created later
  }

  getValue() {
    return this.editor ? this.editor.getValue() : '';
  } // this requites the editor for getValue()

  delete() {
    if (this.editor) {
      this.editor.dispose();
    }
    this.element.remove();
  }
}
 // this is in the scriptLoader for Monaco Editor   
    if (editorElement) {
        editorElement.style.display = 'block';
        this.editor = monaco.editor.create(editorElement, {
          value: this.getInitialContent(this.type),
          language: language,
          theme: 'custom-dark',
          automaticLayout: true,
          minimap: { enabled: false },
        });

        if (Object.keys(files).length > 1) {
          editorElement.style.display = 'none';
        }
      }

Firebase Functions: Unhandled error RangeError: Maximum call stack size exceeded when returning object with document references

I’ve been running Gen 1 cloud functions with Firestore for years and returning documents successfully. I recently updated to firebase_functions 6.3.2 and now all of my functions are failing in the Emulator with the following error:

Unhandled error RangeError: Maximum call stack size exceeded at Function.entries ()at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:169:37) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22) at encode (/Development/App/api/functions/node_modules/firebase-functions/lib/common/providers/https.js:170:22)

Package Versions

"engines": {
    "node": "22"
  },
"firebase-admin": "^13.4.0",
"firebase-functions": "^6.3.2",

Here’s the code that retrieves a doc and returns, generating the error above:

exports.getItem = functions.https.onCall(async (data, context) => {
  let id = data.id;
  let result = {};

  const itemDoc = await db.collection("items").doc(id).get(); 
  result.item = itemDoc.data();
  return result;
});

//I've also tried this as a Promise and the error is the same

HISTORY: This exact function works in prior versions of firebase_functions (e.g., 4.2.1) which are live in Production, but now fails when using firebase_functions 6.3.2 in the emulator.

ROOT CAUSE: Documents in the items collection have a components attribute that is an array of DocumentReferences. When I update my function to empty that array (i.e., result.item.components = [];), the error goes away. So it seems that something changed in the way firebase functions handle object serialization and returning document references is now not possible.

CHALLENGES: The app that uses this api expects Document References to be returned, since it always worked that way. I could change the app to process document reference paths and cast to a Document Reference, but it’s a real pain to synchronize the deployment since updates require app store reviews etc. and I never know what that timeline is going to be. I’d really prefer to find a way to return document references.

Does anyone know what changed in firebase_functions that would cause this issue, and if there are any workarounds?

Why does Cropper.Js’ .cropper-container increase in height when I loop through multiple images?

In Cropper.js v1.5.12, the ountermost parent div of crop box has the classes cropper-container cropper-bg. The height of each of these div increases as I loop through multiple images to create an instance of crop box for each image. For examole, 4 images, each had a width of 679px and a height of 960px. When I looped through the images, the first .cropper-container had height of 2849px; the 2nd had height of 4991px; the 3rd had height of 9275px; and the 4th had height of 17843px. However, If I do no loop through multiple images and that the image is only one, the height of .cropper-container is 728px for an image that had width of 679px and a height of 960px. This was a perfect fit for the image (not too long or short for the image) as the rendered width of the image was 500px. What could be the problem here and what could be the fix? I have already set img{max-width: 100%;} in my css file.

I know that there is a later version of Cropper.js but I am trying to under the problem here first.

My JS is like the code below:

$modal.on('shown.bs.modal', function(){
    
    const images = document.querySelectorAll('.images');
    
    let numImages = images.length;
    
    const croppers = [];
    let i;

    for (i = 0; i < numImages; i++) {
        croppers.push(new Cropper(images[i], {
            aspectRatio: NaN, 
            viewMode: 2, 
            preview:'.preview',
            dragMode: 'move',
            cropBoxResizable: true,
            
            minCropBoxWidth: 320,
            minCropBoxHeight: 240,
    
            data:{ 
              width: 640,
              height:  480
            }
        }));
    }
});

JS issue with adding an element and removing it using s

I have js functions that are supposed to create and remove an HTML element by I’d but don’t work when rendering. (note that the seemingly non-existent element with I’d gamespace is real in the html)

function start(){
  let frame = document.createElement("iframe").setAttribute('width', 'auto').setAttribute('id', 'gameframe').setAttribute('href', 'medv.io/bit-planes/?mode=domination');
  document.getElementById('gamespace').appendChild(frame);
}
function stop() {
  document.getElementById('gameframe').remove();
}

I ran the html with linking the script properly, clicked the start and stop buttons, but nothing happened with either button.

JavaScript ReferenceError: getSessionIdFromUrl is not defined in Oracle APEX code

I am working on an Oracle APEX application where I need to delete selected rows from an Interactive Grid by sending their SUPPLIER_ID and ID values to an Application Process (DELETE_SELECTED_SUPPLIERS_APP).

To handle this, I have written a JavaScript function that adds a custom button to the Interactive Grid’s toolbar. Upon clicking the button, it captures the selected rows, retrieves the session ID from the URL, and sends the data to the Application Process using apex.server.process.

However, I am encountering two major issues:

Uncaught SyntaxError: Unexpected token ‘function’ (at file.js:line:column)
This happens when I load the page, and the browser points to a specific line in my JavaScript code. It seems there is something wrong with how the JavaScript is structured, but I can’t figure out what exactly is causing the error.

ReferenceError: getSessionIdFromUrl is not defined
When I try to invoke the function getSessionIdFromUrl() in my code, the browser throws this error. This function is meant to extract the session parameter from the URL.

Despite multiple attempts to fix the code (e.g., reordering the function definition), these errors persist.
JavaScript Code

// Function to extract the session ID from the URL
function getSessionIdFromUrl() {
    var url = window.location.href; // Get the current URL
    var sessionIdMatch = url.match(/session=([d]+)/); // Regex to match the 'session' parameter
    return sessionIdMatch ? sessionIdMatch[1] : null; // Return the session ID or null if not found
}

function(config) {
    let $ = apex.jQuery,
        toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),
        toolbarGroup = toolbarData.toolbarFind("actions3");

    apex.actions.add({
        name: "delete-selected-suppliers",
        label: "Delete Selected Suppliers",
        action: function(event, focusElement) {
            var grid = apex.region("Delete_SUPP").widget().interactiveGrid("getViews", "grid");
            var model = grid.model;
            var selectedRecords = grid.getSelectedRecords();

            if (selectedRecords.length === 0) {
                apex.message.alert("Please select at least one supplier to delete.");
                return false;
            }

            // Capture SUPPLIER_ID and ID from selected rows
            var recordsToDelete = selectedRecords.map(function(record) {
                return {
                    supplier_id: model.getValue(record, "SUPPLIER_ID"),
                    id: model.getValue(record, "ID")
                };
            });

            console.log("Records to delete:", recordsToDelete);

            // Retrieve session ID from the URL
            var sessionId = getSessionIdFromUrl();

            // Validate session ID
            if (!sessionId) {
                console.error("Session ID not found in the URL.");
                apex.message.showErrors([{ message: "Session ID not found. Please refresh the page and try again." }]);
                return false;
            }

            apex.message.confirm("Are you sure you want to delete the selected suppliers?", function(okPressed) {
                if (okPressed) {
                    apex.server.process(
                        "DELETE_SELECTED_SUPPLIERS_APP",
                        { x01: JSON.stringify(recordsToDelete) }, // Send data as JSON
                        {
                            success: function(data) {
                                if (data && data.status === "success") {
                                    apex.message.showPageSuccess(data.message);
                                    apex.region("Delete_SUPP").refresh(); // Refresh the Interactive Grid
                                } else {
                                    apex.message.showErrors([{ message: data.message || "An unknown error occurred." }]);
                                }
                            },
                            error: function(jqXHR) {
                                console.error("AJAX error:", jqXHR.responseText);
                                apex.message.showErrors([{ message: "An error occurred during the process." }]);
                            }
                        },
                        { p_instance: sessionId } // Manually propagate the session ID
                    );
                }
            });

            return true;
        }
    });

    toolbarGroup.controls.push({
        type: "BUTTON",
        id: "delete_selected_suppliers",
        label: "Delete Selected Suppliers",
        icon: "fa fa-trash",
        action: "delete-selected-suppliers"
    });

    config.toolbarData = toolbarData;
    return config;
}

PL/SQL application process:

DECLARE
    l_records_to_delete CLOB; -- Variable para almacenar el JSON recibido
    l_supplier_id VARCHAR2(4000); -- Variable para almacenar SUPPLIER_ID
    l_id VARCHAR2(4000); -- Variable para almacenar ID
    l_count NUMBER; -- Número de registros en el JSON
BEGIN
    -- Debug message to confirm that the process is called
    apex_debug.message('DELETE_SELECTED_SUPPLIERS_APP process called');

    -- Get the JSON sended X01
    l_records_to_delete := apex_application.g_x01;

    -- validate that the JSON is present
    IF l_records_to_delete IS NULL THEN
        apex_debug.message('Error: X01 is NULL. No data received.');
        apex_json.open_object;
        apex_json.write('status', 'error');
        apex_json.write('message', 'No data received for deletion.');
        apex_json.close_object;
        RETURN;
    END IF;

    -- Initialize the JSON for analysis
    apex_json.parse(p_source => l_records_to_delete);

    -- Count the number of objects in the JSON
    l_count := apex_json.get_count(p_path => '$'); -- Contar elementos en la raíz del array

    -- Iterate over records in JSON
    FOR i IN 1 .. l_count LOOP
        BEGIN
            -- Extract SUPPLIER_ID and ID from JSON
            l_supplier_id := apex_json.get_varchar2(p_path => '$[' || (i - 1) || '].supplier_id');
            l_id := apex_json.get_varchar2(p_path => '$[' || (i - 1) || '].id');

            -- Try to delete the register
            DELETE FROM SELECTED_SUPPLIERS
            WHERE SUPPLIER_ID = l_supplier_id
              AND ID = l_id;

            -- Message to confirm every delete.
            IF SQL%ROWCOUNT = 0 THEN
                apex_debug.message('No rows deleted for SUPPLIER_ID: ' || l_supplier_id || ' and ID: ' || l_id);
            ELSE
                apex_debug.message('Deleted SUPPLIER_ID: ' || l_supplier_id || ' for ID: ' || l_id);
            END IF;

        EXCEPTION
            WHEN OTHERS THEN
                apex_debug.message('Error: ' || SQLERRM || ' for SUPPLIER_ID: ' || l_supplier_id || ' and ID: ' || l_id);
        END;
    END LOOP;

    -- Generater JSON Answer for success
    apex_json.open_object;
    apex_json.write('status', 'success');
    apex_json.write('message', 'Selected suppliers were successfully deleted.');
    apex_json.close_object;

EXCEPTION
    WHEN OTHERS THEN
        -- Manejar errores y generar respuesta JSON para fallos
        apex_debug.message('Error: ' || SQLERRM);
        apex_json.open_object;
        apex_json.write('status', 'error');
        apex_json.write('message', 'An error occurred while deleting suppliers: ' || SQLERRM);
        apex_json.close_object;
END;

Additional Context
I am using Oracle APEX (version 24.2.3).
The Interactive Grid has the Static ID Delete_SUPP.
The Application Process DELETE_SELECTED_SUPPLIERS_APP is configured as an Ajax Callback and works correctly when tested independently.

blank page on the browser in my react app using react hook form

the browser shows me blank page and i see no error in the vs code and terminal. but in the console i see:

"Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. at renderWithHooksAgain (react-dom-client.development.js:5614:17) at renderWithHooks (react-dom-client.development.js:5532:21) at updateFunctionComponent (react-dom-client.development.js:8897:19) at beginWork (react-dom-client.development.js:10522:18) at runWithFiberInDEV (react-dom-client.development.js:1519:30) at performUnitOfWork (react-dom-client.development.js:15132:22) at workLoopSync (react-dom-client.development.js:14956:41) at renderRootSync (react-dom-client.development.js:14936:11) at performWorkOnRoot (react-dom-client.development.js:14462:44) at performWorkOnRootViaSchedulerTask (react-dom-client.development.js:16216:7)"

and a warning:

“hook.js:608 An error occurred in the <App> component.

Consider adding an error boundary to your tree to customize error handling behavior.

Visit https://react.dev/link/error-boundaries to learn more about error boundaries.”


this is my code in the app.jsx component:

const tipPercents = [5, 10, 15, 25, 50];

export default function App() {
  const { register, handleSubmit, setValue, watch } = useForm();
  const [tipPercent, setTipPercent] = useState(null);

  const customTip = parseFloat(watch('customTip')) || null;
  const bill = parseFloat(watch('bill')) || 0;
  const people = parseFloat(watch('people')) || 0;

  const tip = customTip || tipPercent || 0;
  const tipAmount = people ? ((bill * tip) / 100) / people : 0;
  const total = people ? (bill + (bill * tip) / 100) / people : 0;

  const handleTipClick = (value) => {
    setTipPercent(value);
    setValue('customTip', '');
    setValue('tipPercent', value)
  };

  const reset = () => {
    setTipPercent(null);
    setValue('bill', '');
    setValue('people', '');
    setValue('customTip', '');
  };

  return (
    <div>
      <div>
        <form onSubmit={handleSubmit(() => {})}>

          <div className='left'>
            <div>
              <label>Bill</label>
              <div>
                <img src={dollar} alt="bill" />
                <input type="number" placeholder='0' {...register('bill')} />
              </div>
            </div>
            <div>
              <p>Select Tip %</p>
              <div>
                {/* tip button components go here */}
                {tipPercents.map((percent) => (
                  <TipButton
                    key={percent}
                    value={percent}
                    isActive={tipPercent === percent}
                    onClick={handleTipClick}
                   />
                ))}
              </div>
              <input
                type="number" 
                placeholder='Custom' 
                {...register('customTip')} 
                onFocus={setTipPercent(null)} 
              />
            </div>
            <div>
              <label>Number of People</label>
              <div>
                <img src={person} alt="person" />
                <input type="number" placeholder='0' {...register('people')} />
              </div>
            </div>
          </div>

          <div className='right'>
            <div>
              {/* result components go here */}
              <ResultRow title={"Tip Amount"} amount={tipAmount.toFixed(2)} />
              <ResultRow title={"Total"} amount={total.toFixed(2)} />
            </div>
            <button type='button' onClick={reset}>RESET</button>
          </div>

        </form>
      </div>
    </div>
  )
}

this is tipButton.jsx component:

export default function TipButton ({ value, onClick, isActive }) {
    return (
        <button
            type="button"
            onClick={() => onClick(value)}
            className={`tip-button ${isActive === value ? 'active-button' : ''}`}
        >
            {value}%
        </button>
    )
}

ResultRow.jsx:

export default function ResultRow ({ title, amount }) {
    return (
        <div>
            <div>
                <p>{title}</p>
                <p>/ person</p>
            </div>
            <h3>${amount}</h3>
        </div>
    )
}

i asked chatgpt and it said the problem is related to sth like setValue or onclick function for TipButton component. i tried the solution it gave me but didn’t work.

Expo v53 KeyboardAvoiding view: View’s height changes after opening and closing the keyboard

As you can see in the initial render, the blue view at the bottom has a different size compared to the same view after opening and closing the keyboard.

Current behaviour:

Current behaviour

In my app I have a “footer” element that should stay at the bottom of the screen.
I managed to reduce the problem to a few simple lines of code.

<KeyboardAvoidingView
  behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
  style={{ flex: 1, backgroundColor: 'blue' }}
  keyboardVerticalOffset={insets.top}
  >
  <View style={{ backgroundColor: 'purple', flex: 1 }}>
   <TextInput style={{ backgroundColor: 'red'}}placeholder="Type here..." />
  </View>
 <Text>Hello</Text>
</KeyboardAvoidingView>

Thank you!

Javascript and PHP

I’m trying to have PHP work with JavaScript, right now JavaScript is ensuring that all my inputs are filled, then I want PHP to run. Right now, it doesn’t matter if anything is empty, it just runs and creates the data in MySQL.

This function checks for any empty or incorrect spaces before it submits, then would block the button from submitting the form.

function getSignupFormErrors(firstname, email, password, repeatPassword){
  let errors = []

  if(firstname === '' || firstname == null){
    errors.push('Firstname is required')
    firstname_input.parentElement.classList.add('incorrect')
  }
  if(email === '' || email == null){
    errors.push('Email is required')
    email_input.parentElement.classList.add('incorrect')
  }
  if(password === '' || password == null){
    errors.push('Password is required')
    password_input.parentElement.classList.add('incorrect')
  }
  if(password.length < 5){
    errors.push('Password must have at least 5 characters')
    password_input.parentElement.classList.add('incorrect')
  }
  if(password !== repeatPassword){
    errors.push('Password does not match repeated password')
    password_input.parentElement.classList.add('incorrect')
    repeat_password_input.parentElement.classList.add('incorrect')
  }


  return errors;
}

Then after it checks for errors it prints it in a line for users to read:

const allInputs = [firstname_input, email_input, password_input, repeat_password_input].filter(input => input != null)

allInputs.forEach(input => {
  input.addEventListener('input', () => {
    if(input.parentElement.classList.contains('incorrect')){
      input.parentElement.classList.remove('incorrect')
      error_message.innerText = ''
    }
  })
})

My PHP is checking for any of that email inside the database, but doesn’t read that nothing is supposed to happen.

if(isset($_POST['signUp'])){
    $firstName=$_POST['firstname'];
    $email=$_POST['email'];
    $password=$_POST['password'];
    $password=md5($password);

     $checkEmail="SELECT * From users where email='$email'";
     $result=$conn->query($checkEmail);
     if($result->num_rows>0){
        echo '<script>
                        window.location.href = "login.php";
                        alert("Sign Up failed. Email already exists!")
                    </script>';
     }
     else{
        $insertQuery="INSERT INTO users(firstname,email,password)
                       VALUES ('$firstName','$email','$password')";
            if($conn->query($insertQuery)==TRUE){
                header("location: login.php");
            }
            else{
                echo "Error:".$conn->error;
            }
     }
   

}

I’ve tried to write a piece of code that may check and see that if email is null, it quits the operation (on the PHP side). But after doing so, I realized that’s not what I’m looking for, I’ve tried googling it, but nothing is helpful.

CKEditor 5 – Get X/Y coordinates of cursor

Wanted to be able to get the X and Y coordinates of the cursor (blinking pipe) in relation to the viewport.

The closest I could get to finding a solution was this link:
https://ckeditor.com/old/forums/CKEditor-3.x/Cursor-coordinates-XY-SOLVED

But it seems to be very old and obsolete solution. Couldn’t make it work.

The application I have in mind is: When the user presses a certain key, a popup will show up in the cursos position with some option for him to select.

Thnaks.

await for async function that returns a promise will wait for the promise to resolve aswell

I am writing a function that needs to return a promise to be handled. Inside the function, there is some other async functions that I need to wait before returning my promise.
After calling this function, I need to wait before continuing the code, because function3 depends on what happens inside function 2.

// version 1

function1 () {
 function2().then(selected => {
  // need to define whats happens with the promise here
 })
 function3(){}
}

async function2 () {
  await X
  await Y

  return new Promise(async (resolve, reject) => {}

}


//version 2

async function1 () {
 await function2().then(selected => {
  // need to define whats happens with the promise here
 })
 function3(){}
}

async function2 () {
  await X
  await Y

  return new Promise(async (resolve, reject) => {}

}

The problem here is that on version 1, function3 is being called before function2 has ran all its code.

Version 2 is waiting for both function2 code and the promise it returns to be fullfilled. So basically function3 is not being called.

Is there anyway I can wait for the function 2 to run but still be able to define how to handle its promise?

How to optimize a user-uploaded image before applying it as a texture in Three.js?

I’m building an online product customization tool using Three.js. The user uploads an image (like a logo or artwork), and we apply that image as a texture on a 3D object (a .glb reusable cup model).

However, when the uploaded image has a lot of colors or is large in size (e.g., 2MB, 2000x2000px), the texture application becomes slow, and the user experience degrades significantly.

I would like to optimize this process by reducing the weight of the uploaded image on the client side, before sending it to the server or applying it to the texture.

My questions:
How can I resize and compress the user-uploaded image in the browser before applying it as a Three.js texture?

Is it possible to reduce the number of colors (bit depth) or use something like pngquant or imagequant.js in the browser?

Can I convert the image to WebP using canvas or other client-side tools and still use it in a THREE.Texture?

What’s the best way to integrate image optimization with texture generation in a Three.js workflow?

react delete request not reaching spring boot api, 404 error

My react app successfully gets and posts from/to Spring Boot JPA MySql db. But delete fails with 404, meaning it can find the endpoint.

MedaverterApplication.java

@SpringBootApplication
@ComponentScan(basePackages = { "net.tekknow.medaverter.*" })
@EntityScan(basePackages = "net.tekknow.medaverter.*") 
public class MedaverterApplication {

    public static void main(String[] args) {
        SpringApplication.run(MedaverterApplication.class, args);
    }

      @Bean
      public WebMvcConfigurer corsConfigurer() {
          return new WebMvcConfigurer() {
              @Override
              public void addCorsMappings(CorsRegistry registry) {
                  registry.addMapping("/**")
                          .allowedOrigins("http://localhost:3000") 
                          .allowedMethods("GET", "POST", "PUT", "DELETE")
                          .allowedHeaders("*")
                          .allowCredentials(true);
              }
          };
      }
}

EventController.java

package net.tekknow.medaverter.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import java.util.List;
import net.tekknow.medaverter.models.Event;
import net.tekknow.medaverter.repository.EventRepo;

@CrossOrigin
@RestController
public class EventController {
    @Autowired
    EventRepo eventRepo;

    @GetMapping("/get-events")
    public List<Event> getEvents(int user_id) {
        List<Event> events = eventRepo.findEventsByUserId(user_id);
        return events;
    }

    @PostMapping(path = "/save-event", consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<Event> addEvent(@RequestBody Event event) {
        return ResponseEntity.ok().body(eventRepo.save(event));
    }

    @DeleteMapping("/delete-event/{id}")
    public ResponseEntity<String> deleteEvent(@PathVariable Integer id) {
        try {
            eventRepo.deleteById(id);
            return new ResponseEntity<>("Item deleted successfully", HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>("Error deleting item", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

Note that both GET and POST work, but not DELETE

events.tsx

const deleteEvent = async (id: GridRowId) => {
  const response = await fetch(`/delete-event?id=${id}`, {
    method: 'DELETE',
    headers: {
      'Content-Type': 'application/json' // Or the appropriate content type
    },
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json();
    })
    .then((data) => {
      console.log('Row deleted successfully:', data);
    })
    .catch((error) => {
      console.error('Error deleting row:', error);
    });
}

I also tried:

  const response = await fetch(`http://localhost:3000/delete-event?id=${id}`, {...
  const response = await fetch(`http://localhost:8080/delete-event?id=${id}`, {...

How is it that I can get and save data, but not delete? I thought maybe the browser was blocking due to CORS, but I’ve got that covered. Can anybody see what I am doing wrong?