Vue3 Routing, Deal with ID not found for blog article

I want to write a lightwight blog in vue3.

I used a simple undefined check and router.push to redirect when a blog-post was not found in the data… but this seems nasty…also my post object is potentialy undefined which forces me to use post?. in my template….

There has to be a more vue-ish way to make my desired behaviour work – any suggestions?

Currently my routing is setup up as:

const routes: Array<RouteRecordRaw> = [
  { path: '/', component: BlogTimelineView },
  { path: '/posts/:id', component: BlogPostView },
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFoundView },
];

A click on the timeline router link passes the id to the blogpost-view and I use dummy data to check if a post for that id was found:

<script lang="ts" setup>

import { useRoute } from 'vue-router';
import posts from '@/data/posts.json';
import { Ref, ref } from 'vue';
import router from '@/router';

interface Post {
    id: string;
    title: string;
    type: string;
    link: string;
    date: string;
    content?: string;
    description?: string;
    version?: string;
}

const route = useRoute();
const post: Ref<Post | undefined> = ref(undefined);

// # TODO: replace with async call to fetch post data
post.value = posts.find((post) => post.id === route.params.id);
post.value === undefined && router.push('/404')

</script>

<template>
    <div class="blog-post">
        <h1>{{ post?.title }}</h1>
        <p>{{ post?.content }}</p>
        Post-ID {{ $route.params.id }}

    </div>
</template>

Appriciate your help

Cheers
David

Chrome extension, adding instance to global scope such as window on Instagram.com seems futile

So, I am trying to script some stuff against instagram, but I’ve noticed that Instagram is somehow able to clear access to any variable or instance put on window.aaa, or window.document.aaa or window.document.documentElement.aaa or window.addEventEventListener.aaa will eventually all disappear.

When I set any of these properties, I am able to verify that:

a) things execute where I set things
b) things are set on the property

However, some vodoo magic is happening and I’ve first encountered it on Instagram, and one Bank website.

Instances, wherever they are set on, will all become inaccessible eventually.

My first question is, how do they pull it off? Is there some kind of listener they are utilizing to ensure things not set by them somehow is cleared.

Second question is, are there any known ways around this?

You can easily try this by installing Custom Javascript Extension and enable jquery for Instagram.com but it will not become available on the window object.

JavaScript code for web-based audio player application designed to play live radio streams doesnt work on iphone and mozilla firefox

In WordPress with Hello Elementor, Elementor and Elementor Pro I wrote a custom web-based audio player to play live radio stream but it doesnt work on iphone and Mozilla firefox in all devices.
I tried many things but nothing works. When I switch off enhanced protection off it works. Can someone help me?

