Nullish value narrowing on Typescript using logical conjunction on React

Can someone help me to clarify why typescript does actually narrow the type in this case:

subcollectionId is narrowed to whatever non-nullish value you expect to have

const subCollectionId = collection.subcollection?.id
{subcollectionId && (<Text>{subcollectionId}<Text/>)}

but not in

collection.subcollection?.id can still be nullish inside the

{collection.subcollection?.id && (<Text>{collection.subcollection?.id}<Text/>)}
<Text>{collection.subcollection?.id}<Text/>

On my testing collection.subcollection?.id can still be a nullish value but not if I declare an additional variable.

Flask Form Submission: class_id is “undefined” When Creating an Exam

I’m developing a Flask-based school hub app where teachers can create exams. However, I’m encountering an issue where class_id is "undefined" when submitting the form.


Issue:

When I submit the form, Flask logs the following:

DEBUG - Raw Form Data: {'title': '1', 'class_id': 'undefined', 'description': '1'}
ERROR - Validation failed: Invalid or missing class_id

Even though class_id exists in my form and is being set dynamically from the backend (Jinja) or fetched via JavaScript, it still appears as "undefined" in Flask’s request.form.


Flask Route (create_exam)

@main.route('/create_exam', methods=['POST'])
@login_required
def create_exam():
    if current_user.role != 'teacher':
        return jsonify({'error': 'Unauthorized'}), 403

    logger.debug(f"Raw Form Data: {dict(request.form)}")

    title = request.form.get('title')
    class_id = request.form.get('class_id')
    description = request.form.get('description')

    logger.debug(f"Received Exam Data - Title: {title}, Class ID: {class_id}, Description: {description}")

    if not class_id or class_id.strip().lower() in ["undefined", "null", "none", ""]:
        logger.error(f"Validation failed: Invalid or missing class_id. Received: {class_id}")
        return jsonify({'error': 'A valid class ID is required'}), 400

    try:
        class_id = int(class_id)
    except ValueError:
        return jsonify({'error': 'Class ID must be a valid number'}), 400

    class_entry = Class.query.get(class_id)
    if not class_entry:
        return jsonify({'error': 'Invalid class or unauthorized access'}), 403

    try:
        exam = Exam(title=title, class_id=class_id, description=description, teacher_id=current_user.id)
        db.session.add(exam)
        db.session.commit()
        return jsonify({'message': 'Exam created successfully'}), 201
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': 'Failed to create exam'}), 500

HTML Form

<form id="exam-form" action="/create_exam" method="POST">
    <div class="mb-3">
        <label for="title" class="form-label">Exam Title</label>
        <input type="text" class="form-control" id="title" name="title" required>
    </div>
    
    <div class="mb-3">
        <label for="class_id" class="form-label">Select Class</label>
        <select class="form-control" id="class_id" name="class_id" required>
            {% if class_codes %}
                <option value="" disabled selected>Select a class</option>
                {% for class_code in class_codes %}
                    <option value="{{ class_code.id }}">{{ class_code.code }}</option>
                {% endfor %}
            {% else %}
                <option disabled>No class codes available</option>
            {% endif %}
        </select>
    </div>

    <button type="submit" class="btn btn-primary">Create Exam</button>
</form>

JavaScript (Fetching Class Codes & Debugging Submission)

document.addEventListener("DOMContentLoaded", function () {
    const classSelect = document.getElementById("class_id");

    fetch("/get_class_codes")
        .then(response => response.json())
        .then(data => {
            console.log("[DEBUG] Received class codes:", data);

            if (classSelect.options.length <= 1) { 
                classSelect.innerHTML = ""; // Clear only if Jinja hasn't preloaded

                let defaultOption = document.createElement("option");
                defaultOption.value = "";
                defaultOption.disabled = true;
                defaultOption.selected = true;
                defaultOption.textContent = "Select a class";
                classSelect.appendChild(defaultOption);

                data.forEach(classCode => {
                    let option = document.createElement("option");
                    option.value = classCode.id;
                    option.textContent = classCode.code;
                    classSelect.appendChild(option);
                });
            }
        })
        .catch(error => console.error("[DEBUG] Error fetching class codes:", error));
});

