PageSourceSearch

https://www.label-emmaus.co/static/js/alpine/custom/onboardingModal.js?v=615087a581

js label-emmaus.co collected 2026-09-24 19:00:06 UTC 2,645 bytes, 93 lines download raw bytes

1// Onboarding modal — auto-opens once per id (localStorage-gated).
2
3document.addEventListener('alpine:init', () => {
4  Alpine.data('onboardingModal', (config) => {
5    const baseModal = window.__labelBaseModal();
6    return {
7      ...baseModal,
8      slides: config.slides || [],
9      currentIndex: 0,
10      id: config.id,
11      finalCtaLabel: config.final_cta_label,
12      finalCtaAction: config.final_cta_action || { type: 'close' },
13
14      get seenKey() {
15        return `onboarding-seen-${this.id}`;
16      },
17
18      get primaryLabel() {
19        if (this.currentIndex === 0) return "C'est parti !";
20        if (this.currentIndex === this.slides.length - 1) return this.finalCtaLabel;
21        return 'Suivant';
22      },
23
24      init() {
25        baseModal.init && baseModal.init.call(this);
26        try {
27          if (!localStorage.getItem(this.seenKey)) {
28            // Marked on display, not on dismissal: there is no close button, so a
29            // user leaving via Back or a closed tab reaches no dismissal path and
30            // would otherwise be greeted again on every page load and every login.
31            this.markSeen();
32            this.$nextTick(() => {
33              this.open = true;
34            });
35          }
36        } catch (_e) {
37          // localStorage may be unavailable (private mode, quota); skip auto-open.
38        }
39      },
40
41      markSeen() {
42        try {
43          localStorage.setItem(this.seenKey, '1');
44        } catch (_e) {
45          // noop — best effort
46        }
47      },
48
49      toggle() {
50        if (this.open) this.markSeen();
51        baseModal.toggle.call(this);
52      },
53
54      close() {
55        this.markSeen();
56        return baseModal.close.call(this);
57      },
58
59      prev() {
60        if (this.currentIndex > 0) this.currentIndex -= 1;
61      },
62
63      advance() {
64        if (this.currentIndex < this.slides.length - 1) {
65          this.currentIndex += 1;
66        } else {
67          this.finish();
68        }
69      },
70
71      finish() {
72        this.markSeen();
73        const action = this.finalCtaAction || { type: 'close' };
74        if (action.type === 'redirect' && action.url) {
75          window.location.href = action.url;
76        } else {
77          this.open = false;
78        }
79      },
80
81      modalWrapper: {
82        ...baseModal.modalWrapper,
83        // Topmost-only ESC: when other tiered modales render alongside,
84        // focus-trap puts focus in the topmost wrapper; only that one acts.
85        ['@keydown.window.escape']() {
86          if (this.open && this.$el.contains(document.activeElement)) {
87            this.close();
88          }
89        },
90      },
91    };
92  });
93});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.