The wire:on event is triggered and rolled back

The event occurs, the text changes, but immediately returns to the previous state (I went through the debugger, it will change for a moment). Where to look and what I don’t understand. I use livewire 3.

Component code

public function change($clientId)
    {
        $this->dispatch('changeText', $clientId);
    }

Component template

<h1 id="target-text">Old Text</h1>

<button wire:click="change({{ $client->id }})">Press</button>

@script
<script>
    $wire.$on('changeText', () => {
      const oldText = document.getElementById('target-text');
      oldText.innerText = 'New Text';
    });
</script>
@endscript

I expect it, but not…

<h1 id="target-text">New Text</h1>

How do I end all animations on their last frame?

I’ve been struggling to get this button to start all my animations at the same time. After a lot of trial and error, I managed to get it working. However, when I watched how it played out, my elements weren’t aligned, and the animation didn’t stop when I added ‘animation-fill-mode: forwards’.

Struggles:

  1. Align the image and loading text in the center and position the image above the loading text.

  2. Make the button onclick trigger the image and loading text, starting all animations until you reach the chapter selection.

  3. Resolve the annoying flickering of the chapter text.

  4. Ensure everything stops at the last frame instead of stopping at the first.

Feel free to assist the worst coder on earth. <3

Alignment: I’ve tried various methods, including creating divs, using display flex and grids, employing position absolute, and every imaginable technique. However, whenever I manage to get one part working, it seems to make it worse at other parts of the code.

Animation: Despite trying almost everything I could find online and reaching out to teachers and chatbots, no one seems to have a solution. I experimented with ‘animation-fill-mode: forwards,’ but it didn’t yield the desired results. Unfortunately, that’s pretty much the extent of my knowledge on the matter, my brain is very tiny.

Chapter Text: I attempted to address the flickering issue when the chapter text fades in. Surprisingly, shortening the text to “Chap” instead of “Chapter” seemed to resolve the problem, first try. However, upon refreshing the page, the flickering returned, GRRRR.

Start Button: I haven’t given this issue as much love as the other issues. I tried using a solid black image with a z-index of -5 and an animation that set “0% = z-index: -5,” “99% = z-index: -5,” and “100% = z-index: 3.” This approach failed, I decided to “Get the milk”.

https://www.youtube.com/watch?v=7kBien8OL0w <— Menu music


HappyErotisk
<—

* {
    text-align: center
}
a {
    text-decoration: none;
    color: white;
    font-size: 200%;
    font-family: cursive;
    text-align: center;
    z-index: 1;
}

a:hover {
    color: gray;
}

div.middle {
    position: absolute;
    display: grid;
    margin: auto;
    animation-fill-mode:forwards;
    animation: fadein 10s;
    z-index: 2;
}


body {
    background-color: rgb(0, 0, 0);
    overflow: hidden;
    position: relative;
}

h1 {
    color: darkred;
}

h2.fadeout {
    color: white;
    z-index: 1;
    animation-fill-mode: forwards;
    margin: 10% auto;
    position: relative;
}
/* 
div {
    display: flex;
    justify-content: center;
    align-items: center;
} */


div.divbox {
    margin: auto;
    width: 70%;
    aspect-ratio: 16/9;
    display: flex;
    border: 5px solid white;
    justify-content: center;
    align-items: center;
    z-index: 1;
    position: relative;
    height: 70vh;
}

div.load {
    animation-fill-mode: forwards;
    position: relative;
    margin-top: 20%;
}


div.divboxx {
    display: grid;
    justify-content: center;
    align-items: center;
    animation-fill-mode: forwards;
    margin-top: -20%;
    position: absolute;
    z-index: 2;
    top: 50%;
    left: 50%;
}

#erotic {
    width: 80%;
    aspect-ratio: 1/1;
    display: grid;
    justify-content: center;
    align-items: center;
    animation-fill-mode: forwards;
}

img {
    aspect-ratio: 1/1;
    width: 100%;
}

.helix {
    z-index: 1;
    margin: auto;
}


@keyframes spinner {
    0% {transform: rotateY(0deg); opacity: 100%;}
    50% {transform: rotateY(-900deg); opacity: 100%;}
    75% {transform: rotateY(-1350deg); opacity: 0%;}
    100% {transform: rotateY(-1800deg); opacity: 0%;}
}



@keyframes fadeout {
    0% {opacity: 100%; left: auto; right: auto;}
    50% {opacity: 100%; left: auto; right: auto;}
    75% {opacity: 0%; left: auto; right: auto;}
    100% {opacity: 0%; left: 100%; right: auto;}
}

@keyframes fadein {
    0% {opacity: 0%; left: 50%; right: 50%;}
    75% {opacity: 0%; left: 50%; right: 50%;}
    100% {opacity: 100%; left: 50%; right: 50%;}
}