// Debugging Form Submission
document.getElementById("exam-form").addEventListener("submit", function (event) {
    let classSelect = document.getElementById("class_id");
    console.log("[DEBUG] Selected class ID:", classSelect.value);

    if (!classSelect.value || classSelect.value === "undefined") {
        event.preventDefault();
        alert("Please select a valid class.");
    }
});
  1. Checked document.getElementById("class_id").value before submitting → It logs the correct class ID.
  2. Checked Flask request.form output → It logs "undefined".
  3. Manually selected an option before submitting → Still logs "undefined".
  4. Used fetch("/get_class_codes") to populate the dropdown → The options are generated correctly, but still, "undefined" is sent.

What I Expected:

  • The selected class_id should be sent properly and received by Flask as a valid integer.
  • request.form.get("class_id") should return the selected class ID instead of "undefined".

Questions:

  • Why is class_id being sent as "undefined"?
  • Could the issue be caused by JavaScript interfering with form submission?
  • Is there a better way to debug form data in Flask?

User validation method with jwt in react and c#

I’m developing an application in react with the backend in c#, for the validation of logged in users, the backend returns me a jwt on login and I save it in the cookies with the security parameters (secure, same-sime: strict, http-only and others), and with each request within the system it kills the previous jwt and creates a new one in a sequential flow, but if I press f5 on the page, it can’t retrieve the jwt because it has the http-only parameter and I end up being kicked from the page. I tried to do some logic using context but I couldn’t solve the page refresh part, I need genuine help.

(I’m currently running the cookie without http-only, so when it refreshes I recover the last saved cookie using the default state value, but I need http-only for pci-dss)

Below is my private route code that wraps my screens (It may seem like dirty code and it really is, but it was the only way to get the user logged in the way they designed the jwt logic):

const PrivateRoute = ({ children }) => {
  const [isAuthenticated, setIsAuthenticated] = useState(null);
  const [token, setToken] = useState(Cookies.get('authToken'));
  const [isSessionLoaded, setIsSessionLoaded] = useState(false); // Novo estado
  const location = useLocation();

  const { userSession, tokenResponse, setTokenResponse, setTokenAtual, tokenAtual, setUserSession } = useAuthContext();
  
  const navigate = useNavigate();

  const validation = async () => {
    try {
      const response = await validateTokenJWT(token);
      if (response.data) {
        setIsAuthenticated(true);
        return response.data;
      } else {
        Cookies.remove("authToken");
        setIsAuthenticated(false);
        return navigate("/");
      }
    } catch (e) {
      console.log(e);
      return navigate("/");
    }
  };

  const validationFirstTime = async () => {
    try {
      const response = await validateTokenJWT(tokenResponse);
      if (response.data) {
        setIsAuthenticated(true);
        return response.data;
      } else {
        Cookies.remove("authToken");
        setIsAuthenticated(false);
        return navigate("/");
      }
    } catch (e) {
      console.log(e);
      return navigate("/");
    }
  };

  useEffect(() => {
    const checkToken = async () => {
      if (tokenResponse) {
        const newToken = await validationFirstTime();
        setTokenResponse(null);
        if (newToken && newToken !== token) {
          setTokenAtual(newToken);
          setToken(newToken);
          Cookies.set("authToken", newToken, {
            expires: new Date(new Date().getTime() + 15 * 60 * 1000),
            path: "/",
            sameSite: "Strict", // Previne ataques CSRF
            secure: true, // Garante que o cookie só seja transmitido via HTTPS
          });

          systemname.interceptors.request.use(
            (config) => {
              const token = newToken;
              if (token) {
                config.headers.Authorization = `Bearer ${token}`;
              }
              return config;
            },
            (error) => {
              return Promise.reject(error);
            }
          );

        } else {
          Cookies.remove("authToken");
          setIsAuthenticated(false);
          return navigate("/");
        }
      } else {
        if (token) {
          const newToken = await validation();
          if (newToken && newToken !== token) {
            setTokenAtual(newToken);
            setToken(newToken);
            Cookies.set("authToken", newToken, {
              expires: new Date(new Date().getTime() + 15 * 60 * 1000),
              path: "/",
              sameSite: "Strict", // Previne ataques CSRF
              secure: true, // Garante que o cookie só seja transmitido via HTTPS
            });

            systemname.interceptors.request.use(
              (config) => {
                const token = newToken;
                if (token) {
                  config.headers.Authorization = `Bearer ${token}`;
                }
                return config;
              },
              (error) => {
                return Promise.reject(error);
              }
            );
          }
        } else {
          Cookies.remove("authToken");
          setIsAuthenticated(false);
          return navigate("/");
        }
      }
    };

    checkToken();
  }, [location.pathname]);

  useEffect(() => {
    const checkUserSession = async () => {
      if (tokenAtual) {
        try {
          const response = await getUserByAuthToken();
          if (response.data) {
            setUserSession(response.data);
            setIsSessionLoaded(true);
          }
        } catch (error) {
          console.log(error);
        }
      }
    };
    checkUserSession();
  }, [tokenAtual]);

  useEffect(() => {
    if (isSessionLoaded) {
      const routeName = window.location.pathname.split("/").pop();
      const permissions = userSession?.screens;

      const permissionFound = permissions.map((screen) => {
        if (screen.userScreenId === routeName) {
          return true;
        } else {
          return false;
        }
      });

      const hasPermission = permissionFound.includes(true);

      if (!isAuthenticated) {
        navigate("/");
      } else if (!hasPermission) {
        navigate("/AccesDenied");
      }
    }
  }, [isSessionLoaded, userSession, isAuthenticated, navigate]);

  if (isAuthenticated === null) {
    return (
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          height: "100vh",
        }}
      >
        <Spin size="large" />
      </div>
    );
  }

  return children;
};