(function () {
    const el = {
        'timer': '#timer .elementor-heading-title',
        'duration': '#duration .elementor-heading-title',
        'loading': '#loading',
        'playBtn': '#playBtn',
        'pauseBtn': '#pauseBtn',
        'backward': '#backward',
        'forward': '#forward',
        'bar': '#bar',
        'progress': '#progress',
        'tracker': '#tracker',
        'volBar': '#volBar',
        'volBarPerc': '#volBarPerc',
        'volTracker': '#volTracker',
        'mute': '#mute i',
        'htmlAudio': '#html-audio',
        'live': '#live'
    };

    const elems = {};
    Object.keys(el).forEach((key) => {
        elems[key] = document.querySelector(el[key]);
    });

    /**
     * Radio class containing the state of our stations.
     * Includes all methods for playing, stopping, etc.
     * @param station object with station details ({title, src, howl, ...}).
     */
    var Radio = function (station) {
        var self = this;

        self.station = station;
        self.vol = 1;
        self.duration = 0;
        self.playing = false;

        self.loadtime = 0;

        setInterval(function () {
            var f = self.updateDuration();
        }, 1000);
    };

    Radio.prototype = {

        /**
         * Play a station.
         */
        play: function () {
            var self = this;
            var sound;
            var data = self.station;

            // If we already loaded this track, use the current one.
            // Otherwise, setup and load a new Howl.
            if (data.howl) {
                data.howl.play();

            } else {
                self.newHowl();

                self.station.howl.load();
                self.station.howl.volume(0, self.sid);
                self.sid = self.station.howl.play();
                self.station.howl.seek(0, self.sid);
            }

            self.playing = true;

            // Show the pause button.
            if (data.howl.state(self.sid) === 'loaded') {
                elems.playBtn.style.display = 'none';
                elems.pauseBtn.style.display = 'flex';
            } else {
                elems.loading.style.display = 'flex';
                elems.playBtn.style.display = 'none';
                elems.pauseBtn.style.display = 'none';
            }
        },

        newHowl: function () {
            var self = this;
            self.station.howl = new Howl({
                src: self.station.src, // + '?dt=' + Date.now().toString(),
                html5: true, // A live stream can only be played through HTML5 Audio.
                ext: ['mp3'],
                format: ['mp3'],
                preload: false,
                autoplay: true,
                onplay: function () {
                    // Start updating the progress of the track.
                    requestAnimationFrame(self.step.bind(self));
                    elems.pauseBtn.style.display = 'flex';
                },
                onload: function () {
                    elems.loading.style.display = 'none';
                },
                onpause: function () {
                    requestAnimationFrame(self.step.bind(self));
                },
                onstop: function () {
                },
                onseek: function () {
                    // Start updating the progress of the track.
                    requestAnimationFrame(self.step.bind(self));
                }
            });
        },

        updateDuration: function () {

            var self = this;
            var sound = self.station.howl;

            if (!sound) {
                return -1;
            }
            console.log(sound.state(self.sid));
            if (sound.state(self.sid) === 'loading') {
                self.loadtime++;
            }
            if (sound.state(self.sid) !== 'loaded') {
                elems.loading.style.display = 'flex';
                elems.playBtn.style.display = 'none';
                elems.pauseBtn.style.display = 'none';

                if (sound.state(self.sid) !== 'loading' || self.loadtime > 5) { // || self.duration > 0) {
                    console.log("new")
                    self.station.howl.unload(self.sid);
                    // self.station.howl = null;
                    //
                    // self.newHowl();
                    self.duration = 0;
                    self.loadtime = 0;
                    self.station.howl.load();
                    self.sid = self.station.howl.play();
                    self.station.howl.volume(0, self.sid);
                    self.station.howl.seek(0, self.sid);
                    self.playing = true;

                }
                return 0;
            }

            elems.loading.style.display = 'none';
            if (self.playing) {
                elems.playBtn.style.display = 'none';
                elems.pauseBtn.style.display = 'flex';
            } else {
                elems.playBtn.style.display = 'flex';
                elems.pauseBtn.style.display = 'none';
            }

            self.duration++;
            self.station.howl.volume(self.vol, self.sid);

            return 1;
        },

        /**
         * Pause the currently playing track.
         */
        pause: function () {
            var self = this;

            // Get the Howl we want to manipulate.
            var sound = self.station.howl;

            if (!sound) return;

            // Puase the sound.
            sound.pause(self.sid);

            self.playing = false;

            // Show the play button.
            elems.playBtn.style.display = 'flex';
            elems.pauseBtn.style.display = 'none';
        },

        goLive: function () {
            var self = this;

            var sound = self.station.howl;

            if (!sound) return;

            var s = self.duration - 1;
            if (s < 0) s = 0;

            sound.seek(s, self.sid);
        },

        jump: function (direction) {
            var self = this;

            var sound = self.station.howl;

            if (!sound) return;

            var jump = 10

            if (direction === 'backward') {
                jump *= -1
            }

            var newSeek = sound.seek(self.sid) + jump;

            if (newSeek < 0) {
                newSeek = 0;
            }

            if (newSeek > self.duration) {
                newSeek = self.duration - 1;
                if (newSeek < 0) newSeek = 0;
            }

            if (sound.state() === 'loaded') {
                sound.seek(newSeek, self.sid);
            }
        },

        /**
         * Stop a station's live stream.
         */
        stop: function () {
            var self = this;

            // Get the Howl we want to manipulate.
            var sound = self.station.howl;

            if (!sound) return;

            // Stop the sound.
            if (sound) {
                sound.unload(self.sid);
            }
        },

        /**
         * Set the volume and update the volume slider display.
         * @param  {Number} val Volume between 0 and 1.
         */
        volume: function (val) {
            var self = this;

            if (!self.station.howl) return;

            // Update the display on the slider.
            elems.volBarPerc.style.width = (val * 100) + '%';
            elems.volTracker.style.left = (val * 100) + '%';

            if (val === 0) {
                elems.mute.classList.remove("player-fill-volume");
                elems.mute.classList.add("player-fill-mute");

                self.volSave = self.station.howl.volume(self.sid);
                if (self.volSave < 0.1) self.volSave = 0.1;

            } else {
                elems.mute.classList.remove("player-fill-mute");
                elems.mute.classList.add("player-fill-volume");
            }


            // Update the global volume (affecting all Howls).
            self.station.howl.volume(val, self.sid);
            self.vol = val;
        },

        mute: function () {
            var self = this;
            if (!self.station.howl) return;

            if (self.station.howl.volume(self.sid) === 0) {
                self.volume(self.volSave);
            } else {
                self.volume(0);
            }
        },

        /**
         * Seek to a new position in the currently playing track.
         * @param  {Number} per Percentage through the song to skip.
         */
        seek: function (per) {
            var self = this;

            // Get the Howl we want to manipulate.
            var sound = self.station.howl;

            if (!sound) return;

            // Convert the percent into a seek position.
            //if (sound.playing()) {
            var newSeek = self.duration * per;

            if (self.duration - newSeek < 2) {
                newSeek = self.duration - 1;
            }
            if (newSeek < 0) newSeek = 0;
            sound.seek(newSeek, self.sid);
            //}
        },

        /**
         * The step called within requestAnimationFrame to update the playback position.
         */
        step: function () {
            var self = this;

            // Get the Howl we want to manipulate.
            var sound = self.station.howl;

            if (sound) {
                var seek = sound.seek(self.sid) || 0;


                // if (self.duration > 0){ // && sound.state() === "loaded" && seek <= self.duration) {
                // Determine our current seek position.
                var perc = ((seek / self.duration) * 100) || 100;
                var diff = self.duration - seek;
                var timertxt = '';

                if (diff < 0) {
                    seek = self.duration - 1;
                    if (seek < 0) seek = 0;
                    sound.seek(seek, self.sid);

                    perc = 100;
                    elems.live.classList.add('now');
                } else if (diff < 2) {
                    perc = 100;
                    elems.live.classList.add('now');
                } else {
                    elems.live.classList.remove('now');
                    timertxt = '- ' + self.formatTime(Math.round(diff))
                }

                elems.timer.innerHTML = timertxt;
                elems.duration.innerHTML = self.formatTime(Math.round(self.duration));

                if (!window.trackerDown) {
                    elems.progress.style.width = perc.toString() + '%';
                    elems.tracker.style.left = perc.toString() + '%';
                }
                // }
            }


            // If the sound is still playing, continue stepping.
            //if (sound.playing()) {
            requestAnimationFrame(self.step.bind(self));
            //}
        },

        /**
         * Format the time from seconds to M:SS.
         * @param  {Number} secs Seconds to format.
         * @return {String}      Formatted time.
         */
        formatTime: function (secs) {
            var minutes = Math.floor(secs / 60) || 0;
            var seconds = (secs - minutes * 60) || 0;

            return minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
        }

    };

    window.trackerDown = false;
    window.volTrackerDown = false;
    window.trackerPerc = 0;

    // Setup our new radio and pass in the stations.
    var player = new Radio(
        {
            freq: '100.6',
            title: "Nostos Radio",
            src: 'https://rdst.win:48051', // + Date.now().toString(), 'https://neos.win:37878/stream?type=.mp3',
            howl: null
        }
    );


    // Bind our player controls.

    // Main Buttons

    elems.playBtn.addEventListener('click', function () {
        player.play();
    });
    elems.pauseBtn.addEventListener('click', function () {
        player.pause();
    });

    elems.live.addEventListener('click', function () {
        player.goLive();
    });

    elems.backward.addEventListener('click', function () {
        player.jump('backward');
    });

    elems.forward.addEventListener('click', function () {
        player.jump('forward');
    });


    // Progress Bar

    function getPercent(event, bar) {
        let x = event.clientX || event.touches[0].clientX;
        let barRect = bar.getBoundingClientRect();
        let per;
        if (x < barRect.left) {
            per = 0;
        } else if (x > barRect.left + barRect.width) {
            per = 1;
        } else {
            per = (x - barRect.left) / barRect.width;
        }

        return per;
    }


    elems.bar.addEventListener('mousedown', function (event) {
        if(!player.station.howl) return;
        window.trackerPerc = getPercent(event, elems.bar);
        // player.seek(per);
        window.trackerDown = true;
        elems.progress.style.width = (window.trackerPerc * 100).toString() + '%';
        elems.tracker.style.left = (window.trackerPerc * 100).toString() + '%';
    });

    elems.tracker.addEventListener('mousedown', function () {
        if(!player.station.howl) return;
        window.trackerDown = true;
        elems.progress.style.width = (window.trackerPerc * 100).toString() + '%';
        elems.tracker.style.left = (window.trackerPerc * 100).toString() + '%';
    });
    elems.tracker.addEventListener('touchstart', function () {
        if(!player.station.howl) return;
        window.trackerDown = true;
        elems.progress.style.width = (window.trackerPerc * 100).toString() + '%';
        elems.tracker.style.left = (window.trackerPerc * 100).toString() + '%';
    });

    // Volume

    elems.mute.addEventListener('click', function () {
        player.mute();
    });

    // Set up the event listeners to enable dragging of volume slider.
    elems.volBar.addEventListener('mousedown', function (event) {
        let per = getPercent(event, elems.volBar);
        player.volume(per);
        window.volTrackerDown = true;
    });

    elems.volTracker.addEventListener('mousedown', function () {
        window.volTrackerDown = true;
    });
    elems.volTracker.addEventListener('touchstart', function () {
        window.volTrackerDown = true;
    });


    // Move Bars

    window.addEventListener('mouseup', function () {
        if(!player.station.howl) return;
        if (window.trackerDown) {
            player.seek(window.trackerPerc);
        }
        window.trackerDown = false;
        window.volTrackerDown = false;
    });
    window.addEventListener('touchend', function () {
        if(!player.station.howl) return;
        if (window.trackerDown) {
            player.seek(window.trackerPerc);
        }
        window.trackerDown = false;
        window.volTrackerDown = false;
    });

    var move = function (event) {
        if(!player.station.howl) return;

        if (window.trackerDown) {
            window.trackerPerc = getPercent(event, elems.bar);
            elems.progress.style.width = (window.trackerPerc * 100).toString() + '%';
            elems.tracker.style.left = (window.trackerPerc * 100).toString() + '%';
            // player.seek(per);
        }

        if (window.volTrackerDown) {
            let per = getPercent(event, elems.volBar);
            player.volume(per);
        }
    };

    window.addEventListener('mousemove', move);
    window.addEventListener('touchmove', move);

})();
</script>

