orestbida / iframemanager

🍪 GDPR friendly iframe manager written in vanilla js
https://orestbida.com/demo-projects/iframemanager/demo1/
MIT License
226 stars 25 forks source link

SvelteKit #50

Open carstenjaksch opened 2 months ago

carstenjaksch commented 2 months ago

I have a hard time getting this to work with SvelteKit.

The div stays black and I get the following error in console:

Bildschirm­foto 2024-03-10 um 10 13 03

Outside a Svelte component, it works fine. The strange thing is, it worked a few times within a Svelte component. But after another reload it was gone (nothing changed). Now I can't reproduce the working state ... Could you provide a SvelteKit example in StackBlitz?

Currently, I have the css and js part via CDN in app.html and also tried to load them with inside the component.

orestbida commented 2 months ago

I just created a basic example here.

carstenjaksch commented 2 months ago

Unfortunately, that doesn't work either. I have invited you to the private repo and will send you the necessary .env contents via email.

Maybe it is a bug in this very specific context? I hope you can reproduce it.

carstenjaksch commented 2 months ago

The script seems to work after I change something and hot reload kicks in. After a full reload, the div is black again.

The services Map of im.getState() is empty after a full reload, but not with hot reload. Maybe the script runs too early?

carstenjaksch commented 2 months ago

Finally! The simple thing is to use actions in Svelte: https://svelte.dev/docs/svelte-action

They run code after an element ist rendered to the DOM. Maybe update your Svelte example?

This is my final code:

// iframemanager.ts

import '@orestbida/iframemanager';
import '@orestbida/iframemanager/dist/iframemanager.css';

const im = (node) => {
    // @ts-ignore
    const im = iframemanager();

    im.run({
        ...
    });
};

export default im;
<!-- component.svelte -->

<script lang="ts">
    import im from '$lib/Iframemanager';
</script>

<div {...dataAtts} use:im />
driskell commented 1 month ago

@orestbida @carstenjaksch

It worth noting that when you call run multiple times you get multiple consent notice elements added to the DOM and they start to stack up. It seems running run is not idempotent - it will in fact duplicate elements.

So I think Iframemanager as it stands does not support dynamic elements that are added after initial run is called. Perhaps needs a refresh method that just captures unknown ones and cleans up state for missing ones. run can then just reject if already been given a config.

carstenjaksch commented 1 month ago

@orestbida I have another issue with SvelteKit. I try to load Google Maps API as a custom widget according to your demo.

Svelte:

<script>
// ...
const dataAtts = {
  'data-service': 'maps',
  'data-autoscale': '',
  'data-lat': loc[0],
  'data-lang': loc[1],
  'data-title': embed.maps.title,
  'data-phone': embed.maps.contact.phone.target,
  'data-email': embed.maps.contact.email.target
};
// ...
</script>
<!-- ... -->
<div {...dataAtts} use:im>
  <div data-placeholder>
    <div id="map"></div>
  </div>
</div>

onAccept:

onAccept: async (div, setIframe) => {
    await CookieConsent.loadScript(
        'https://maps.googleapis.com/maps/api/js?key=[API]'
    );
    await im.childExists({ childProperty: 'maps' });

    const { lat, lng, title, phone, email } = div.dataset;

    const map = new google.maps.Map(div.querySelector('#map') as HTMLElement, {
        center: { lat: Number(lat), lng: Number(lng) },
        zoom: 9
    });

    const infowindow = new google.maps.InfoWindow({
        content: `<div style="max-width: 288px; padding: 8px 20px 20px 8px;"><p style="line-height: 1.2; margin-bottom: 12px;"><strong>${title}</strong></p><p style="line-height: 1.2;">Telefon: <a href="tel:${phone}">${phone}</a><br>E-Mail: <a href="mailto:${email}">${email}</a></p></div>`,
        ariaLabel: title
    });

    const marker = new google.maps.Marker({
        position: { lat: Number(lat), lng: Number(lng) },
        map,
        title: title
    });

    infowindow.open({
        anchor: marker,
        map
    });

    marker.addListener('click', () => {
        infowindow.open({
            anchor: marker,
            map
        });
    });

    (await im.childExists({ parent: div })) && setIframe(div.querySelector('iframe'));
},

The issue: My div#maps inside the placeholder is not there (before and after accept) and the black box is spinning forever. This error follows in the browser console:

Uncaught (in promise) InvalidValueError: Map: Expected mapDiv of type HTMLElement but was passed null.

Could you provide a working example for custom widgets with SvelteKit?

stale[bot] commented 2 days ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.