export default PrivateRoute;

I tried everything, I need help, I’m also looking for some other solution to make this work, even if it means removing the token from the cookie (it would be even better)

IBM Hyperledger Fabric error in packaging chaincode

During packaging of chaincode of tar.gz file in IBM Hyperledger Fabric I’m getting the below error:

Failed to determine workspace language type, supported languages are JavaScript, TypeScript, Go and Java. Please ensure your contract’s root-level directory is open in the Explorer.

All my environment setup is in javascript but system is trying to mess it in between of java and javascript and I’m not working anywhere in java.

I had also opened my lib folder which only has smart contract in it for packaging chaincode but still I’m getting the below terminal error:
Executing task: C:Users”user name”.cargobincargo.exe build

error: could not find Cargo.toml in C:"my parent directory path"lib or any parent directory

  • The terminal process “C:Users”user name”.cargobincargo.exe ‘build'” terminated with exit code: 101.
  • Terminal will be reused by tasks, press any key to close it.

I tried to open my lib folder which contains only the smart contracts in a separate visual studio code.

I expect that my packaging chaincode of tar.gz file would got created but it throws the error:

Failed to determine workspace language type, supported languages are JavaScript, TypeScript, Go and Java. Please ensure your contract’s root-level directory is open in the Explorer.

Terminal Error:

Executing task: C:Users”user name”.cargobincargo.exe build

error: could not find Cargo.toml in C:"my parent directory path"lib or any parent directory

  • The terminal process “C:Users”user name”.cargobincargo.exe ‘build'” terminated with exit code: 101.
  • Terminal will be reused by tasks, press any key to close it.

Help me to resolve the above issue so that I can create my packaging chaincode in IBM Hyperledger Fabric in visual studio code.

How to use Karma/Jasmine to test web application that opens a link in a new window/tab?

I have a small webapp that opens a link in a new window. The document in the new window then interacts with the original webapp through the DOM.

The webapp itself is written in Angular, but the link is plain HTML (not even coming from an Angular template). The target document is not Angular, just plain HTML/CSS/JS:

  <a target="_blank" rel="opener" href="/assets/probes/xss.html">Click here!</a>

Tests are set up according to Angular’s component testing guide. Here’s a snippet of the setup code:

  beforeEach(async () => {
    TestBed.configureTestingModule(xssDemoConfig);
    await TestBed.compileComponents();
    fixture = TestBed.createComponent(XssDemoComponent);
    fixture.detectChanges();

    // ...
  });

This setup works like a charm for hundreds of other tests. The new test code is simple:

  el.querySelector('a').click();

I’ve confirmed in the browser debug console that the selector returns the correct <a> element. (And I have other working tests that trigger click events on similar links — only difference is that those links have javascript: URLs and do not open a new window or even trigger navigation.)

Everything works like a charm when testing manually in a browser. However, when my new tests try to click the link, nothing at all happens. No new window, but no error or log message either. My spec just runs into a timeout. (I’ve tried more generous timeouts, but this hasn’t fixed it.)

So, finally my questions:

  • Why is this happening?
  • Does the Angular TestBed, or Jasmine, or Karma have some hidden feature that intercepts such clicks?
  • If so, which of them is at fault here?
  • Is there any way that I could bypass this undesired behavior?
  • Is such testing feasible with Karma/Jasmine at all?
  • If not, which other tools/frameworks should I try?

Note that this post is about integration/e2e tests. So, I do not want to mock away anything (as numerous answers to similar questions suggest). I really do want to test the interactions between the two windows (and ideally discard the new window afterwards).