Horozontal scrolling divs not duplicating the content and only the surrounding div

I have a pen that has a smooth horizontal scrolling of images in a div but it is only cloning the surrounding div and not the IMG or content in the div.

<style>
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  position: relative;
}
.horizontal-scrolling-banner div img {
  max-height:250px;
}
.horizontal-scrolling-banner {
  overflow: hidden;
}

.horizontal-scrolling-banner__helper-wrapper {
  align-items: center;
  display: flex;
  left: 0;
  transform: translateZ(0);
  transition-property: left;
  transition-timing-function: linear;
}
</style>
<div class="horizontal-scrolling-banner">
  <div><img src="/wp-content/uploads/2024/02/BL_BLCL-lifestyle-phone.jpg"></div>
  <div><img src="/wp-content/uploads/2024/02/BL_BLCL_lifestyle-dining.jpg"></div>
  <div><img src="/wp-content/uploads/2024/02/LakelandVillageCenter_Coffee.jpg"></div>
<div><img src="/wp-content/uploads/2024/02/BL_BLCL-Lifestyle-farmersmarket.jpg"></div>
</div>
<script >
(function horizontalScrollingBanner() {
  var banners = document.getElementsByClassName('horizontal-scrolling-banner');
  if (!banners || banners.length === 0) {
    return;
  }
  var pxPerSecond = 50;
  setUpElements();
  scrollTheBanners();
  window.addEventListener('resize', setUpElements);

  function setUpElements() {
    for (var i = 0; i < banners.length; i++) {
      var currentBanner = banners[i];
      var helperWrapperClass = 'horizontal-scrolling-banner__helper-wrapper';
      var currentHelperWrapper = currentBanner.querySelector('.' + helperWrapperClass);
      if (currentHelperWrapper) {
        var clones = currentHelperWrapper.querySelectorAll('[data-clone]');
        Array.prototype.forEach.call(clones, function(clone) {
          clone.remove();
        });
        var childrenCount = currentHelperWrapper.children.length;
        for (var i = 0; i < childrenCount; i++) {
          currentBanner.appendChild(currentHelperWrapper.children[0]);
        }
        currentHelperWrapper.remove();
      }

      var children = currentBanner.children;

      var bannerWidth = currentBanner.getBoundingClientRect().width;
      var minWidthToCoverBanner = (bannerWidth * 2) + children[0].getBoundingClientRect().width;
      var childrenWidth = Array.prototype.reduce.call(children, function(r, child) {
        return r + child.getBoundingClientRect().width;
      }, 0);
      var currentWidth = childrenWidth;


      do {
        Array.prototype.forEach.call(children, function(child) {
          var clone = child.cloneNode();
          clone.setAttribute('aria-hidden', true);
          clone.dataset.clone = true;
          currentBanner.appendChild(clone);
        });
        currentWidth += childrenWidth;
      } while (currentWidth < minWidthToCoverBanner);

      var transitionHelperWrapper = document.createElement('div');
      transitionHelperWrapper.classList.add('horizontal-scrolling-banner__helper-wrapper');
      var childrenCount = children.length;
      for (var i = 0; i < childrenCount; i++) {
        transitionHelperWrapper.appendChild(children[0]);
      }
      currentBanner.appendChild(transitionHelperWrapper);
      transitionHelperWrapper.dataset.childrenWidth = childrenWidth;
    }
  }

  function scrollTheBanners() {
    for (var i = 0; i < banners.length; i++) {
      var helperWrapper = banners[i].firstElementChild;
      var childrenWidth = helperWrapper.dataset.childrenWidth;
      var offsetLeft = helperWrapper.offsetLeft;

      if (offsetLeft <= (childrenWidth * -1)) {
        helperWrapper.style.transitionDuration = '0s';
        helperWrapper.style.left = '0px';
        helperWrapper.style.removeProperty('transition-duration');
      } else if (helperWrapper.style.left === '' || helperWrapper.style.left === '0px') {
        setTimeout(function() {
          helperWrapper.style.transitionDuration = (childrenWidth / pxPerSecond).toFixed() + 's';
          helperWrapper.style.left = (childrenWidth * -1) + 'px';
        }, 0);
      }
    }
    requestAnimationFrame(scrollTheBanners);
  }
})();
    </script>

