PageSourceSearch

https://www.label-emmaus.co/static/js/alpine/custom/favoris/skeleton.js?v=204e6a99b7

js label-emmaus.co collected 2026-10-02 05:00:57 UTC 5,547 bytes, 167 lines download raw bytes

1const SECTION_MODE_TO_SKELETON_MODE = {
2  tous: 'all',
3  merchants: 'by_merchant',
4  boutique: 'boutique',
5};
6
7const SKELETON_DIMENSION_SELECTORS = {
8  sortingWidth: '#favoris-sort-select',
9  sortingHeight: '#favoris-sort-select',
10  totalHitsWidth: '#favoris-filtered-count, #favoris-boutique-count',
11  totalHitsHeight: '#favoris-filtered-count, #favoris-boutique-count',
12  promoToggleWidth: '#favoris-promo-toggle',
13  promoToggleHeight: '#favoris-promo-toggle',
14  soldToggleWidth: '#favoris-sold-toggle',
15  soldToggleHeight: '#favoris-sold-toggle',
16  searchWidth: '#favoris-search',
17  searchHeight: '#favoris-search',
18};
19
20const PRESENCE_SELECTORS = {
21  hasCategoryChips: '#favoris-category-chips',
22  hasPromoToggle: '#favoris-promo-toggle',
23  hasSoldToggle: '#favoris-sold-toggle',
24  hasSortSelect: '#favoris-sort-select',
25  hasTotalHits: '#favoris-filtered-count, #favoris-boutique-count',
26  hasSearch: '#favoris-search',
27};
28
29document.addEventListener('alpine:init', () => {
30  Alpine.data('skeletonFavoris', () => ({
31    sortingWidth: '0px',
32    sortingHeight: '0px',
33    totalHitsWidth: '0px',
34    totalHitsHeight: '0px',
35    promoToggleWidth: '0px',
36    promoToggleHeight: '0px',
37    soldToggleWidth: '0px',
38    soldToggleHeight: '0px',
39    searchWidth: '0px',
40    searchHeight: '0px',
41    chipWidths: [],
42    chipHeight: '0px',
43    headerOffset: '0px',
44    hasCategoryChips: false,
45    hasPromoToggle: false,
46    hasSoldToggle: false,
47    hasSortSelect: false,
48    hasTotalHits: false,
49    hasSearch: false,
50    mode: 'all',
51    loading: false,
52
53    init() {
54      const declaredMode = this.$el.dataset.mode;
55      if (declaredMode) {
56        this.mode = declaredMode;
57      }
58
59      this._boundCompute = this.computeDimensions.bind(this);
60      this._boundAfterSwap = this._handleAfterSwap.bind(this);
61      this._boundResize = this._handleResize.bind(this);
62      this._resizeRaf = null;
63      this._resizeObserver = typeof ResizeObserver === 'function' ? new ResizeObserver(this._boundCompute) : null;
64
65      this.computeDimensions();
66      setTimeout(this._boundCompute, 500);
67      this._observeFilterBar();
68
69      document.addEventListener('htmx:afterSwap', this._boundAfterSwap);
70      window.addEventListener('resize', this._boundResize, { passive: true });
71
72      this.$el.addEventListener('alpine:destroy', () => {
73        document.removeEventListener('htmx:afterSwap', this._boundAfterSwap);
74        window.removeEventListener('resize', this._boundResize);
75        if (this._resizeObserver) {
76          this._resizeObserver.disconnect();
77        }
78        if (this._resizeRaf) {
79          cancelAnimationFrame(this._resizeRaf);
80        }
81      });
82    },
83
84    _observeFilterBar() {
85      if (!this._resizeObserver) return;
86      const bar = document.getElementById('favoris-filter-bar');
87      this._resizeObserver.disconnect();
88      if (bar) {
89        this._resizeObserver.observe(bar);
90      }
91    },
92
93    _handleResize() {
94      if (this._resizeRaf) return;
95      this._resizeRaf = requestAnimationFrame(() => {
96        this._resizeRaf = null;
97        this.computeDimensions();
98      });
99    },
100
101    _handleAfterSwap(event) {
102      const target = event?.detail?.target;
103      if (target && target.id === 'favoris-content') {
104        const section = document.getElementById('favoris-content');
105        if (section) {
106          const sectionMode = section.dataset.mode;
107          const mapped = SECTION_MODE_TO_SKELETON_MODE[sectionMode];
108          if (mapped) {
109            this.mode = mapped;
110          }
111        }
112      }
113
114      this.loading = false;
115      this._observeFilterBar();
116      this.computeDimensions();
117    },
118
119    computeDimensions() {
120      const measurements = {};
121      Object.entries(SKELETON_DIMENSION_SELECTORS).forEach(([key, selector]) => {
122        const element = document.querySelector(selector);
123        if (!element) return;
124        const rect = element.getBoundingClientRect();
125        measurements[key] = key.endsWith('Width') ? Math.ceil(rect.width) : Math.ceil(rect.height);
126      });
127
128      const presence = {};
129      Object.entries(PRESENCE_SELECTORS).forEach(([key, selector]) => {
130        const el = document.querySelector(selector);
131        presence[key] = key === 'hasCategoryChips' ? Boolean(el && el.children.length > 0) : Boolean(el);
132      });
133
134      const chipWidths = [];
135      let chipHeightPx = 0;
136      const chipsContainer = document.getElementById('favoris-category-chips');
137      if (chipsContainer) {
138        Array.from(chipsContainer.children).forEach((chip) => {
139          const rect = chip.getBoundingClientRect();
140          chipWidths.push(Math.ceil(rect.width));
141          chipHeightPx = Math.max(chipHeightPx, Math.ceil(rect.height));
142        });
143      }
144
145      let headerOffsetPx = 0;
146      const host = document.getElementById('favoris-skeleton-host');
147      const filterBar = document.getElementById('favoris-filter-bar');
148      if (host && filterBar) {
149        const hostRect = host.getBoundingClientRect();
150        const barRect = filterBar.getBoundingClientRect();
151        headerOffsetPx = Math.max(0, Math.ceil(barRect.top - hostRect.top));
152      }
153
154      requestAnimationFrame(() => {
155        Object.entries(measurements).forEach(([key, value]) => {
156          this[key] = `${value}px`;
157        });
158        Object.entries(presence).forEach(([key, value]) => {
159          this[key] = value;
160        });
161        this.chipWidths = chipWidths;
162        this.chipHeight = `${chipHeightPx}px`;
163        this.headerOffset = `${headerOffsetPx}px`;
164      });
165    },
166  }));
167});

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.