How do I code the PHP script to make a contact form?

  • I have html set up
  • I have JS set up
  • I dont know how to get the php set up
  • my html code is set up below:
<form action="action_page.php">

    <label for="fname">First Name</label>
    <input type="text" id="fname" name="firstname" placeholder="Your name..">

    <label for="lname">Last Name</label>
    <input type="text" id="lname" name="lastname" placeholder="Your last name..">

    <label for="subject">Subject</label>
    <textarea id="subject" name="subject" placeholder="Write something.." style="height:200px"></textarea>

    <input type="submit" value="Submit">

  </form>

Q2 Options Reset After Page Reload or Navigation, Even When Q1 is Set to ‘Result’

I want to disable the Q2 options when the Result option is selected for Q1. So, when I select Result for Q1, all options in Q2 should be disabled.

However, the issue is that when I navigate to another page and come back, or when I reload the page, the Q2 options get reset. Even though the Result option for Q1 remains checked, the Q2 options are no longer disabled. How can I fix it.

Thanks in advance.

here’s my function:

function handleQ2Checkboxes() {
    var q1 = document.getElementById("Q1:::Result");
    var q2Options = document.querySelectorAll('.Q2');

        
    if (q1.checked) {
        q2Options.forEach(function(checkbox) {
            checkbox.disabled = true;
            checkbox.checked = false;  // Uncheck the checkbox
        });
            
    } else {
        q2Options.forEach(function(checkbox) {
            checkbox.disabled = false;
            checkbox.setAttribute("validation", "required");
        });
    }
}

CSS Scale (not resize) a DIV horizontally to 100% of its parent container

I’ve got a DIV that has a fixed size of its background image. I use relative positioning on child elements to display data where it needs to be shown at the appropriate location on the image. However, I’d like the DIV to actually be 100% width of its parent container and to grow and shrink horizontally (scale) without disturbing the layout of the child element positioning and size? I’m guessing I’ll have to use a combination of CSS transform/scale and javascript. Any help is appreciated.

<div style="background-image:url('my.png');width:800px;height:367px;position:relative;">
  <div style="position:absolute;left:80px;top:120px;font-size:14px;">value</div>
  <div style="position:absolute;left:200px;top:300px;font-size:14px;">value</div>
  <div style="position:absolute;left:450px;top:80px;font-size:14px;">value</div>
</div>

How to fix ThreeJs camera controls only updating for starting view