This is a functioning pen of the issue I am having.

https://codepen.io/abennington/pen/QWPxqyq

Any help is greatly appreciated as to what I have done wrong. 🙂

Get upload speed from socket io

I am using socket io to upload a file as a buffer to the server. This process works, but I want to get the upload speed in bytes per second. How can I accurately achieve this? Does socket io natively support this?

function upload_handler(files) {
  if (!socket || socket.disconnected) {
    alert('Sorry :( nSomething went wrong! Try again in a bit.');
    return;
  }

  const file = files[0];
  const reader = new FileReader();

  reader.onload = function(event) {
    const buffer = event.target.result;
    const totalSize = buffer.byteLength;
    const chunkSize = 1024 * 1024; // 1MB chunk size

    socket.on(user_id, function(data) {
      const from = data.from
      if (from === 'file-upload') {
        const message = data.message
        if (message === 'send-more-chunk') {
          const progress = data.progress
          console.log(progress)

          if (data.end < totalSize) {
            sendChunk(data.end);
          }
        } else if (message === 'all-chunks-received') {
          console.log("upload done")
        } else if (message === 'upload-error') {
          console.log("An error occurred while uploading file")
        }
      }
    });

    function sendChunk(start) {
      const chunk = buffer.slice(start, start + chunkSize);

      socket.emit('file-upload', {
        userId: user_id,
        fileName: file.name,
        chunk: chunk,
        start,
        end: start + chunk.byteLength,
        totalSize: totalSize
      });
    }

    sendChunk(0);
  };

  reader.onerror = function(event) {
    console.error('File read error:', event.target.error);
  };

  reader.readAsArrayBuffer(file);
}
<input type="file" onchange="upload_handler(this.files)" hidden />
io.on('connection', function(client) {

  client.on("file-upload", (fileMetadata) => {
    const userId = fileMetadata.userId;
    const fileName = fileMetadata.fileName;
    const dataChunk = fileMetadata.chunk;
    const startSize = fileMetadata.start;
    const endSize = fileMetadata.end;
    const totalSize = fileMetadata.totalSize;

    if (endSize === totalSize) {
      const message = {
        agent: 'server',
        from: 'file-upload',
        message: 'all-chunks-received',
        progress: '100'
      };
      client.emit(userId, message);
    } else if (endSize < totalSize) {
      let progress = (endSize / totalSize) * 100
      progress = parseFloat(progress.toFixed(1))
      const message = {
        agent: 'server',
        from: 'file-upload',
        message: 'send-more-chunk',
        end: endSize,
        progress: progress
      };
      client.emit(userId, message);
    } else {
      console.log('Error occurred at upload event');
      const message = {
        agent: 'server',
        from: 'file-upload',
        message: 'upload-error'
      };
      client.emit(userId, message);
    }
  });
})