button {
    margin: auto;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
<audio id="sound1" src="menymusic.mp3" preload="auto"></audio>
<button onclick="document.getElementById('sound1').play(); ani();">Play</button>
  
    <div class="divbox">
        
        <div class="divboxx">
            <img id="erotic" src="Happyerotisk.png" class="helix">    
        </div>
        <div class="load">
            <h2  id="loading" class="fadeout">Loading</h2>
        </div>
       
        <div id="chapter" class="middle">
                <a href="../Kapitel1/Index.html">Chapter 1</a>
                <a href="../Kapitel2/Index.html">Chapter 2</a>
                <a href="../Kapitel3/Index.html">Chapter 3</a>
        </div>  
    </div>
<script>
        function ani() {
    //Get All
    var erotic = document.getElementById("erotic");
    var loading = document.getElementById("loading");
    var chapter = document.getElementById("chapter");

    //Start animation
    triggerAnimation(erotic, 'spinner 10s linear');
    triggerAnimation(loading, 'fadeout 10s linear');
    triggerAnimation(chapter, 'fadein 10s linear');
    }

    function triggerAnimation(element, animation) {
    element.style.animation = 'none';
    element.offsetHeight;
    element.style.animation = animation;
    }
</script>
</body>
</html>

Trying to dynamically render a background of stars in Vue with Rive Animations

I am currently attempting to create a background for my website I am building using Vue. I have created small star animations in Rive and turned those animations into Vue Components. I am trying to now dynamically render these stars in the background of my website to make a nice space background. However, with my current implementation, it only draws one of the stars and puts it in the top left of the page instead of randomizing the position. The method to draw the static stars in a canvas works, but generating the dynamic stars made from Vue components is where the issue lies.

My current implementation attempts to create a container that takes up the full height and width of the current page, then it creates a list of star components with randomized locations, and finally, it attempts to loop through those star lists and render them in the background. Here is the page where all of this is happening:

<template>
  <div class="page-container">
    <!-- Canvas Background -->
    <canvas ref="spaceCanvas" class="background-canvas"></canvas>

    <!-- Rive Stars Containers -->
    <div class="stars-container">
      <div class="normal-stars">
        <NormalStar v-for="star in normalStars" :key="star.id" :style="{ top: star.y + 'px', left: star.x + 'px' }" />
      </div>
      <div class="purple-stars">
        <PurpleStar v-for="star in purpleStars" :key="star.id" :style="{ top: star.y + 'px', left: star.x + 'px' }" />
      </div>
      <div class="orange-stars">
        <OrangeStar v-for="star in orangeStars" :key="star.id" :style="{ top: star.y + 'px', left: star.x + 'px' }" />
      </div>
    </div>

    <!-- Overlaying Content -->
    <div class="content-overlay">
      <main>
        <!-- This router view shows the main pages (Created in router/index.js) -->
        <router-view />
      </main>
      <footer>
        <!-- Vertical Spacing -->
        <div class="vertical-spacing"></div>
        <div class="vertical-spacing"></div>
        <!-- Footer -->
        <div class="container d-flex flex-column gap-4 col-6 align-items-center">
          <div class="d-flex gap-4">
            <LinkedIn />
            <Github />
            <Indeed />
            <Instagram />
          </div>
          <p>Created by <b>Justice Gooch</b></p>
          <Earth />
        </div>
      </footer>
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";

// Icons
import Github from "./components/icons/github.vue";
import LinkedIn from "./components/icons/linkedin.vue";
import Indeed from "./components/icons/indeed.vue";
import Instagram from "./components/icons/instagram.vue";

// Illustrations
import Earth from "./components/static-illustrations/Earth.vue";
import PurpleStar from "./components/rive-illustrations/PurpleStar.vue";
import NormalStar from "./components/rive-illustrations/NormalStar.vue";
import OrangeStar from "./components/rive-illustrations/OrangeStar.vue";

// Refs for normal, purple, and orange stars
const normalStars = ref([]);
const purpleStars = ref([]);
const orangeStars = ref([]);

const spaceCanvas = ref(null);

onMounted(() => {
  const canvas = spaceCanvas.value;
  const ctx = canvas.getContext('2d');

  // Set canvas width and height to match the content height
  canvas.width = document.body.scrollWidth;
  canvas.height = document.body.scrollHeight;

  // Handle window resize
  window.addEventListener("resize", () => {
    // Set canvas width and height to match the content height
    canvas.width = document.body.scrollWidth;
    canvas.height = document.body.scrollHeight;
    // Redraw stars on resize
    drawStars();
    generateStars();
  });

  // Function to draw background stars
  function drawStars() {
    const numberOfStars = 100;
    for (let i = 0; i < numberOfStars; i++) {
      const x = Math.random() * canvas.width;
      const y = Math.random() * canvas.height;
      const radius = Math.random() * 1.5;
      const alpha = Math.random();

      ctx.beginPath();
      ctx.arc(x, y, radius, 0, Math.PI * 2, false);
      ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
      ctx.fill();
    }
  }

  // Function to generate star positions for each category
  function generateStars() {
    function generateStarCoordinates(count) {
      const starsArray = [];
      for (let i = 0; i < count; i++) {
        starsArray.push({
          id: i,
          x: Math.random() * document.body.scrollWidth,
          y: Math.random() * document.body.scrollHeight,
        });
      }
      return starsArray;
    }

    debugger;
    // Populate the stars arrays
    normalStars.value = generateStarCoordinates(150);
    purpleStars.value = generateStarCoordinates(10);
    orangeStars.value = generateStarCoordinates(10);
  }

  // Initial drawing of stars and generation of Rive stars
  drawStars();
  generateStars();
});
</script>

<style scoped>
.page-container {
  position: relative;
  overflow: hidden;
}

.background-canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
}

.stars-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;

  pointer-events: none;
}

.normal-stars,
.purple-stars,
.orange-stars {
  position: absolute;
}

.content-overlay {
  position: relative;
  z-index: 2;
}
</style>

And for example, here is one of my star components (that appear to work correctly by themselves):

<template>
  <canvas id="riveNormalStar" class="star-canvas" width="18" height="18"></canvas>
</template>

<script setup>

import * as rive from "@rive-app/canvas";
import {onMounted} from "vue";

onMounted(() => {
  const r = new rive.Rive({
    src: 'src/assets/rive/portfolio.riv',
    canvas: document.getElementById("riveNormalStar"),
    autoplay: true,
    artboard: "Normal Star",
    animations: ["Timeline 1"],
    onLoad: () => {
      r.resizeDrawingSurfaceToCanvas();
    },
  });
})

</script>

<style scoped>
  .star-canvas {
    width: 18px;
    height: 18px;
  }
</style>

Based on testing, and the fact that at least one of the stars appears, I believe the issue has to be an issue with the logic I am using to generate the list of stars and show them using the v-for loop. Does anyone see anything that could be causing this?

How can I remove an item from the current cart using Velo in Wix?

Product:
Wix Editor

Hi,
I am building a custom cart page where I successfully list all the items in the current cart using a repeater. Each item has a delete button, and I need assistance in removing an item from the cart when this button is clicked.

Based on the updated Velo documentation, I understand that I should use the removeLineItemsFromCurrentCart() API to remove items. However, I’m facing issues retrieving the current cart data. When attempting to use the API, I receive an error message saying that the cart owner could not be found.

Could you please guide me on how to resolve this issue? How can I properly remove an item from the current cart, especially when the user is not logged in?