I am making a 3d Three Js game, but I have run into a problem with my camera controls. When I look the starting direction that you look, the camera controls are all right. But if I look backward, the up and down camera controls inverse, and if I look to one of the sides, then those controls make the whole thing go sideways. I think the problem is like an old time joystick, where if you stand on the side of the claw machine or whatever it is, than forward would not be forward, it would be to the side. Here is my code so far: (Sorry, mouse lock doesn’t work with stack overflow, use something like https://www.w3schools.com/html/tryit.asp?filename=tryhtml_default)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>First Person Game</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
    let scene, camera, renderer;
    let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
    let velocity = new THREE.Vector3();
    let direction = new THREE.Vector3();
    let canJump = false;
    let prevTime = performance.now();
    let cubes = [], cubeVelocities = [];
    let heldCube = null;

    const speed = 150.0;
    const jumpVelocity = 75.0;
    const gravity = 9.8 * 50.0;
    const pickUpDistance = 2.0;
    const originalCubeScale = 1;
    const heldCubeScale = 0.5;
    const friction = 0.1; // Friction coefficient
    let pitch = 0, yaw = 0;

    init();
    animate();

    function init() {
        // Scene and camera setup
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.y = 1.6;

        // Renderer setup
        renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        // Ground
        const groundGeometry = new THREE.PlaneGeometry(50, 50);
        const groundMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
        const ground = new THREE.Mesh(groundGeometry, groundMaterial);
        ground.rotation.x = -Math.PI / 2;
        scene.add(ground);

        // Tangible cubes
        const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
        const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
        for (let i = 0; i < 3; i++) {
            const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
            cube.position.set(Math.random() * 30 - 15, 1.6, Math.random() * 30 - 15);
            cubes.push(cube);
            cubeVelocities.push(new THREE.Vector3());
            scene.add(cube);
        }

        // Event listeners for movement
        document.addEventListener('keydown', onKeyDown);
        document.addEventListener('keyup', onKeyUp);

        // Lock the mouse
        document.body.addEventListener('click', () => {
            document.body.requestPointerLock();
        });
        document.addEventListener('mousemove', onMouseMove);

        window.addEventListener('resize', onWindowResize);
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function onKeyDown(event) {
        switch (event.code) {
            case 'KeyW': moveForward = true; break;
            case 'KeyS': moveBackward = true; break;
            case 'KeyA': moveLeft = true; break; 
            case 'KeyD': moveRight = true; break;
            case 'Space':
                if (canJump) {
                    velocity.y = jumpVelocity;
                    canJump = false;
                }
                break;
            case 'KeyF':
                pickOrThrowCube();
                break;
        }
    }

    function onKeyUp(event) {
        switch (event.code) {
            case 'KeyW': moveForward = false; break;
            case 'KeyS': moveBackward = false; break;
            case 'KeyA': moveLeft = false; break; 
            case 'KeyD': moveRight = false; break;
        }
    }

    function onMouseMove(event) {
        if (document.pointerLockElement) {
            const sensitivity = 0.002;

            yaw -= event.movementX * sensitivity;
            pitch -= event.movementY * sensitivity;
            pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch));

            camera.rotation.y = yaw;
            camera.rotation.x = pitch;
            camera.rotation.z = 0; // Prevent rolling sideways
        }
    }

    function pickOrThrowCube() {
        if (heldCube) {
            // Throw the held cube
            const throwVelocity = new THREE.Vector3();
            camera.getWorldDirection(throwVelocity);
            throwVelocity.multiplyScalar(200); // Throw strength
            heldCube.position.add(throwVelocity.multiplyScalar(0.02));
            cubeVelocities[cubes.indexOf(heldCube)].copy(throwVelocity);
            heldCube.scale.set(originalCubeScale, originalCubeScale, originalCubeScale); // Reset cube scale
            heldCube = null;
        } else {
            // Pick up a cube if close enough and looking at it
            const raycaster = new THREE.Raycaster();
            raycaster.setFromCamera(new THREE.Vector2(0, 0), camera);
            const intersects = raycaster.intersectObjects(cubes);

            if (intersects.length > 0) {
                const intersect = intersects[0];
                if (intersect.distance < pickUpDistance) {
                    heldCube = intersect.object;
                    cubeVelocities[cubes.indexOf(heldCube)].set(0, 0, 0); // Stop the cube's movement
                    heldCube.scale.set(heldCubeScale, heldCubeScale, heldCubeScale); // Make the cube smaller
                    heldCube.position.copy(camera.position).add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5));
                }
            }
        }
    }

    function animate() {
        requestAnimationFrame(animate);

        // Update time
        const time = performance.now();
        const delta = (time - prevTime) / 1000;

        // Movement logic
        direction.z = Number(moveForward) - Number(moveBackward);
        direction.x = Number(moveRight) - Number(moveLeft);
        direction.normalize();

        velocity.x -= velocity.x * 10.0 * delta;
        velocity.z -= velocity.z * 10.0 * delta;
        velocity.y -= gravity * delta;

        if (moveForward || moveBackward || moveLeft || moveRight) {
            const frontDirection = new THREE.Vector3();
            camera.getWorldDirection(frontDirection);

            const rightDirection = new THREE.Vector3();
            rightDirection.crossVectors(camera.up, frontDirection).normalize();

            frontDirection.multiplyScalar(direction.z * speed * delta);
            rightDirection.multiplyScalar(direction.x * speed * delta);

            velocity.add(frontDirection).add(rightDirection);
        }

        camera.position.addScaledVector(velocity, delta);

        // Collision detection with barriers
        camera.position.x = Math.max(-24, Math.min(24, camera.position.x));
        camera.position.z = Math.max(-24, Math.min(24, camera.position.z));

        if (camera.position.y < 1.6) {
            velocity.y = 0;
            camera.position.y = 1.6;
            canJump = true;
        }

        // Update held cube position
        if (heldCube) {
            heldCube.position.copy(camera.position).add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1.5));
        }

        // Cube collision logic
        for (let i = 0; i < cubes.length; i++) {
            if (cubes[i] !== heldCube) {
                // Apply friction
                cubeVelocities[i].x *= (1 - friction);
                cubeVelocities[i].z *= (1 - friction);

                // Apply gravity to cubes
                cubeVelocities[i].y -= gravity * delta;
                cubes[i].position.addScaledVector(cubeVelocities[i], delta);

                // Cube collision with ground: stop bouncing
                if (cubes[i].position.y < 0.5) {
                    cubes[i].position.y = 0.5;
                    cubeVelocities[i].y = 0; // Stop upward velocity
                }

                // Simple cube interaction logic for pushing
                for (let j = 0; j < cubes.length; j++) {
                    if (i !== j) {
                        const distance = cubes[i].position.distanceTo(cubes[j].position);
                        if (distance < 1.5) { // If cubes are close enough
                            const collisionDirection = new THREE.Vector3().subVectors(cubes[i].position, cubes[j].position).normalize();
                            const relativeVelocity = new THREE.Vector3().subVectors(cubeVelocities[i], cubeVelocities[j]);
                            if (relativeVelocity.dot(collisionDirection) < 0) { // Only push if moving toward each other
                                const pushAmount = 0.02; // Adjust to control push force
                                cubeVelocities[i].add(collisionDirection.clone().multiplyScalar(pushAmount));
                                cubeVelocities[j].sub(collisionDirection.clone().multiplyScalar(pushAmount));
                            }
                        }
                    }
                }
            }
        }

        renderer.render(scene, camera);
        prevTime = time;
    }