Shopify: Create a custom flow to create a customer (Additional metafields)

I want to create a custom form for the user to register, because I need the birthday of the customer.

So I need the user to enter his birthday as a REQUIRED field and I need to check if the user is above the age of 18.

Then at the checkout I also want to reconfirm the user is above 18.

I thought it would be the best approach to create a custom Shopify App for that.

I created a cart checkout validation so I can check for the birthday which worked out.

run.graphql:

query RunInput {
  cart {
    buyerIdentity {
      customer {
        metafield(key: "birthday") {
          value
        }
      }
    }
  }
}

run.ts:

export function run(input: RunInput): FunctionRunResult {
  const error = {
    localizedMessage: "Birthday not set.",
    target: "cart"
  };

  const errors: any = [];

  if (input.cart.buyerIdentity?.customer?.metafield?.value === undefined) {
    error.localizedMessage += input.cart.buyerIdentity?.customer?.metafield?.value ?? "{NO}";
    errors.push(error);
  }

  return {
    errors
  }
};

So currently I get this error message inside my cart, because no birthday value is deposited.

Now I needed to create that custom form for the user to register at. I used the main-register.liquid from the dawn theme as a template. I added my birthday input and added a validation method called validateForm().

This is how the script looks:

function validateForm() {
    var firstName = document.getElementById('RegisterForm-FirstName').value;
    var lastName = document.getElementById('RegisterForm-LastName').value;
    var password = document.getElementById('RegisterForm-password').value;
    var email = document.getElementById('RegisterForm-email').value;
    var birthday = document.getElementById('RegisterForm-birthday').value;

    var errorMessage = document.getElementById("error-message");

    errorMessage.hidden = true;
    
    if (!firstName.trim().length) {
      errorMessage.hidden = false;
      return false;
    }
    
    // all other checks if empty ....

    var record=birthday.trim();
    var currentdate=new Date();

    var currDay = currentdate.getDate();
    var currMonth = currentdate.getMonth() + 1;
    var currYear = currentdate.getFullYear() - 17;

    var aighteenStr = currDay + "-" + currMonth + "-" + currYear;
    var aighteen = new Date(aighteenStr);
    
    var birth = new Date(record);      

    console.log(birth);
    console.log(aighteen);

    if(birth > aighteen)
    {
        alert("Du musst über 18 Jahre sein, um einen Account erstellen zu können.");
        return false;
    }
    
    return true;
  }

I did my research and found the createCustomer function / mutation, but I’m not sure how to implement it here.

I’ve also found this tutorial, but it looked strange to put my credentials into the liquid file.

Any advice on how to call that function? Or do I need to follow a different approach?

(Different approach my mind has crossed:
Use the normal create_customer form and add a new field with the id customer[note][birthday].
This worked in the saving process, but without a validation if the user is 18+.
I also didn’t find a method to retrieve that information in the checkout validation because the customer model that gets returned in the cart only has a metafield value and no note value (information here) )

Necessary async-await working with IndexedDB

I have a react typescript App, in my App I use IndexedDB for storing some Data.
I have separate class for working with IndexedDB call DB . in one of my class methods I use this code for getting all data

 public async getAll(){

 const promise = await new Promise((resolve,reject)=>{
    const req = this.openDB();
    req.addEventListener("error", (e) => {
      console.log("error ", e);
      reject ("error");
    });

    req.addEventListener("success", () => {
      const db = req.result;
      const tx = db.transaction("tasks", "readonly");
      tx.addEventListener("complete", () => {
        console.log("transaction complete");
        db.close();
      });

      const readObj = tx.objectStore("tasks");
      const data = readObj.getAll();
      
      data.addEventListener("success",(e)=>{
        console.log(data);
        console.log(e);
        resolve (data.result);
      });

    });
 });

 return await promise;

} 

and in one of my component event handler

      const db = new DB();
      const dataPro = db.getAll();
      dataPro.then((resData)=>{
      console.log(resData); // I have Data I need it
                           }

but the getAll func works fine without async-await , so my question is : is it really Necessary to use async-await in getAll func ?? I mean is there any situation that I need async-await

I try getAll func code without async-await and it works fine for me

Vite react setInputs data from shadcn select component

I’m currently working on a vite react project which uses shadcn for component styling.
Now I am trying to add the entered values into a useState. It works fine on input fields etc. But i’m not able to set the right value for the gender since my written function to get the selected value from the select ignores all of the other values written before.

Full code:

import React from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Link } from "react-router-dom";
import { useState } from "react";
import { Terminal } from "lucide-react";
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from "@/components/ui/select";