The error message I recieve:

“”Error: message: ‘Cart not found: Cannot find cart by ownership’
details:
applicationError:
description: Cannot find cart by ownership
code: OWNED_CART_NOT_FOUND
data: {}”

Additional information:
This is the code I have.

–cart.web.js–

`import wixData from 'wix-data';
import { currentUser } from 'wix-users-backend';
import { Permissions, webMethod } from "wix-web-module";
import { currentCart } from "wix-ecom-backend";
import { getCurrentCart } from 'wix-stores-backend';


export const myRemoveLineItemsFromCurrentCartFunction = webMethod(
  Permissions.Anyone,
  async (lineItemIds) => {
    try {
      const updatedCurrentCart =
        await currentCart.removeLineItemsFromCurrentCart(lineItemIds);
      console.log("Success! Line items removed from cart:", updatedCurrentCart);
      return updatedCurrentCart;
    } catch (error) {
      console.error(error);
      // Handle the error
    }
  },
);

—Front Page—-

`
import { myRemoveLineItemsFromCurrentCartFunction } from “backend/cart.web.js”;

$item(“#deleteItemButton”).onClick(() => {

                        console.log("Butona tıklandı.");

                        try {
                            wixData.query('AddToCartInformation')
                                .eq('productID', itemData.productID)
                                .eq('timestamp', itemData.timestamp)
                                .eq('userID', wixUsers.currentUser.id)
                                .find().then((results) => {
                                    if (results.items.length > 0) {
                                        console.log("Veri bulundu:", results.items[0]);

                                    } else {
                                        throw new Error("Ürün bulunamadı");
                                    }

                                    const productIdToUpdateCart = results.items[0].productID;
                                    const quantityToUpdateCart = results.items[0].quantity;
                                    console.log("Product ID: " + productIdToUpdateCart + "Product Quantity: " + quantityToUpdateCart);

                                    getCurrentCart()
                                        .then((cart) => {
                                            console.log("Sepet:", cart);
                                            // Sepet boş mu dolu mu kontrol et
                                            if (cart.lineItems.length > 0) {
                                                // Sepet bilgilerini göster
                                                cart.lineItems.forEach(item => {
                                                    console.log(`Ürün: ${item.name}, Adet: ${item.quantity}`);
                                                    console.log("İtem id: ", item.productId);

                                                    compareProductQuantities(productIdToUpdateCart, quantityToUpdateCart,
                                                        item.productId, item.quantity);
                                                    //removeProductFromCurrentCart(item.productId);

                                                    // Sample lineItemIds array:
                                                    const lineItemIds = [
                                                        results.items[0].productID,
                                                    ];

                                                    
                                                    console.log(cart._id);

                                                   
                                                    myRemoveLineItemsFromCurrentCartFunction(lineItemIds)
                                                        .then((updatedCurrentCart) => {
                                                            
                                                            console.log("Success! Line items removed from cart:", updatedCurrentCart);
                                                            return updatedCurrentCart;
                                                            
                                                        })
                                                        .catch((error) => {
                                                            console.error(error);
                                                            // Handle the error
                                                        });
                                                });
                                            } else {
                                                console.log("Sepet boş");
                                            }

                                        })
                                        .catch((error) => {
                                            console.error("Sepet alınamadı:", error);
                                        });

                                })

                        } catch (error) {
                            console.log(error);
                        }

                    });

`

Intermediate points in a line chart in Apache echartJS?

I am trying to find intermediate points between two points connected by a line in a line chart using Apache EChartsJS.

`https://jsfiddle.net/fnxzb2cq/2/

Here when you hover over the point, the value shows up as an alert. But I am looking for values for intermediate points which are interpolated .e.g, in the graph above, when I hover over the line corresponding to the point 15 in the x-axis, it should alter value of ~ 175.

Is this possible through echart’s API or do we need to create a custom fit line and then do the calculations in a different function and just display the results of the function while it hovers?

Thanks.

How to set elements back to relative after keeping it on fixed

https://codepen.io/BlazgoCompany/pen/dyBBRLp

I am trying to make a website with lots of scroll animations (the text has been masked). The first animation with the zooming in star works very well, but the second animation doesn’t work. It plays the animation like normal, but once it is done, it doesn’t go back to the regular scrolling. It should also continue with the text below it after the animation is done.

I am pretty sure I need to set it to relative but can’t seem to get it to work.

Also, please do not suggest using ScrollTrigger because it will not stay on CodePen forever, and I do not want to get Club GSAP.

I am unable to use Stack Snippets for some reason so here’s the full code:

<div class="top-right">
    <span class="cta-login">
        <button class="my-dash btn-base">Lorem Ipsum</button>
    </span>
</div>
<div class="nav">
    <span class="logo">
        <!-- Logo Placeholder -->
    </span>
    <span class="cta-login">
        <button class="login btn-base" onclick="openModal()">Login</button>
    </span>
</div>
<div class="hero">
    <h1 class="hero-text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