</script>
</body>
</html>

Convert “Mon Feb 24 2025 05:17:41 GMT-0800 (PST)” to “Mon Feb 24 2025 05:17:41 GMT-0800 (IST)” format

Is there are a way by which I can convert from PST to IST format? PST should change to IST

“Mon Feb 24 2025 05:17:41 GMT-0800 (PST)” to “Mon Feb 24 2025 05:17:41 GMT-0800 (IST)” format

I tried the below but it didn’t work –

var lastWorkingDay = new Date(today);

gs.info(lastWorkingDay)//Giving an output as – Mon Feb 24 2025 09:02:42 GMT-0800 (PST)

var s = new Date(lastWorkingDay).toLocaleString(undefined, {timeZone: ‘Asia/Kolkata’});
gs.info(s); //not working

var date = new Date(lastWorkingDay);
gs.info(date.toString()); //not working

Regards,
Saurabh

How to reset the zoom given by the pinch to zoom gesture?

I am using a library to highlight an image, and this image has the property touch-action: auto;. However, when clicking the close button to close the highlighted image, the zoom applied by the “pinch to zoom” gesture remains. I would like to reset this zoom on mobile.

I tried something like this, but it didn’t work on iOS devices (Safari), and it also ends up limiting the zoom after the afterZoomOut function is called:

const viewportMetaTag = document.querySelector("meta[name=viewport]");

afterZoomIn={()=>viewportMetaTag?.setAttribute("content", "width=device-width, initial-scale=1.0, maximum-scale=10.0")}
afterZoomOut={()=>viewportMetaTag?.setAttribute("content", "width=device-width, initial-scale=1.0, maximum-scale=1.0")}

I also tried, but it didn’t have any effect on mobile:

document.body.style.scale = "1"

Owl Carousel 2 – Catch Largest Height For Each Slider

I’ve used ACF Pro to create a flexible page builder. On pages where there is more than one slider module in use, is it possible to automatically calculate the largest height of each slider rather than applying it to all slider modules on the page?

For example, at the moment if one slider has a height of 550 pixels it applies the same height to the other sliders on the page even if their content may have heights of 200 pixels and 300 pixels respectively.