const SignUp = () => {
    const [inputs, setInputs] = useState({
        username: "",
        email: "",
        password: "",
        repeatPassword: "",
        gender: "",
    });

    const handleSelectChange = (gender) => {
        setInputs({ ...inputs.gender, gender });
    };

    const handleSubmit = (e) => {
        e.preventDefault();

        console.log(inputs);
    };

    return (
        <div>
            <div className="container relative hidden h-screen flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0">
                <div className="relative hidden h-full flex-col bg-muted p-10 text-white lg:flex dark:border-r">
                    <div className="absolute inset-0 bg-zinc-900" />
                    <div className="relative z-20 flex items-center text-lg font-medium">
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            viewBox="0 0 24 24"
                            fill="none"
                            stroke="currentColor"
                            strokeWidth="2"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                            className="mr-2 h-6 w-6"
                        >
                            <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
                        </svg>
                        Vibely
                    </div>
                    <div className="relative z-20 mt-auto">
                        <blockquote className="space-y-2">
                            <p className="text-base">
                                &ldquo;Step into the world of infinite
                                possibilities with our virtual avatar chat!
                                Engage, explore, and connect with others in a
                                whole new dimension. Your avatar is your
                                passport to endless conversations and
                                experiences&rdquo;
                            </p>
                            <footer className="text-sm">Vibely.com</footer>
                        </blockquote>
                    </div>
                </div>
                <div className="lg:p-8">
                    <div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
                        <div className="flex flex-col space-y-2 text-center">
                            <h1 className="text-2xl font-semibold tracking-tight">
                                Create a account
                            </h1>
                            <p className="text-sm text-muted-foreground">
                                Create a account to get started on Vibely
                            </p>
                        </div>
                    </div>
                    <div className="grid gap-6 w-auto ml-20 mr-20 mt-5">
                        <Alert>
                            <Terminal className="h-4 w-4" />
                            <AlertTitle>Heads up!</AlertTitle>
                            <AlertDescription>
                                If you already have an account, you can{" "}
                                <Link className="font-semibold" to="/login">
                                    login here
                                </Link>
                                .
                            </AlertDescription>
                        </Alert>
                        <form onSubmit={handleSubmit}>
                            <div className="grid gap-4">
                                <Input
                                    id="username"
                                    placeholder="Username"
                                    type="text"
                                    autoCorrect="off"
                                    value={inputs.username}
                                    onChange={(e) =>
                                        setInputs({
                                            ...inputs,
                                            username: e.target.value,
                                        })
                                    }
                                />
                            </div>
                            <div className="grid gap-4 mt-5">
                                <Input
                                    id="email"
                                    placeholder="Email address"
                                    type="email"
                                    value={inputs.email}
                                    onChange={(e) =>
                                        setInputs({
                                            ...inputs,
                                            email: e.target.value,
                                        })
                                    }
                                />
                            </div>
                            <div className="grid gap-4 mt-5">
                                <Input
                                    id="password"
                                    placeholder="Password"
                                    type="password"
                                    value={inputs.password}
                                    onChange={(e) =>
                                        setInputs({
                                            ...inputs,
                                            password: e.target.value,
                                        })
                                    }
                                />
                            </div>
                            <div className="grid gap-4 mt-5">
                                <Input
                                    id="repeatPassword"
                                    placeholder="Password confirmation"
                                    type="password"
                                    value={inputs.repeatPassword}
                                    onChange={(e) =>
                                        setInputs({
                                            ...inputs,
                                            repeatPassword: e.target.value,
                                        })
                                    }
                                />
                            </div>
                            <div className="grid gap-4 mt-5">
                                <Select onValueChange={handleSelectChange}>
                                    <SelectTrigger id="gender">
                                        <SelectValue placeholder="Gender" />
                                    </SelectTrigger>
                                    <SelectContent position="popper">
                                        <SelectItem value="male">
                                            Male
                                        </SelectItem>
                                        <SelectItem value="female">
                                            Female
                                        </SelectItem>
                                    </SelectContent>
                                </Select>
                            </div>
                            <div className="grid gap-4 mt-6">
                                <Button type="submit">Register</Button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default SignUp;

Example on what happens:

enter image description here
enter image description here

How to set data() value in vue before loading template

I do not know how to solve this problem I’ve been stuck for a few hours now. I tried multiple solutions but I do not have any more possible solutions for that problem.

I have two objects (user_1, user_2) that are loaded and set in App.vue like that

beforeCreate() {
    this.$store.dispatch("initializeUser");
    try {
      this.user_1 =  getUser("lukasz");
      this.user_2 =  getUser("karolina");
      this.$store.commit("setUser_1", this.user_1)
      this.$store.commit("setUser_2", this.user_2)

    } catch (error) {
      console.error("Error fetching users:", error);
    }
  },
async function getUser(user) {
  try {
    const response = await axios.get(`http://localhost:8080/api/users/username/${user}`);
    return response.data;
  } catch (error) {
    console.error("Error fetching user:", error);
    throw error; // Re-throw the error to be caught by the caller
  }
}

and after that template, StartPage is loading because !hasUser returns false at first

<template>
  <div id="wrapper">
    <StartPage v-if="!hasUser" />  <div v-else>  <Navbar />
    <section class="section">
      <router-view />
    </section>
  </div>
  </div>
</template>

but then in StartPage when I try to set user_1 and user_2 value from store to local variables everything works fine until router-link gives error that user_2 and user_1 are undefined even though I print them in mounted() function and there they are.

I tried using beforeMount(), created(), separating this function outside of export but it did not help either.

I know that if i hardcode some value in place of user_1 and user_2 site loads fine so there must be an issue

Here is StartPage.vue in which the error occurs

<template>
  <div>
    <router-link class="user2" :to="{name: 'User View', params: {user: this.user_2.username}}">
      <div class="split left" @mouseover="setHearts" @click="setSelectedUser(user_2)">
        <div class="centered">
          <button>{{ this.user_2.username }}</button>
        </div>
        <HeartIcon v-for="index in hearts" :key="index" class="heart"></HeartIcon>
      </div>
    </router-link>

    <router-link class="user1" :to="{name: 'User View', params: {user: this.user_1.username}}">
      <div class="split right" @mouseover="setFootballs" @click="setSelectedUser(user_1)">
        <div class="centered">
          <button class="button-text">{{ this.user_1.username }}</button>
        </div>
        <FootballIcon v-for="index in footballs" :key="index" class="football"></FootballIcon>
      </div>
    </router-link>
  </div>

</template>

<script>
import HeartIcon from "@/components/Heart.vue";
import FootballIcon from "@/components/Football.vue";

export default {
  name: 'StartPage',
  computed: {},
  data() {
    return {
      hearts: 10,
      footballs: 10,
      user_1: {},
      user_2: {}
    }
  },
  components: {
    HeartIcon,
    FootballIcon
  },
  methods: {
    setHearts() {
      const hearts = document.querySelectorAll('.left .heart');
      hearts.forEach(heart => {
        const maxTop = window.innerHeight - heart.clientHeight; // Maximum top position
        const maxLeft = window.innerWidth - heart.clientWidth; // Maximum left position
        const randomTop = Math.random() * maxTop;
        const randomLeft = Math.random() * maxLeft;
        heart.style.top = `${randomTop}px`;
        heart.style.left = `${randomLeft}px`;
        heart.style.transform = `rotate(${Math.random() * 90 - 45}deg)`;
      });
    },

    setFootballs() {
      const footballs = document.querySelectorAll('.right .football');
      footballs.forEach(football => {
        const maxTop = window.innerHeight - football.clientHeight; // Maximum top position
        const maxLeft = window.innerWidth - football.clientWidth; // Maximum left position
        const randomTop = Math.random() * maxTop;
        const randomLeft = Math.random() * maxLeft;
        football.style.top = `${randomTop}px`;
        football.style.left = `${randomLeft}px`;
        football.style.transform = `rotate(${Math.random() * 90 - 45}deg)`;
      });
    },
    async setSelectedUser(user) {
      try {
        // Call an action to commit the selected user to the store
        await this.$store.dispatch("setSelectedUser", user);
      } catch (error) {
        console.error("Error setting selected user:", error);
      }
    },
    setUsers() {
      this.user_1 = this.$store.state.user_1
      this.user_2 = this.$store.state.user_2
    }

  },
  mounted() {
    this.setUsers();
  }
}
</script>

And the error i am receiving

[Vue warn]: Unhandled error during execution of setup function 
  at <RouterLink class="user2" to= {name: 'User View', params: {…}} > 
  at <StartPage key=0 > 
  at <App>

vue-router.mjs:1146 Uncaught (in promise) Error: Missing required param "user"

I hope someone will find a solution to that problem

Webpack 5 Dynamic Import : “ChunkLoadError”

I use Webpack in a php project and I did some refactoring to do dynamic import in order to reduce the rendering size of my JS.
But I have this error because a ‘/’ is missing before the file name because the path is ‘/public/vendors/dist/…’:

Not allowed to load local resource: file:///C:/app/projets_name/public/vendors/js/dist452.bc790b53.js

Error loading custom function: ChunkLoadError: Loading chunk 954 failed.
(error: file:///C:/app/projets_name/public/vendors/js/dist954.21bc36fc.js)

Here is my webpack config:

const path = require('path')
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const {WebpackManifestPlugin} = require('webpack-manifest-plugin');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const {WebpackLaravelMixManifest} = require('webpack-laravel-mix-manifest');
// const Dotenv = require('dotenv-webpack');

const dev = process.env.NODE_ENV === "dev"

const cssLoaders = [
    // Creates `style` nodes from JS strings
    dev ? "style-loader" : MiniCssExtractPlugin.loader,

    // Translates CSS into CommonJS
    {
        loader: "css-loader",
        options: {importLoaders: 1},
    },
    {
        loader: "postcss-loader",
        options: {
            postcssOptions: {
                plugins: [
                    [
                        "postcss-preset-env",
                        {
                            // browsers: 'last 2 versions'
                        },
                    ],
                ],
            },
        },
    },
]

let config_webpack = {
    mode: dev ? "development" : "production",
    entry: {
        app: ['./resources/scss/app.scss', './resources/js/src/app.js']
    },
    watch: dev,
    output: {
        path: path.resolve(__dirname, "public/vendors/dist"),
        publicPath: path.resolve(__dirname, "public/vendors/js/dist"),
        filename: dev ? '[name].js' : '[name].[chunkhash:8].js',
        clean: true,
    },
    devtool: dev ? "cheap-module-source-map" : false,
    module: {
        rules: [
            {
                test: /.js$/,
                exclude: /node_modules/,
                use: ["babel-loader"]
            },
            {
                test: /.css$/i,
                use: cssLoaders
            },
            {
                test: /.s[ac]ss$/i,
                use: [
                    ...cssLoaders,
                    // Compiles Sass to CSS
                    "sass-loader",
                ],
            },
            {
                test: /.(png|jpe?g|gif|svg)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 10 * 1024 // 10kb
                    }
                },
                generator: {
                    filename: 'images/[hash][ext][query]'
                }
            }
        ]
    },
    optimization: {
        minimize: !dev,
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    sourceMap: true,
                },
            }),
            new CssMinimizerPlugin(),
        ],
    },
    plugins: [],
    resolve: {
        alias: {
            functions: path.resolve(__dirname, 'resources/js/functions/'),
            modules: path.resolve(__dirname, 'resources/js/modules/'),
            components: path.resolve(__dirname, 'resources/js/components/'),
        },
    },
}