</div>
<div class="content">
    <small class="subtitle">Sed do eiusmod tempor incididunt.</small>
    <h2 style="margin-bottom: 0">
        <span class="brand gradient teal text">Lorem.</span>
        <span class="brand gradient blue text">Ipsum.</span>
    </h2>
    <h2 class="brand gradient red text">Dolor Sit Amet.</h2>
    <p style="color: #999">Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <span class="highlight">Ut enim</span> ad minim veniam, quis nostrud <span class="highlight">exercitation</span> ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    <button class="getstarted">Get Started</button>
    <div class="spacer-240"></div>
    <h1 class="tw-heading gray">Placeholder Heading</h1>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4>Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4>Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4>Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    <div class="gen-card">
        <h2>Placeholder Title</h2>
        <h4 class="anim brand red text">Placeholder Subtitle</h4>
        <p>Placeholder text for description.</p>
    </div>
    This text should appear after this scroll animation (but it doesn't!)
</div>

@import url('https://fonts.googleapis.com/css?family=Nunito:200,200i');
    @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500');
    @import url('https://fonts.googleapis.com/css?family=Varela+Round');

    /* Import fonts */
    /* Global Styles */
    body {
        background: black;
        overflow-x: hidden;
        min-height: 800vh;
        margin: 0;
        font-family: sans-serif;
        /* Fallback font */
    }

    input {
        padding: 12px;
        width: 80%;
        border-radius: 8px;
        border: none;
        left: 50%;
        position: relative;
        transform: translate(-50%);
        margin-top: 42px;
    }

    .hero {
        padding: 16px;
        position: fixed;
        width: 100%;
        height: 100vh;
        background: radial-gradient(circle at 0% -10%, var(--gradient-color), transparent 38%);
    }

    .hero-text {
        color: white !important;
        font-size: 64px;
        font-family: "Varela Round", sans-serif;
        /* Default to Varela Round, fallback to sans-serif */
        display: inline-block;
        position: relative;
        z-index: 10;
    }

    .hero-text svg {
        transform: translateY(-4px);
        display: inline;
        vertical-align: middle;
        background-color: transparent;
    }

    .content {
        color: white;
        display: none;
        font-family: "Varela Round";
        text-align: center;
    }

    .highlight {
        color: #e3b505;
    }

    .btn-base,
    .modal .login,
    .backbtn {
        border-radius: 20px;
        border: none;
        padding: 0 12px;
        height: 30px;
        background: #e3b505;
        font-size: 16px;
        font-weight: bold;
    }

    .btn-base:hover,
    .modal .login:hover,
    .backbtn:hover {
        background: #c8a104;
    }

    .getstarted {
        padding: 8px 16px;
        border-radius: 32px;
        height: auto;
    }

    .nav {
        position: fixed;
        top: -36px;
        background: radial-gradient(circle at 0% center, #066ab2, transparent 80%);
        backdrop-filter: blur(8px);
        width: calc(100% - 32px);
        height: 36px;
        z-index: 1000;
        left: 50%;
        transform: translate(-50%, 0);
        max-width: 500px;
        border-radius: 32px;
    }

    button:active {
        transform: scale(0.9)
    }

    button {
        transition: transform 0.1s;
    }


    .btncontainer {
        margin-top: 48px;
        left: 50%;
        position: relative;
        transform: translate(-50%);
        display: inline-block;
    }

    .btn-close {
        position: absolute;
        right: 8px;
        top: 8px;
        width: 32px;
        height: 32px;
        background: #95190C;
        color: white
    }

    .btn-close:hover {
        background: #711409;
    }

    .loader {
        height: 24px;
        width: 24px;
        border: 3px solid transparent;
        border-bottom: 3px solid black;
        border-radius: 32px;
        animation: spin 1s linear infinite;
    }

    @keyframes spin {
        0% {
            transform: rotate(0deg);
        }

        100% {
            transform: rotate(360deg);
        }

    }

    .login-modal h1 {
        font-size: 24px;
        font-weight: bold;
        text-align: center;
        margin-bottom: -20
    }

    .brand.gradient.teal.text {
        background: #107E7D;
        background: -webkit-linear-gradient(#28E2DF, #0C5A59);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .brand.gradient.blue.text {
        background: #066AB1;
        background: -webkit-linear-gradient(#89CBFB, #05528A);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .brand.gradient.blue.extra {
        background: #066AB1;
        background: -webkit-linear-gradient(#C4E5FD, #05528A);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .brand.gradient.red.text {
        margin-top: 0;
        background: #971A0C;
        background: -webkit-linear-gradient(#F6877B, #711409);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    h2 {
        font-size: 32px;
    }

    .subtitle {
        font-size: 14px;
        background: -webkit-linear-gradient(#eee, #3f3f3f);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .subtitle::after,
    .subtitle::before {
        content: '';
        width: 64px;
        height: 1px;
        display: inline-block;
    }

    .subtitle::before {

        transform: translate(-8px, -4px);
        background: linear-gradient(-90deg, #aaa 0%, transparent 100%);
        right: 120%;
        top: 50%;
    }

    .subtitle::after {
        transform: translate(8px, -4px);
        background: linear-gradient(90deg, #aaa 0%, transparent 100%);
        left: 120%;
        top: 50%;
    }

    h1.gray.tw-heading {
        font-size: 48px;
        background: -webkit-linear-gradient(#eee, #333);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    }

    .spacer-240 {
        height: 240px;
    }

    .gen-card {
        width: calc(25% - 14px);
        margin: 0 4px;
        display: inline-block;
        height: 360;
        background: transparent;
        backdrop-filter: blur(4px);
        opacity: 0;
        border-radius: 16px;
        text-align: center;
        padding: 12px;
        border: 1px solid #555
    }

    .gen-card h2 {
        margin: 0;
    }

    .fixed {
        position: fixed;
    }
    .relative{
        position: relative;
    }

    /* .anim.brand.red.text{
        margin-top: 0;
        background: #971A0C;
        background: -webkit-linear-gradient(#F6877B, #711409);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
    } */

    function setTransformOriginToChild() {
        const parent = document.querySelector('.hero-text');
        const child = document.querySelector('.hero-text .star');

        const parentRect = parent.getBoundingClientRect();
        const childRect = child.getBoundingClientRect();

        const childCenterX = (childRect.left - 10 + childRect.right) / 2;
        const childCenterY = (childRect.top + 4 + childRect.bottom) / 2;

        const transformOriginX = (childCenterX - parentRect.left) / parentRect.width * 100;
        const transformOriginY = (childCenterY - parentRect.top) / parentRect.height * 100;

        parent.style.transformOrigin = `${transformOriginX}% ${transformOriginY}%`;
    }



    window.addEventListener('resize', setTransformOriginToChild);


    
    // Function to split text into multiple spans
    function splitTextIntoSpans() {
        // Get the container element
        const container = document.querySelector('.hero-text');

        // Get the text content of the container
        const text = container.textContent;

        // Create a document fragment to hold the new span elements
        const fragment = document.createDocumentFragment();

        // Define words to style
        const wordsToStyle = {
            'future': '#066AB2',
            'sit': '#066AB2'
        };

        // Helper function to create span elements for text
        function createSpansForText(text, color = '') {
            const fragment = document.createDocumentFragment();
            for (let char of text) {
                const span = document.createElement('span');
                span.textContent = char;
                if (color) {
                    span.classList.add("brand")
                    span.classList.add("gradient")
                    span.classList.add("blue")
                    span.classList.add("text")
                    span.classList.add("extra")
                }
                fragment.appendChild(span);
            }
            return fragment;
        }

        // Process the text letter by letter
        let index = 0;
        while (index < text.length) {
            // Find the next word or space
            let nextSpace = text.indexOf(' ', index);
            if (nextSpace === -1) {
                nextSpace = text.length;
            }

            var word = text.slice(index, nextSpace);

            // Add a space character after the word
            if (nextSpace < text.length) {
                word += ' ';
            }

            // Create spans for each letter of the word
            const color = wordsToStyle[word.trim()] || '';
            const wordFragment = createSpansForText(word, color);
            fragment.appendChild(wordFragment);

            // If the word  add a special span element after it
            if (word.trim() === 'sit') {
                const starSpan = document.createElement('span');
                starSpan.className = 'star';
                starSpan.innerHTML = `
      <svg width="32" height="24">
        <path d="M 2 12 q 10 0 10 -10 q 0 10 10 10 q -10 0 -10 10 q 0 -10 -10 -10 M 0 12 A 1 1 0 0 0 24 12 A 1 1 0 0 0 0 12"></path>
      </svg>`;
                fragment.appendChild(starSpan);
            }

            // Move to the next word
            index = nextSpace + 1;
        }

        // Clear the original container
        container.textContent = '';

        // Append the fragment to the container
        container.appendChild(fragment);
    }
    function calculateTravelDistance() {
        // Get the .star element
        const starElement = document.querySelector('.hero-text .star');

        // Get the bounding rectangle of the .star element
        const starRect = starElement.getBoundingClientRect();

        // Get the center of the .star element
        const starCenterX = starRect.left + starRect.width / 2;
        const starCenterY = starRect.top + starRect.height / 2;

        // Get the center of the screen
        const screenCenterX = window.innerWidth / 2;
        const screenCenterY = window.innerHeight / 2;

        // Calculate the amount to move the element
        const moveX = screenCenterX - starCenterX;
        const moveY = screenCenterY - starCenterY;

        return { moveX, moveY };
    }
    // Call the function to split the text
    window.addEventListener('load', () => {
        splitTextIntoSpans();
        setTransformOriginToChild()
        tl = gsap.timeline({
        })
        tl.set(".hero-text span", { filter: "blur(32px)" })
        tl.set(".hero", { "--gradient-color": "#FFD700" })
        tl.set(".hero-text svg", { fill: "white" })
        tl.to(".hero-text span", { filter: "blur(0px)", duration: 0.5, stagger: 0.05 })
        tl.to(".top-right", { opacity: 0, duration: 0.8 }, "<+=1.2")
        tl.to(".hero-text", { y: calculateTravelDistance().moveY, x: calculateTravelDistance().moveX, duration: 3, fill: "black", ease: "power4.in" }, "+=0.5")
        tl.to(".hero-text", { scale: 90, duration: 3, ease: "power4.in" }, "<")
        tl.to(".hero-text svg", { duration: 1, fill: "black", background: "transparent" }, "-=1")
        tl.to(".hero", { duration: 1, "--gradient-color": "#000" }, "-=1")
        tl.to(".nav", { duration: 1, top: "16px" }, "-=1")
        tl.pause(0.5)
    });
    var gentlmarker = 1000000
    var gentl = 0
    document.addEventListener("scroll", () => {
        //get scroll position
        const scrollPosition = window.scrollY;
        if ((scrollPosition / 200) + 0.5 < 5.8) {
            gsap.set(".hero", { display: "block" })
            gsap.set(".content", { display: "none" })
            tl.pause((scrollPosition / 200) + 0.5)
        }
        else {
            gsap.set(".hero", { display: "block" })
            gsap.set(".content", { display: "none" })
            tl.pause((scrollPosition / 200) + 0.5)
            gsap.set(".hero", { display: "none" })
            gsap.set(".content", { position: "relative", top: 1060 + window.innerHeight, display: "block" })
        }
        if(document.querySelector(".tw-heading").getBoundingClientRect().top < 200 && scrollPosition > 1800){
            //"pin" the tw-heading and the gencards for 300 px of scrolling
            gsap.set(".tw-heading", {position: "fixed", top: 200-32, left: "50%", xPercent: -50, width: "100%"})
            gc = document.querySelectorAll(".gen-card")
            gcw = gc[0].getBoundingClientRect().width
            gsap.set(".gen-card", {position: "fixed", opacity: 1, top: 264, right: -gcw})
            gentl=gsap.timeline({})
            // gentl.to(gc[0], {position: "fixed", top: 264, left: 8})
            // gentl.to(gc[1], {position: "fixed", top: 264, left: 8+gcw+8})
            // gentl.to(gc[2], {position: "fixed", top: 264, left: 8+gcw+8+gcw+8})
            // gentl.to(gc[3], {position: "fixed", top: 264, left: 8+gcw+8+gcw+8+gcw+8})
            

            // Common properties for the animation
            const commonProps = {
                position: "fixed",
                top: 264
            };

            // Define the start position and end positions for gc elements
            const startPosition = -200;
            const endPositionFirst = -gcw;
            const endPositionLast = 32;

            // Create a timeline animation with stagger
            gentl.to(gc, {
                ...commonProps,
                left: endPositionFirst,
                stagger: 0.2, // Stagger by 0.1 seconds for each element
                duration: 1,  // Adjust duration to your preference
                ease: "power1.inOut" // Example easing function
            })
            .to(gc[gc.length - 1], {
                left: endPositionLast,
                duration: 1, // Same duration as above to keep consistency
                ease: "power1.inOut" // Use the same easing function
            }, "-=1")
            .to(gc[3], {
                width: "50%",
                left: "50%",
                x: "-50%",
                duration: 1, // Same duration as above to keep consistency
                ease: "power1.inOut" 
            })
            .addLabel("fgenfocus")
            .to(gc[3].querySelector("h2"), {
                opacity: 0
            }, "fgenfocus")
            .to(gc[3].querySelector("h2"), {
                opacity: 0,
                height: "0px",
                margin: 0
            }, "fgenfocus")
            .add(function(){
              gc[3].querySelector("h4").innerHTML="Now the th scrolling should continue as normal"
            }, "fgenfocus")
            .to(gc[3].querySelector("h4"), {
                fontSize: "32px",
                margin: 0
            }, "fgenfocus")


            // gentl.to([gc[0], gc[1], gc[2]], {width: 0})
            gentl.pause()
            gentlmarker = scrollPosition
            

        }
        if(scrollPosition>gentlmarker){
            gc = document.querySelectorAll(".gen-card")
            gcw = gc[0].getBoundingClientRect().width
            
            console.log(gentlmarker)
            console.log((scrollPosition-gentlmarker)/300)
            console.log("----------------")
            gentl.pause((scrollPosition-gentlmarker)/300)
        }

        if((scrollPosition-gentlmarker)/300 < 0){
            gsap.set(".tw-heading", {position: "static", xPercent: 0})
            gsap.set(".gen-card", { opacity: 0 })
        }
       

    })




    







    document.querySelector(".getstarted").addEventListener("click", () => {
        let clickTl = gsap.timeline({})
        clickTl.to(".getstarted", { scale: 100, duration: 2, ease: "power4.in" })
        clickTl.to(".getstarted", { background: "black", color: "black", duration: 1, ease: "power4.in" }, "-=1")
    })

Thanks!

How to access data in Proxy(Object) in app.js Vue3 sent by Inertia::share

I am using Laravel with Inertia/Vue3.
In my app.js file

import './bootstrap';

import { createInertiaApp, Head, Link, usePage } from '@inertiajs/vue3';
import { createApp, h, computed } from 'vue';
import { ZiggyVue } from '../../vendor/tightenco/ziggy';
import Layout from './Layouts/GuestLayout.vue';

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';


console.log(usePage());

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: name => {
      const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
      let page = pages[`./Pages/${name}.vue`]
      page.default.layout = name.startsWith('Public/') ? undefined : (page.default.layout || Layout)
      return page
    },
    setup({ el, App, props, plugin }) {
        return createApp({ render: () => h(App, props) })
            .use(plugin)
            .component('Head', Head)
            .component('Link', Link)
            .use(ZiggyVue)
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
})

in console i see my data but I cannot find a way to access it

console.log information of usePage()

I need to check if I have authorised user to use Authenticated Layout for pages or Guest Layout if don’t have auth.user.

I tried toRaw from ‘vue’, but I don’t find way to access this data.

Hiding/showing a sidebar with a grid design – Script not working

I’m trying to show/hide a sidebar within a grid. I’ve a working script for this which works fine on a plain vanilla html document, but used in conjunction with grid, it doesn’t.
Here are the relevant parts of the CSS:

#body {
  min-height: 100vh;
  display: grid;
  grid-template-rows: 60px 1fr auto;
  grid-template-columns: 300px auto;
  grid-template-areas: 'menubtn header '
'sidebar content'
'footer footer';
}
#menubtn {
  grid-area: menubtn;
}
#header {
  grid-area: header;
  background-color: white;
}
#sidebar {
  grid-area: sidebar;
  background-color: white;
}
#content {
  grid-area: content;
}
#footer {
  grid-area: footer;
  background-color: white;
}
.hide {
  position: absolute;
  top: 10000px;
  left: 10000px;
  z-index: -1;

}
and here is the script:

   <script>
   const sts = document.querySelector("#status");
   sts.innerHTML = "Initializing....";
  const wireUp = ()=> {
   sts.innerHTML = "Wiring Up..";  // verified running it..
   const btn = document.querySelector("#toggle-button");
   if (!btn) sts.innerHTML = "No toggle button found!"
   else {
       btn.addEventListener("click", ()=>{
           // sts.innerHTML = "clicked..."; // verified clicked
           const sideBar = document.querySelector("#sidebar");
           if (!sideBar)  {
               sts.innerHTMl = "Error sidebar not found.";
               return;
           }
           if (btn.innerHTML.toLowerCase().search("hide") > -1) {
               sideBar.setAttribute("aria-hidden", "true")
               sideBar.classList.add("hide");
               btn.innerHTML = "Show Menu";
               sts.innerHTML = "Hiding menu";
           }else {
               sideBar.setAttribute("aria-hidden", "false")
               sideBar.classList.remove("hide");
               btn.innerHTML = "HideMenu";
               sts.innerHTML = "Showing menu";
           }
       } )
   }
   }
   </script>

Ideally, I’d like it to disappear and for the content to occupy the extra space, but it would be nice if its status could be passed on to subsequent pages. In PHP, I could store something in $_SESSION, but JS and I aren’t friends yet, so not sure whether this kind of thing is possible.
Any help welcomed.

How to deploy local langflow bot?

Local langflow bot

if you have worked with langflow, then you might have used this local interface provided by langflow but the problem is, it works only when you are running the langflow server locally, how can i use this interface without running langflow locally?

enter image description here

how can i change this URL to use the cloud version of langflow on the datastax instead of running langflow locally?

I tried using the datastax url of the flow but that did not seem to work

How long would it take to exhaust integers up to MAX_SAFE_INTEGER?

I found that searching for this answer confusing and not well documented.

In JavaScript you have a MAX_SAFE_INTEGER defined as 2^53 - 1

I did discover an article that put such large numbers into perspective however they focus on 2^64. And JS uses a smaller number. Most birthday paradox calculators lack the ability to scale to that number.

Why is this interesting? I found myself debating with developers about the use of a UUID(v4) for unique IDs in their web apps. By comparison a monotonic counter globally used in a single web app would have an entire 2^53 - 1 space of unique values per tab session. I’m interested in understanding the trade off of the exhaustion of values for a monotonic counter compared to the collision probability of UUIDv4.

Cookies not working in Safari iOS, but works in Android and Desktop

I have an AppScript web app that uses cookies to store if a user is “Registered”. If that’s the case it lets the user use a Cupon. The app works fine when used in Android and desktop browsers. But when using it with an iPhone (mobile Safari) it stops working correctly.

Here’s how the cookie setting and reading works:

function getCookie(cname) {
            let name = cname + "=";
            let decodedCookie = decodeURIComponent(document.cookie);
            let ca = decodedCookie.split(';');
            for (let i = 0; i < ca.length; i++) {
                let c = ca[i];
                while (c.charAt(0) == ' ') {
                    c = c.substring(1);
                }
                if (c.indexOf(name) == 0) {
                    return c.substring(name.length, c.length);
                }
            }
            return "";
        }

        function setCookie(cname, cvalue, exdays) {
            const d = new Date();
            d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
            let expires = "expires=" + d.toUTCString();
            document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
        }

And here’s how the cookies are used:

switch (action) {
                case "register":
                    if (userid) {
                        setCookie(STORAGE_KEY, userid, 1)
                        $('#success').html(`<i class="bi bi-person-check-fill"></i> Te has registrado con el usuario: <b>${userid}</b>`);
                        $('#success').show();
                    } else {
                        setCookie(STORAGE_KEY, "", 1)
                        $('#error').html(`<i class="bi bi-exclamation-circle-fill"></i> No se pudo registrar el usuario.`);
                        $('#error').show();
                    }
                    break;

                case "checkin":
                    var regUserid = getCookie(STORAGE_KEY);
                    if (!regUserid) {
                        $('#error').html(`<i class="bi bi-exclamation-circle-fill"></i> Debes registrarte para fichar.`);
                        $('#error').show();
                    } else {
                        $('#loader').show();
                        google.script.run
                            .withSuccessHandler(function (ret) {
                                $('#loader').hide();
                                if (ret === false) {
                                    $('#error').html(`<i class="bi bi-exclamation-circle-fill"></i> El cupón ya existe. No puedes fichar de nuevo con el mismo cupón.`);
                                    $('#error').show();
                                } else {
                                    $('#success').html(`<i class="bi bi-alarm"></i> ${ret}<br/><b>${control}</b>: ${regUserid}`);
                                    $('#success').show();
                                }
                            })
                            .withFailureHandler(function (err) {
                                $('#error').html(`<i class="bi bi-exclamation-circle-fill"></i> Se ha producido un error: ${err}`);
                                $('#loader').hide();
                                $('#error').show();
                            })
                            .checkin(regUserid, control);
                    }
                    break;

                default:
                    var regUserid = getCookie(STORAGE_KEY);
                    if (!regUserid) {
                        $('#error').html(`<i class="bi bi-exclamation-circle-fill"></i> Debes registrarte para fichar.`);
                        $('#error').show();
                    } else {
                        $('#success').html(`<i class="bi bi-person-badge"></i> Estás registrad@ como <b>${regUserid}</b>`);
                        $('#success').show();
                    }
                    break;
            }

JS Hooks not working in Arabic RTL WordPress

in this wordpress website the english products autoplay the videos yet in arabic they arent loaded.

see links below
English

https://omniastores.com/product/omnia-maram-white-full-set-accessories-in-high-quality-simulated-diamonds/

Arabic Same product

https://omniastores.com/ar/product/%d8%a3%d9%85%d9%86%d9%8a%d9%87-%d9%85%d8%b1%d8%a7%d9%85-%d9%88%d8%a7%d9%8a%d8%aa-%d9%85%d8%ac%d9%85%d9%88%d8%b9%d8%a9-%d9%83%d8%a7%d9%85%d9%84%d8%a9-%d9%85%d9%86-%d8%a7%d9%84%d8%a5%d9%83%d8%b3%d8%b3/

i kept debugging and found out the JS function isnt working properly

(function($) {
    'use strict';
    woodmartThemeModule.$document.on('wdReplaceMainGallery', function() {
        woodmartThemeModule.productVideoGallery();
    });

    $.each([
        'frontend/element_ready/wd_single_product_gallery.default'
    ], function(index, value) {
        woodmartThemeModule.wdElementorAddAction(value, function() {
            woodmartThemeModule.productVideoGallery();
        });
    });

Please help

Questions on data passing within react JS

I’m not new to react but I’m also not super experienced and I wanted to ask some opinions about the proper ways to pass around data

Now the current project we’ve been working on has redux and I’ve been told not to use it and I will admit to a point that redux has been abused put the point where even local states have been put into redox and it’s ridiculous

So those refactoring that’s going to be done for this project I’m working on in one question always comes to mind that I struggle with is how to pass data between sibling components ends if there’s any rules against how deep you can pass data down within components.

  1. So for the first one I guess the question is is if you have a component that has five sibling components, And let’s imagine that one of those components set some kind of data from like a network call how can you return that and pass it along to the sibling components? I think my first assumption would be to pass back some state or call back to the parent and then how the parent do it from there but I’m not sure if that’s the only best way.

  2. My other question concerned about passing data within components right so let’s say we have a parent sibling and I need to pass down a prop with data 5 components deep Is that an appropriate pattern or is it shamed upon? As an alternative I have seen the producer context consumer pattern that reacts has and I guess is this a case for that or is there some kind of rules of when that would be the best time to use?

  3. And just for the sake of completion, Is there any type of rules or better patterns or better practices to know when to use passing down props versus redux versus producer content consumer?

Thanks everyone

My War project isn’t giving the proper amount of cards and forces a tie, why?

I’ve moved on from my calculator project, and I’m now making a webpage with the card game War. However, I’ve encountered a problem: When I test it out, it says that the two players both only have 1 card. When I click “Draw” to draw the cards, it just says there’s a tie. The suit images aren’t appended properly either.

I’ve tried rearranging things, defining variables that were previously defined in-function at the top alongside the other variables, and checking the console log for errors. None of these worked however.
Here’s my code, if it turns out to be a typo or a redundant command like last time (or something that can’t be reproduced), I’m sorry.
HTML:

<html>
<head>
<title>War</title>
<link href="resources/css/style.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" href="resources/images/favicon.ico" type="image/x-icon">
<link rel="icon" href="resources/images/favicon.ico" type="image/x-icon">
</head>
<body>
<div id="gameboard" class="flex">
<div class="flexColumn">
<h1>War</h1>
<h2 id="winner">Winner</h2>
<h3>Player 1 has <span id="player1cards"></span> cards.</h3>
<h3>Player 2 has <span id="player2cards"></span> cards.</h3>
</div>
<div class="flex">
    <div id="player1" class="flexColumn player">
        <h2>Player 1</h2>
        <div id="player1number" class="number">
        </div>
        <div id="player1suit" class="suit">
        </div>
    </div>
<h2 id="draw">Draw</h2>
<div id="player2" class="flexColumn player">
    <h2>Player 2</h2>
    <div id="player2number" class="number">
    </div>
    <div id="player2suit" class="suit">
    </div>
   </div>
  </div>
 </div>
</div>
<script type="text/javascript" src="resources/js/jquery.js"></script>
<script type="text/javascript" src="resources/js/script.js"></script>
</body>
</html>

JS:

var $player1 = $("#player1");
var $player1number = $("#player1number");
var $player1suit = $("#player1suit");
var $player2 = $("#player2");
var $player2number = $("#player2number");
var $player2suit = $("#player2suit");
var $draw = $("#draw");
var $winner = $("#winner");
var cards = [];
var $player1cards = $("#player1cards");
var $player2cards = $("#player2cards");
var number1=$player1[0][0];
var number2=$player2[0][0];
var suit1=$player1[0][1];
var suit2=$player2[0][1];


cards.shuffle = function() {
    console.log("shuffle");
    var input = this;
    for (var i = cards.length-1; i >=0; i--) {
        var randomIndex = Math.floor(Math.random()*(i+1));
        var itemAtIndex = cards[randomIndex][0];
        var itemAtSecond = cards[randomIndex][1];
        input[randomIndex][0] = input[i][0];
        input[randomIndex][1] = input[i][1];   
    }
    return input;
}

cards.shuffle();

var half = cards.length/2;
for (i=0; i<half; i++) {
    $player1.push(cards[i]);
}

cards.splice(0, half);

player2 = cards;
$player1cards.html($player1.length);
$player2cards.html($player2.length);


$draw.on('click', function() {
    $player1suit.empty();
    $player2suit.empty();
    $player1number.html(number1);
    $player2number.html(number2);
    if (suit1 == 1) {
        suit1 = "<img src = 'resources/images/heart.png'/>";
    }
    if (suit1 == 2) {
        suit1 = "<img src = 'resources/images/diamond.png'/>";
    }
    if (suit1 == 3) {
        suit1 = "<img src = 'resources/images/club.png'/>";
    }
    if (suit1 == 4) {
        suit1 = "<img src = 'resources/images/spade.png'/>";
    }
    if (suit2 == 1) {
        suit2 = "<img src = 'resources/images/heart.png'/>";
    }
    if (suit2 == 2) {
        suit2 = "<img src = 'resources/images/diamond.png'/>";
    }
    if (suit2 == 3) {
        suit2 = "<img src = 'resources/images/club.png'/>";
    }
    if (suit2 == 4) {
        suit2 = "<img src = 'resources/images/spade.png'/>";
    }

    playedCards = [];
    $player1cards.html($player1.length);
    $player2cards.html($player2.length);
    
for (i=0; i<number1; i++) {
    $player1suit.append(suit1);
}

for (i=0; i<number2; i++) {
    $player2suit.append(suit2);
}

playedCards.push($player1[0]);
playedCards.push($player2[0]);

$player1.splice(0,1);
$player2.splice(0,1);

if (number1 > number2) {
    $winner.html("Player 1 wins");
    for (i=0; i<playedCards,length; i++) {
       $player1.push(playedCards[i]);
    } 
     } if (number2 > number1) {
        $winner.html("Player 2 wins");
        for (i=0; i<playedCards.length; i++) {
        player2.push(playedCards[i]);       
        }
        } if (number1 == number2) {       
        $winner.html("This means war!");      
        for (i=0; i<3; i++){        
        playedCards.push(player1[0]);
        playedCards.push(player2[0]);
        $player1.splice(0,1);        
        $player2.splice(0,1);
        }
        $player1suit.css("display", "none");
        $player2suit.css("display", "none");      
        numberImg1 = "<img style='height:14rem;' src='resources/images/card.png'/>";
        $player1number.html(numberImg1);
        numberImg2 = "<img style='height:14rem;' src='resources/images/card.png'/>";
        $player2number.html(numberImg2);
}
});


for (i = 1; i < 14; i++) {
    cards.push(i);
    }

    for (i = 1; i < 14; i++) {  
        for (k = 1; k < 5; k++) { 
         j = [i, k];                   
         cards.push(j);
        } 
       }

       if (number1<11) {

        for (i=0; i<number1; i++) {
        $player1suit.append(suit1);
        };
        
        } else {
        if (number1 == 11) {
        numberImg1 = "<img src='resources/images/jack.png'/>";
        $player1suit.append(suit1);
        $player1number.html(numberImg1);
      }

        if (number1 == 12) {
        numberImg1 = "<img src='resources/images/queen.png'/>";
        $player1suit.append(suit1);
        $player1number.html(numberImg1);
      }
        if (number1 == 13) {
        numberImg1 = "<img src='resources/images/king.png'/>";
        $player1suit.append(suit1);
        $player1number.html(numberImg1);
    }    
    }
    if (number2<11){

        for (i=0; i<number2; i++) {
        $player2suit.append(suit2);
        };
        
        } else {
        if (number2 == 11) {
        numberImg2 = "<img src='resources/images/jack.png'/>";
        $player2suit.append(suit2);
        $player2number.html(numberImg2);
      }

        if (number2 == 12) {
        numberImg2 = "<img src='resources/images/queen.png'/>";
        $player2suit.append(suit2);
        $player2number.html(numberImg2);
      }
        if (number2 == 13) {
        numberImg2 = "<img src='resources/images/king.png'/>";
        $player2suit.append(suit2);
        $player2number.html(numberImg2);
    }    
    }

And of course, a screenshot or two (ignore the “Layout forced before page was fully loaded” warning):
A screenshot before clicking “Draw”
A screenshot after clicking “Draw”