Is it possible to apply a different height for each slider so there isn’t a big gap on the sliders that don’t have as much content?

                        
                    $button = get_sub_field('add_button');?>

                    <?php if (get_sub_field('margin_top') == 'yes' && get_sub_field('bg_colour_img') == 'colour') : ?>
                        <section class="slider" style="background-color: <?php the_sub_field('background_colour'); ?>; margin-top: 80px; padding: 80px 0;" id="<?php echo esc_html( get_sub_field('anchor_link') ); ?>">
                    <?php elseif (get_sub_field('margin_top') == 'no' && get_sub_field('bg_colour_img') == 'colour') : ?>
                        <section class="slider" style="background-color: <?php the_sub_field('background_colour'); ?>; padding: 80px 0;" id="<?php echo esc_html( get_sub_field('anchor_link') ); ?>">     
                    <?php elseif (get_sub_field('margin_top') == 'yes' && get_sub_field('bg_colour_img') == 'image' && get_sub_field('background_position') == 'left') : ?>
                        <section class="slider left" style="margin-top: 80px;" id="<?php echo esc_html( get_sub_field('anchor_link') ); ?>">
                    <?php elseif (get_sub_field('margin_top') == 'no' && get_sub_field('bg_colour_img') == 'image' && get_sub_field('background_position') == 'left') : ?>
                        <section class="slider left" id="<?php echo esc_html( get_sub_field('anchor_link') ); ?>">
                    <?php elseif (get_sub_field('margin_top') == 'yes' && get_sub_field('bg_colour_img') == 'image' && get_sub_field('background_position') == 'right') : ?>
                        <section class="slider right" style="margin-top: 80px;" id="<?php echo esc_html( get_sub_field('anchor_link') ); ?>">
                    <?php elseif (get_sub_field('margin_top') == 'no' && get_sub_field('bg_colour_img') == 'image' && get_sub_field('background_position') == 'right') : ?>
                        <section class="slider right" id="<?php echo esc_html( get_sub_field('anchor_link') ); ?>">
                    <?php endif; ?>
                            <div class="row" id="top">
                                <div class="inner">
                                    <?php if(get_sub_field('add_button') == 'no') { ?>
                                        <div class="col-6 no-gutters">
                                            <?php if( get_sub_field('heading') ): ?><h2><?php echo esc_html( get_sub_field('heading') ); ?></h2><?php endif; ?>
                                        </div>
                                        <div class="col-6 no-gutters">
                                            <?php if( get_sub_field('copy') ): ?><div class="copy"><span style="color: <?php the_sub_field('copy_colour'); ?>"><?php echo get_sub_field( 'copy') ?></span></div><?php endif; ?>
                                        </div>
                                    <?php } elseif(get_sub_field('add_button') == 'yes') { ?>
                                        <div class="col-4 no-gutters">
                                            <?php if( get_sub_field('heading') ): ?><h2><?php echo esc_html( get_sub_field('heading') ); ?></h2><?php endif; ?>
                                        </div>
                                        <div class="col-1 no-gutters">
                                        </div>
                                        <div class="col-4 no-gutters">
                                            <?php if( get_sub_field('copy') ): ?><div class="copy"><span style="color: <?php the_sub_field('copy_colour'); ?>"><?php echo get_sub_field( 'copy') ?></span></div><?php endif; ?>
                                        </div>  
                                        <div class="col-3 no-gutters">
                                            <?php if(get_sub_field('new_tab') == 'yes') { ?>
                                                <?php if( get_sub_field('button_url') ): ?><div class="read-more"><a href="<?php echo esc_url( get_sub_field('button_url') ); ?>" target="_blank"><?php if( get_sub_field('button_text') ): ?><span class="btn blue-button"><?php the_sub_field('button_text'); ?> <i class="fas fa-chevron-right"></i></span><?php endif; ?></a></div><?php endif; ?>
                                            <?php } elseif(get_sub_field('new_tab') == 'no') { ?>
                                                <?php if( get_sub_field('button_url') ): ?><div class="read-more"><a href="<?php echo esc_url( get_sub_field('button_url') ); ?>" target="_blank"><?php if( get_sub_field('button_text') ): ?><span class="btn blue-button"><?php the_sub_field('button_text'); ?> <i class="fas fa-chevron-right"></i></span><?php endif; ?></a></div><?php endif; ?>
                                            <?php } ?> 
                                        </div> 
                                    <?php } ?> 
                                </div>
                            </div>
                            <div class="row" id="bottom">
                                <div class="inner">
                                    <div class="col-12 no-gutters">
                                        <div class="owl-carousel owl-theme">
                                            <?php
                                            if( have_rows('slides') ): ?>
                                                <?php
                                                while( have_rows('slides') ): the_row(); ?>
                                                    <div class="item" style="background-color: <?php the_sub_field('background_colour'); ?>;">
                                                        <?php if(get_sub_field('icon_image') == 'image') { ?>
                                                            <?php if( get_sub_field('image') ): ?><img src="<?php the_sub_field('image'); ?>" /><?php endif; ?>
                                                                <div class="owl-inner">
                                                                    <?php if( get_sub_field('heading') ): ?><span class="heading" style="color: <?php the_sub_field('heading_colour'); ?>"><?php the_sub_field('heading'); ?></span><?php endif; ?>
                                                                    <?php if( get_sub_field('heading_two') ): ?><span class="heading" id="two" style="color: <?php the_sub_field('heading_colour'); ?>"><?php echo esc_html( get_sub_field('heading_two') ); ?></span><?php endif; ?>
                                                                    <?php if( get_sub_field('copy') ): ?><span class="copy"> <?php the_sub_field('copy'); ?></span><?php endif; ?>
                                                                </div>
                                                                <?php if( get_sub_field('button_url') ): ?>
                                                                    <?php if(get_sub_field('new_tab') == 'yes') { ?>
                                                                        <a href="<?php echo esc_url( get_sub_field('button_url') ); ?>" target="_blank"><span class="btn blue-button"><?php the_sub_field('button_text'); ?> <i class="fas fa-chevron-right"></i></span></a>
                                                                    <?php } elseif(get_sub_field('new_tab') == 'no') { ?>
                                                                        <a href="<?php echo esc_url( get_sub_field('button_url') ); ?>"><span class="btn blue-button"><?php the_sub_field('button_text'); ?> <i class="fas fa-chevron-right"></i></span></a>
                                                                    <?php } ?>  
                                                                <?php endif; ?>
                                                        <?php } elseif(get_sub_field('icon_image') == 'icon') { ?>
                                                            <div class="owl-inner">
                                                                <?php if( get_sub_field('icon') ): ?><img class="icon" src="<?php the_sub_field('icon'); ?>" /><?php endif; ?>
                                                                <?php if( get_sub_field('heading') ): ?><span class="heading" style="color: <?php the_sub_field('heading_colour'); ?>"><?php the_sub_field('heading'); ?></span><?php endif; ?>
                                                                <?php if( get_sub_field('heading_two') ): ?><span class="heading" id="two" style="color: <?php the_sub_field('heading_colour'); ?>"><?php echo esc_html( get_sub_field('heading_two') ); ?></span><?php endif; ?>
                                                                <?php if( get_sub_field('copy') ): ?><span class="copy"> <?php the_sub_field('copy'); ?></span><?php endif; ?>
                                                            </div>
                                                            <?php if( get_sub_field('button_url') ): ?>
                                                                <?php if(get_sub_field('new_tab') == 'yes') { ?>
                                                                    <a href="<?php echo esc_url( get_sub_field('button_url') ); ?>" target="_blank"><span class="btn blue-button"><?php the_sub_field('button_text'); ?> <i class="fas fa-chevron-right"></i></span></a>
                                                                <?php } elseif(get_sub_field('new_tab') == 'no') { ?>
                                                                    <a href="<?php echo esc_url( get_sub_field('button_url') ); ?>"><span class="btn blue-button"><?php the_sub_field('button_text'); ?> <i class="fas fa-chevron-right"></i></span></a>
                                                                <?php } ?>  
                                                            <?php endif; ?>
                                                        <?php } ?> 
                                                    </div>
                                                <?php endwhile; ?>
                                            <?php endif; ?>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </section>  