config_webpack.plugins.push(new MiniCssExtractPlugin({
    filename: dev ? '[name].css' : '[name].[contenthash:8].css',
}))

if (!dev) {
    config_webpack.plugins.push(new WebpackManifestPlugin({
        publicPath: "",
        // fileName: path.resolve(__dirname, 'public/manifest.json'),
    }))

    config_webpack.plugins.push(new CleanWebpackPlugin({
        dry: true,
        verbose: true,
    }))
}

module.exports = config_webpack

I have reviewed the publicPath in my config but it doesn’t work. There is always the ‘/’ missing.
I’m looking for an idea for a solution or if I have to switch to ViteJs then I would like a config that would solve the problem.

Change the class display after selecting a card with a date in Rails

I’m developing an application for a horsemanship school so they can organize their classes and see who booked a class and whatnot!

In the display of all the classes, I’ve created this sroll of dates to help users choose the day they want to see and then display the classes for the set day.

However, I’m not sure how to accomplish this.

I used stimulus javascript to select a card, however it always chooses the same card, no matter where I click. I’ve seen some sugestions to use DatePicker, but that only confuses me more.

So I would like to ask you guys some suggestions. Here is my current code:

This is my card partial that I render on the index page:

<div class="d-flex justify-content-start overflow-banner" data-controller="book-class">
  <% Date.today.all_month.to_a.each do |day| %>
    <div
      class="border-div card d-flex justify-content-center col-2 date-banner-card mx-3"
    >
      <div
        class="d-flex flex-column card-body justify-content-center align-items-center"
        data-action="click->book-class#dataSelected"
        data-book-class-target="card"
      >
        <h2>
          <%= day.strftime("%d") %>
        </h2>
        <p>
          <%= day.strftime("%b") %>
        </p>
      </div>
    </div>
  <% end %>
