PageSourceSearch

https://www.cpm.it/wp-content/themes/hello-theme-child-master/assets/js/cpm-menu-3col-desk.js?ver=1.0.2

js cpm.it collected 2026-10-02 10:27:34 UTC 8,320 bytes, 297 lines download raw bytes

1document.addEventListener('DOMContentLoaded', () => {
2  const root = document.querySelector('[data-component="cpm-menu3"]');
3  if (!root || !window.CPM_MENU3) return;
4
5  const itemsArr = CPM_MENU3.items || [];
6  const childrenMap = CPM_MENU3.children || {};
7  const PLUS = CPM_MENU3.plusSvg || '';
8
9  const byId = new Map(itemsArr.map(it => [String(it.id), it]));
10
11  const col1 = root.querySelector('.cpm-menu3__list[data-level="1"]');
12  const col2 = root.querySelector('.cpm-menu3__list[data-level="2"]');
13  const col3 = root.querySelector('.cpm-menu3__list[data-level="3"]');
14
15  const clear = (ul) => { if (ul) ul.innerHTML = ''; };
16
17  const clean = (s) => (s || '').replace(/\s+/g, ' ').trim();
18  const mergeClasses = (base, extra) => clean(`${clean(base)} ${clean(extra)}`);
19
20  const ensureRelForBlank = (target, rel) => {
21    if (target !== '_blank') return rel || '';
22    const parts = new Set(clean(rel).split(' ').filter(Boolean));
23    parts.add('noopener');
24    parts.add('noreferrer');
25    return Array.from(parts).join(' ');
26  };
27
28  const filterWpClasses = (className) => {
29    const deny = [
30      /^menu-item/, /^current-/, /^page-item/, /^wpml-/,
31      /^mega-/, /^elementor-/, /^nav-/, /^sub-menu/,
32    ];
33    return clean(className)
34      .split(' ')
35      .filter(c => c && !deny.some(rx => rx.test(c)))
36      .join(' ');
37  };
38
39  const hydrateFromWpMenu = (scopeEl) => {
40    (scopeEl || root).querySelectorAll('.cpm-menu3__item[data-id]').forEach((li) => {
41      const id = li.dataset.id;
42      if (!id) return;
43
44      const wpLi = document.querySelector(`#menu-item-${CSS.escape(id)}`);
45      if (!wpLi) return;
46
47      const wpLiClasses = filterWpClasses(wpLi.className || '');
48      if (wpLiClasses) li.className = mergeClasses(li.className, wpLiClasses);
49
50      const wpA = wpLi.querySelector(':scope > a');
51      const target = wpA?.getAttribute('target') || '';
52      const rel = wpA?.getAttribute('rel') || '';
53
54      const a = li.querySelector(':scope > a.cpm-menu3__link');
55      if (a) {
56        if (target) a.setAttribute('target', target);
57        const relFixed = ensureRelForBlank(target, rel);
58        if (relFixed) a.setAttribute('rel', relFixed);
59      }
60    });
61  };
62
63  const dimSiblings = (ul, activeLi) => {
64    ul.querySelectorAll('.cpm-menu3__item').forEach(li => {
65      li.classList.toggle('is-dim', li !== activeLi);
66      li.classList.toggle('is-active', li === activeLi);
67    });
68  };
69
70  const renderLevel = (ul, ids) => {
71    clear(ul);
72
73    (ids || []).forEach((id) => {
74      const it = byId.get(String(id));
75      if (!it) return;
76
77      const kids = childrenMap[String(it.id)] || childrenMap[it.id] || [];
78      const hasChildren = kids.length > 0;
79
80      const li = document.createElement('li');
81      li.className = 'cpm-menu3__item';
82      li.dataset.id = String(it.id);
83      li.dataset.hasChildren = hasChildren ? '1' : '0';
84
85      if (hasChildren) {
86        li.innerHTML = `
87          <button type="button" class="cpm-menu3__btn">
88            <span class="cpm-menu3__title"></span>
89            ${PLUS}
90          </button>
91        `;
92        li.querySelector('.cpm-menu3__title').textContent = it.title;
93      } else {
94        li.innerHTML = `
95          <a class="cpm-menu3__link" href="${it.url}">
96            <span class="cpm-menu3__title"></span>
97          </a>
98        `;
99        li.querySelector('.cpm-menu3__title').textContent = it.title;
100      }
101
102      ul.appendChild(li);
103    });
104
105    hydrateFromWpMenu(ul);
106  };
107
108  // ✅ AUTO OPEN (URL -> currentId -> parentMap -> render col2/col3)
109const normalizeKey = (u) => {
110  try {
111    const x = new URL(u, window.location.origin);
112    const host = (x.host || '').replace(/^www\./, '').toLowerCase();
113    let path = (x.pathname || '/').toLowerCase().replace(/\/+$/, '');
114    if (path === '') path = '/';
115    return host + path;
116  } catch (e) { return ''; }
117};
118
119const buildParentMap = () => {
120  const parent = new Map(); // childId -> parentId
121  Object.keys(childrenMap || {}).forEach(pid => {
122    (childrenMap[pid] || []).forEach(cid => parent.set(String(cid), String(pid)));
123  });
124  return parent;
125};
126
127const findCurrentIdByUrl = () => {
128  // ✅ NON aprire nulla in homepage
129  const path = (new URL(window.location.href)).pathname.replace(/\/+$/, '') || '/';
130  if (path === '/') return null;
131
132  const currentKey = normalizeKey(window.location.href);
133  if (!currentKey) return null;
134
135  const exact = itemsArr.find(it => normalizeKey(it.url) === currentKey);
136  return exact ? String(exact.id) : null;
137};
138
139
140const findLi = (ul, id) =>
141  ul?.querySelector(`.cpm-menu3__item[data-id="${CSS.escape(String(id))}"]`) || null;
142
143const autoOpenFromCurrentPage = () => {
144  const currentId = findCurrentIdByUrl();
145  if (!currentId) return;
146
147  const parentMap = buildParentMap();
148
149  // trail risalendo dai parent (es: 6586 -> 6582 -> 228)
150  const trail = [];
151  let cur = String(currentId);
152  while (cur) {
153    trail.push(cur);
154    cur = parentMap.get(cur);
155  }
156  trail.reverse(); // [228, 6582, 6586]
157
158    // ✅ Se il trail inizia con un "root" (0 o id non presente in col1), lo scarto
159  const col1Ids = new Set(
160    Array.from(col1.querySelectorAll('.cpm-menu3__item[data-id]'))
161      .map(li => String(li.dataset.id))
162  );
163
164  while (trail.length && !col1Ids.has(String(trail[0]))) {
165    trail.shift();
166  }
167
168
169  // ricostruisco colonne in modo pulito
170  clear(col2);
171  clear(col3);
172
173  // L1
174  const lvl1Id = trail[0];
175  if (!lvl1Id) return;
176
177  const li1 = findLi(col1, lvl1Id);
178  if (li1) dimSiblings(col1, li1);
179
180  const kids1 = (childrenMap[lvl1Id] || childrenMap[Number(lvl1Id)] || []).map(String);
181  if (!kids1.length) return;
182  renderLevel(col2, kids1);
183
184  // L2
185  const lvl2Id = trail[1];
186  if (!lvl2Id) return;
187
188  const li2 = findLi(col2, lvl2Id);
189  if (li2) dimSiblings(col2, li2);
190
191  const kids2 = (childrenMap[lvl2Id] || childrenMap[Number(lvl2Id)] || []).map(String);
192  if (!kids2.length) return;
193  renderLevel(col3, kids2);
194
195  // L3 (solo evidenzio)
196  const lvl3Id = trail[2];
197  if (!lvl3Id) return;
198
199  const li3 = findLi(col3, lvl3Id);
200  if (li3) dimSiblings(col3, li3);
201};
202
203
204  // Stato iniziale
205  clear(col2);
206  clear(col3);
207
208  hydrateFromWpMenu(col1);
209
210  autoOpenFromCurrentPage();
211
212
213  // Click delegation
214  root.addEventListener('click', (e) => {
215    const btn = e.target.closest('.cpm-menu3__btn');
216    if (!btn) return;
217
218    const li = btn.closest('.cpm-menu3__item');
219    const ul = li?.closest('.cpm-menu3__list');
220    if (!li || !ul) return;
221
222    const level = ul.dataset.level;
223    const id = li.dataset.id;
224
225    dimSiblings(ul, li);
226
227    const kids = childrenMap[id] || childrenMap[Number(id)] || [];
228    const hasKids = kids.length > 0;
229
230    if (level === '1') {
231      clear(col3);
232      if (hasKids) {
233        renderLevel(col2, kids);
234      } else {
235        clear(col2);
236      }
237    }
238
239    if (level === '2') {
240      if (hasKids) {
241        renderLevel(col3, kids);
242      } else {
243        clear(col3);
244      }
245    }
246  });
247	
248	//GESTIONE BACKGROUND
249const overlayBg = document.getElementById('headermenu_mobile');
250const BG_IMAGE = 'url(https://www.cpm.it/wp-content/uploads/2026/01/CPM_fondo-desktop_1920x1080.jpg)';
251
252const setOverlayBg = (active) => {
253  if (!overlayBg) return;
254  overlayBg.style.backgroundImage = active ? BG_IMAGE : '';
255};
256
257// click su voce menu -> sfondo attivo
258root.addEventListener('click', (e) => {
259  const btn = e.target.closest('.cpm-menu3__btn');
260  if (!btn) return;
261  setOverlayBg(true);
262});
263
264// bottone "Scegli il tuo corso" desktop -> sfondo attivo
265const chooseBtnDesk = document.getElementById('choose_course_btn_desk');
266if (chooseBtnDesk) {
267  chooseBtnDesk.addEventListener('click', () => setOverlayBg(true));
268}
269
270// se c'è già una voce attiva all'apertura → sfondo nostro
271autoOpenFromCurrentPage();
272if (col1.querySelector('.is-active')) setOverlayBg(true);
273
274// reset sfondo solo quando overlay si chiude
275let bgLastVisible = false;
276setInterval(() => {
277  if (!overlayBg) return;
278  const st = window.getComputedStyle(overlayBg);
279  const isVisible =
280    st.display !== 'none' &&
281    st.visibility !== 'hidden' &&
282    st.opacity !== '0';
283
284  if (isVisible && !bgLastVisible) {
285    const anyActive = col1.querySelector('.is-active');
286    setOverlayBg(!!anyActive);
287  }
288
289  if (!isVisible && bgLastVisible) {
290    setOverlayBg(false);
291  }
292
293  bgLastVisible = isVisible;
294}, 250);
295	
296	
297});

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.