<script>
    function setProdTiles()
    {
    var prodTileH = 0; // set variable to catch largest height
    jQuery(".owl-inner").each(function(){
        H = jQuery(this).outerHeight(); // height current productTile
        if (H > prodTileH) // get highest
            {
            prodTileH = H;
            }
    });
    jQuery(".owl-inner").outerHeight(prodTileH);
    }

window.addEventListener("load", setProdTiles);
window.addEventListener("resize", setProdTiles);
</script>


In Vue 3, how can I watch changes to the array structure without marking it as `deep` and having every nested level watched?

I have this component code originally written in Vue 2 using the options API that is now being migrated to Vue 3. The code was simplified to the following where items are added/removed from the array and then the watcher is called to do other things (in this case just console.log):

<template>
  <button @click="addItem">Add</button>
  <button @click="removeItem">Remove</button>
  <br><br>
  <div>Items:</div>
  <div v-for="item in items">{{item}}</div>
</template>

<script>
export default {
  data() {
    return {
      items: [],
    };
  },
  watch: {
    items: {
      handler() {
        console.log('items', this.items);
      },
      //deep: true
    }
  },
  methods: {
    addItem() {
      this.items.push({i: this.items.length});
    },
    removeItem() {
      this.items.pop();
    }
  }
};
</script>

This worked fine in Vue 2 where the items watcher would fire each time an item is added/removed from the array. My actual object has far more attributes on it than just i, so if I mark the watcher with deep: true, the watcher fires as expected, but the view becomes unusably slow. How can I make this array.

I noticed if I change the addItem method to this.items = [...this.items, {i: this.items.length}];, then the watcher gets called as I would expect, but this also seems really inefficient since you’re creating a new array each time. Is there another way to get the watcher to run only on push/pop/unshift/shift/splice calls that modify the existing array’s structure without having to reassign the array reference or mark the array as deep?