</div>

And this is my book-class controller right now. Disclaimer this is just to see if I’m connected and to see if I can get colors to change when selected

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="book-class"
export default class extends Controller {
  static targets = ["toggle", "card"]

  connect() {
    console.log("You're connected")
    console.log(this.cardTarget)
  }

  booked() {
    console.log("you're booked")
  }

  dataSelected() {
    console.log("Selected")
    this.cardTarget.classList.toggle("background-change")
  }
}```

Do not trigger pixel if url contain word page

Facebook pixel triggering two times as because there are two urls in the same page [ redirection ]. but i want facebook pixel to trigger only one time.

I tried the below code :

var add = window.location.toString();

  if (add.indexOf("page=") != -1) {

        fbq('track', "PageView");
    }

So that if there is text “page” in url, then facebook event “PageView” should not trigger.

enter image description here

but if i use above code, not even a single facebook pixel will trigger. am i using wrong code ?

below is entire code i am using :

<script>
  !function(f,b,e,v,n,t,s)
  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
  n.callMethod.apply(n,arguments):n.queue.push(arguments)};
  if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
  n.queue=[];t=b.createElement(e);t.async=!0;
  t.src=v;s=b.getElementsByTagName(e)[0];
  s.parentNode.insertBefore(t,s)}(window, document,'script',
  'https://connect.facebook.net/en_US/fbevents.js');
  fbq('init', '908483260167518');
  //fbq('track', 'PageView');
  $(function() {
    if ( document.location.href.indexOf('page') > -1 ) {
      fbq('track', "PageView");
    }
  /*
  var add = window.location.toString();
  if (add.indexOf("page=") != -1) {
        fbq('track', "PageView");
    }
    */
    
});

I also tried this :

var url = window.location.href;

if (url.search("#Work") >= 0) {

    fbq('track', 'PageView');
}

When I press edit, the to-do-list item disappears, and when I press delete, the id todo-lists disappears

I’m trying to create a simple to-do list app to practice JS. Each to-do-list has two buttons, and the button behavior I’m trying to implement via event deregulation. However, when I press edit, the to-do-list item disappears, and when I press delete, the id todo-lists disappears.

const form = document.getElementById("form");
const wrapper = document.getElementById("todo-lists");

function handleTodo(e) {
  const btn = e.target.closest("button");
  if (!btn) return; //not button
  const todo = e.currentTarget; // todo generated by sumit()

  if (btn.innerText === "remove") {
    wrapper.remove(todo);
  } else if (btn.innerText === "edit") {
    const todo_text = todo.querySelector("div");
    const new_input = document.createElement("input");
    new_input.value = todo_text.innerText;
    todo.prepend(new_input);
    todo.remove(todo_text);
  }
}

function submit(e) {
  e.preventDefault();
  const value = form.elements["todo_input"].value;
  const todo = document.createElement("div");

  todo.addEventListener("click", handleTodo);

  const todo_text = document.createElement("div");
  const del = document.createElement("button");
  const edit = document.createElement("button");
  del.innerText = "remove";
  edit.innerText = "edit";
  todo_text.innerText = value;

  todo.appendChild(todo_text);
  todo.appendChild(del);
  todo.appendChild(edit);
  wrapper.appendChild(todo);
  e.target.elements["todo_input"].value = "";
}

form.addEventListener("submit", submit);
<div id="container">
  <div id="todo-lists"></div>
  <div id="form-wrapper">
    <form id="form">
      <input type="text" placeholder="Enter todo" name="todo_input" />
      <button>Enter</button>
    </form>
  </div>
</div>

enter image description here

This is the result of e.target and e.currentTarget of handleTodo Function.

and i leave the codepen address where you want to run this code.

https://codepen.io/gmjjfjnm-the-flexboxer/pen/RwOJggQ

I took a look at the console log and read the documentation on event delegation, but I couldn’t find the correct answer.

Install Instauto on Raspberry Pi failed

im trying to install Instauto from this github: https://github.com/mifi/instauto

I followed the setup and installed it successfull on my raspberry pi and edited the example.js.

Everytime im running it on my raspberry pi it failes with the following message. Does anybody know why it fails and how to fix it? I tried it with different solutions but nothing worked.

I tried it with different solutions. I read that on Raspberry Pi you need a arm7 chromium package to work with pupeteer. I tried to install and it doesnt work.

I changed the code lines exactly like on the setup for raspberry pi.

Error Message