PageSourceSearch

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

js label-emmaus.co collected 2026-09-24 19:00:01 UTC 4,394 bytes, 141 lines download raw bytes

1const FAVORIS_SWAP_TARGETS = new Set([
2  'favoris-content',
3  'favoris-grid',
4  'favoris-boutique-grid',
5  'favoris-lists-picker-host',
6  'favoris-lists-picker-rows-host',
7]);
8const FAVORIS_GRID_TARGETS = new Set(['favoris-grid', 'favoris-boutique-grid']);
9let favorisFocusInsideSwapTarget = false;
10
11// htmx émet htmx:afterSwap une fois PAR élément top-level du fragment swappé,
12// tous avec la même cible — d'où un garde-fou par xhr pour l'event GA4.
13const ga4TrackedFavorisXhrs = new WeakSet();
14
15function focusFirstInteractive(target) {
16  const trash = target.querySelector('.favoris-trash-button');
17  if (trash && typeof trash.focus === 'function') {
18    trash.focus({ preventScroll: true });
19    return true;
20  }
21  const link = target.querySelector('a[href]');
22  if (link && typeof link.focus === 'function') {
23    link.focus({ preventScroll: true });
24    return true;
25  }
26  const emptyState = target.querySelector('.favoris-empty');
27  if (emptyState && typeof emptyState.focus === 'function') {
28    emptyState.focus({ preventScroll: true });
29    return true;
30  }
31  const section = document.getElementById('favoris-content');
32  if (section) {
33    section.focus({ preventScroll: true });
34    return true;
35  }
36  return false;
37}
38
39htmx.on('htmx:beforeRequest', (event) => {
40  // hx-disabled-elt blurs the trigger to <body> before htmx:beforeSwap,
41  // so capture focus origin here from the requesting element itself.
42  const elt = event?.detail?.elt;
43  if (!elt || typeof elt.closest !== 'function') return;
44  for (const id of FAVORIS_SWAP_TARGETS) {
45    if (elt.closest('#' + id)) {
46      favorisFocusInsideSwapTarget = true;
47      return;
48    }
49  }
50});
51
52htmx.on('htmx:beforeSwap', (event) => {
53  const target = event?.detail?.target;
54  if (!target || !FAVORIS_SWAP_TARGETS.has(target.id)) return;
55  Alpine.destroyTree(target);
56});
57
58htmx.on('htmx:afterSwap', (event) => {
59  const target = event?.detail?.target;
60  if (!target || !FAVORIS_SWAP_TARGETS.has(target.id)) {
61    favorisFocusInsideSwapTarget = false;
62    return;
63  }
64
65  // outerHTML swap detaches the original target; the live element is
66  // re-queried by id so focus() lands on a connected node.
67  const liveTarget = document.getElementById(target.id) || target;
68
69  Alpine.initTree(liveTarget);
70
71  if (window.productCardManager) {
72    window.productCardManager.applyFavorisToCards();
73    window.productCardManager.applyCartToCards();
74    window.productCardManager.setupEventListeners();
75  }
76
77  if (liveTarget.id === 'favoris-content') {
78    const xhr = event?.detail?.xhr;
79    if (!xhr || !ga4TrackedFavorisXhrs.has(xhr)) {
80      if (xhr) {
81        ga4TrackedFavorisXhrs.add(xhr);
82      }
83      ga4.pageView();
84    }
85    liveTarget.focus({ preventScroll: true });
86  } else if (
87    FAVORIS_GRID_TARGETS.has(liveTarget.id) &&
88    favorisFocusInsideSwapTarget &&
89    (document.activeElement === document.body || document.activeElement === null)
90  ) {
91    focusFirstInteractive(liveTarget);
92  }
93
94  favorisFocusInsideSwapTarget = false;
95});
96
97htmx.on('htmx:afterSettle', (event) => {
98  const target = event?.detail?.target;
99  if (!target) return;
100  if (target.id === 'favoris-lists-picker-host') {
101    window.dispatchEvent(
102      new CustomEvent('toggle-favoris-lists-picker-modal', {
103        detail: { triggerSelector: '#favoris-lists-picker-trigger' },
104      })
105    );
106    return;
107  }
108  if (target.id === 'favoris-lists-picker-rows-host') {
109    const form = document.getElementById('favoris-lists-picker-create-form');
110    if (form) form.reset();
111    const heading = document.getElementById('favoris-lists-picker-heading');
112    if (heading) heading.focus();
113  }
114});
115
116htmx.on('htmx:confirm', (event) => {
117  const form = event?.detail?.elt?.closest('form[data-list-name]');
118  if (!form) return;
119  event.preventDefault();
120  window.dispatchEvent(
121    new CustomEvent('open-delete-list-confirm', {
122      detail: {
123        name: form.dataset.listName,
124        message: event.detail.question,
125        issueRequest: () => event.detail.issueRequest(true),
126      },
127    })
128  );
129});
130
131htmx.on('htmx:oobBeforeSwap', (event) => {
132  const target = event?.detail?.target;
133  if (!target || target.id !== 'favoris-filter-bar') return;
134  Alpine.destroyTree(target);
135});
136
137htmx.on('htmx:oobAfterSwap', (event) => {
138  const target = event?.detail?.target;
139  if (!target || target.id !== 'favoris-filter-bar') return;
140  Alpine.initTree(target);
141});

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.