PageSourceSearch

https://www.visitmesaverde.com/scripts/aem.js

js visitmesaverde.com collected 2026-10-02 06:41:41 UTC 28,520 bytes, 888 lines download raw bytes

1/*
2 * Copyright 2025 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12
13/* eslint-env browser */
14function sampleRUM(checkpoint, data) {
15  // eslint-disable-next-line max-len
16  const timeShift = () => (window.performance ? window.performance.now() : Date.now() - window.hlx.rum.firstReadTime);
17  try {
18    window.hlx = window.hlx || {};
19    if (!window.hlx.rum || !window.hlx.rum.collector) {
20      sampleRUM.enhance = () => { };
21      const params = new URLSearchParams(window.location.search);
22      const { currentScript } = document;
23      const rate = params.get('rum')
24        || window.SAMPLE_PAGEVIEWS_AT_RATE
25        || params.get('optel')
26        || (currentScript && currentScript.dataset.rate);
27      const rateValue = {
28        on: 1,
29        off: 0,
30        high: 10,
31        low: 1000,
32      }[rate];
33      const weight = rateValue !== undefined ? rateValue : 100;
34      const id = (window.hlx.rum && window.hlx.rum.id) || crypto.randomUUID().slice(-9);
35      const isSelected = (window.hlx.rum && window.hlx.rum.isSelected)
36        || (weight > 0 && Math.random() * weight < 1);
37      // eslint-disable-next-line object-curly-newline, max-len
38      window.hlx.rum = {
39        weight,
40        id,
41        isSelected,
42        firstReadTime: window.performance ? window.performance.timeOrigin : Date.now(),
43        sampleRUM,
44        queue: [],
45        collector: (...args) => window.hlx.rum.queue.push(args),
46      };
47      if (isSelected) {
48        const dataFromErrorObj = (error) => {
49          const errData = { source: 'undefined error' };
50          try {
51            errData.target = error.toString();
52            if (error.stack) {
53              errData.source = error.stack
54                .split('\n')
55                .filter((line) => line.match(/https?:\/\//))
56                .shift()
57                .replace(/at ([^ ]+) \((.+)\)/, '$1@$2')
58                .replace(/ at /, '@')
59                .trim();
60            }
61          } catch (err) {
62            /* error structure was not as expected */
63          }
64          return errData;
65        };
66
67        window.addEventListener('error', ({ error }) => {
68          const errData = dataFromErrorObj(error);
69          sampleRUM('error', errData);
70        });
71
72        window.addEventListener('unhandledrejection', ({ reason }) => {
73          let errData = {
74            source: 'Unhandled Rejection',
75            target: reason || 'Unknown',
76          };
77          if (reason instanceof Error) {
78            errData = dataFromErrorObj(reason);
79          }
80          sampleRUM('error', errData);
81        });
82
83        window.addEventListener('securitypolicyviolation', (e) => {
84          if (e.blockedURI.includes('helix-rum-enhancer') && e.disposition === 'enforce') {
85            const errData = {
86              source: 'csp',
87              target: e.blockedURI,
88            };
89            sampleRUM.sendPing('error', timeShift(), errData);
90          }
91        });
92
93        sampleRUM.baseURL = sampleRUM.baseURL || new URL(window.RUM_BASE || '/', new URL('https://ot.aem.live'));
94        sampleRUM.collectBaseURL = sampleRUM.collectBaseURL || sampleRUM.baseURL;
95        sampleRUM.sendPing = (ck, time, pingData = {}) => {
96          // eslint-disable-next-line max-len, object-curly-newline
97          const rumData = JSON.stringify({
98            weight,
99            id,
100            referer: window.location.href,
101            checkpoint: ck,
102            t: time,
103            ...pingData,
104          });
105          const urlParams = window.RUM_PARAMS
106            ? new URLSearchParams(window.RUM_PARAMS).toString() || ''
107            : '';
108          const { href: url, origin } = new URL(
109            `.rum/${weight}
109${urlParams ? `?${urlParams}` : ''}`,
110            sampleRUM.collectBaseURL,
111          );
112          const body = origin === window.location.origin
113            ? new Blob([rumData], { type: 'application/json' })
114            : rumData;
115          navigator.sendBeacon(url, body);
116          // eslint-disable-next-line no-console
117          console.debug(`ping:${ck}`, pingData);
118        };
119        sampleRUM.sendPing('top', timeShift());
120
121        sampleRUM.enhance = () => {
122          // only enhance once
123          if (document.querySelector('script[src*="rum-enhancer"]')) return;
124          const { enhancerVersion, enhancerHash } = sampleRUM.enhancerContext || {};
125          const script = document.createElement('script');
126          if (enhancerHash) {
127            script.integrity = enhancerHash;
128            script.setAttribute('crossorigin', 'anonymous');
129          }
130          script.src = new URL(
131            `.rum/@adobe/helix-rum-enhancer@${enhancerVersion || '^2'}/src/index.js`,
132            sampleRUM.baseURL,
133          ).href;
134          document.head.appendChild(script);
135        };
136        if (!window.hlx.RUM_MANUAL_ENHANCE) {
137          sampleRUM.enhance();
138        }
139      }
140    }
141    if (window.hlx.rum && window.hlx.rum.isSelected && checkpoint) {
142      window.hlx.rum.collector(checkpoint, data, timeShift());
143    }
144    document.dispatchEvent(new CustomEvent('rum', { detail: { checkpoint, data } }));
145  } catch (error) {
146    // something went awry
147  }
148}
149
150/**
151 * Setup block utils.
152 */
153function setup() {
154  window.hlx = window.hlx || {};
155  window.hlx.RUM_MASK_URL = 'full';
156  window.hlx.RUM_MANUAL_ENHANCE = true;
157  window.hlx.codeBasePath = '';
158  window.hlx.lighthouse = new URLSearchParams(window.location.search).get('lighthouse') === 'on';
159
160  const scriptEl = document.querySelector('script[src$="/scripts/scripts.js"]');
161  if (scriptEl) {
162    try {
163      const scriptURL = new URL(scriptEl.src, window.location);
164      if (scriptURL.host === window.location.host) {
165        [window.hlx.codeBasePath] = scriptURL.pathname.split('/scripts/scripts.js');
166      } else {
167        [window.hlx.codeBasePath] = scriptURL.href.split('/scripts/scripts.js');
168      }
169    } catch (error) {
170      // eslint-disable-next-line no-console
171      console.log(error);
172    }
173  }
174}
175
176/**
177 * Auto initialization.
178 */
179
180function init() {
181  setup();
182  sampleRUM.collectBaseURL = window.origin;
183  sampleRUM();
184}
185
186/**
187 * Sanitizes a string for use as class name.
188 * @param {string} name The unsanitized string
189 * @returns {string} The class name
190 */
191function toClassName(name) {
192  return typeof name === 'string'
193    ? name
194      .toLowerCase()
195      .replace(/[^0-9a-z]/gi, '-')
196      .replace(/-+/g, '-')
197      .replace(/^-|-$/g, '')
198    : '';
199}
200
201/**
202 * Sanitizes a string for use as a js property name.
203 * @param {string} name The unsanitized string
204 * @returns {string} The camelCased name
205 */
206function toCamelCase(name) {
207  return toClassName(name).replace(/-([a-z])/g, (g) => g[1].toUpperCase());
208}
209
210/**
211 * Extracts the config from a block.
212 * @param {Element} block The block element
213 * @returns {object} The block config
214 */
215// eslint-disable-next-line import/prefer-default-export
216function readBlockConfig(block) {
217  const config = {};
218  block.querySelectorAll(':scope > div').forEach((row) => {
219    if (row.children) {
220      const cols = [...row.children];
221      if (cols[1]) {
222        const col = cols[1];
223        const name = toClassName(cols[0].textContent);
224        let value = '';
225        if (col.querySelector('a')) {
226          const as = [...col.querySelectorAll('a')];
227          if (as.length === 1) {
228            // For DAM paths, prefer textContent over href — Franklin delivery
229            // normalizes hrefs (lowercase + underscore→hyphen) which breaks
230            // case-sensitive JCR DAM lookups on AEM Publish.
231            const a = as[0];
232            const text = a.textContent.trim();
233            value = (text.startsWith('/content/dam/') && a.href.includes('/content/dam/'))
234              ? text : a.href;
235          } else {
236            value = as.map((a) => {
237              const text = a.textContent.trim();
238              return (text.startsWith('/content/dam/') && a.href.includes('/content/dam/'))
239                ? text : a.href;
240            });
241          }
242        } else if (col.querySelector('img')) {
243          const imgs = [...col.querySelectorAll('img')];
244          if (imgs.length === 1) {
245            value = imgs[0].src;
246          } else {
247            value = imgs.map((img) => img.src);
248          }
249        } else if (col.querySelector('p')) {
250          const ps = [...col.querySelectorAll('p')];
251          if (ps.length === 1) {
252            value = ps[0].textContent;
253          } else {
254            value = ps.map((p) => p.textContent);
255          }
256        } else value = row.children[1].textContent;
257        config[name] = value;
258      }
259    }
260  });
261  return config;
262}
263
264/**
265 * Loads a CSS file.
266 * @param {string} href URL to the CSS file
267 */
268async function loadCSS(href) {
269  return new Promise((resolve, reject) => {
270    if (!document.querySelector(`head > link[href="${href}"]`)) {
271      const link = document.createElement('link');
272      link.rel = 'stylesheet';
273      link.href = href;
274      link.onload = resolve;
275      link.onerror = reject;
276      document.head.append(link);
277    } else {
278      resolve();
279    }
280  });
281}
282
283/**
284 * Loads a non module JS file.
285 * @param {string} src URL to the JS file
286 * @param {Object} attrs additional optional attributes
287 */
288async function loadScript(src, attrs) {
289  return new Promise((resolve, reject) => {
290    if (!document.querySelector(`head > script[src="${src}"]`)) {
291      const script = document.createElement('script');
292      script.src = src;
293      if (attrs) {
294        // eslint-disable-next-line no-restricted-syntax, guard-for-in
295        for (const attr in attrs) {
296          script.setAttribute(attr, attrs[attr]);
297        }
298      }
299      script.onload = resolve;
300      script.onerror = reject;
301      document.head.append(script);
302    } else {
303      resolve();
304    }
305  });
306}
307
308/**
309 * Retrieves the content of metadata tags.
310 * @param {string} name The metadata name (or property)
311 * @param {Document} doc Document object to query for metadata. Defaults to the window's document
312 * @returns {string} The metadata value(s)
313 */
314function getMetadata(name, doc = document) {
315  const attr = name && name.includes(':') ? 'property' : 'name';
316  const meta = [...doc.head.querySelectorAll(`meta[${attr}="${name}"]`)]
317    .map((m) => m.content)
318    .join(', ');
319  return meta || '';
320}
321
322/**
323 * Returns a picture element with webp and fallbacks
324 * @param {string} src The image URL
325 * @param {string} [alt] The image alternative text
326 * @param {boolean} [eager] Set loading attribute to eager
327 * @param {Array} [breakpoints] Breakpoints and corresponding params (eg. width)
328 * @returns {Element} The picture element
329 */
330function createOptimizedPicture(
331  src,
332  alt = '',
333  eager = false,
334  breakpoints = [{ media: '(min-width: 600px)', width: '2000' }, { width: '750' }],
335) {
336  const url = new URL(src, window.location.href);
337  const picture = document.createElement('picture');
338  const { pathname } = url;
339  const ext = pathname.substring(pathname.lastIndexOf('.') + 1);
340
341  // webp
342  breakpoints.forEach((br) => {
343    const source = document.createElement('source');
344    if (br.media) source.setAttribute('media', br.media);
345    source.setAttribute('type', 'image/webp');
346    source.setAttribute('srcset', `${pathname}?width=${br.width}&format=webply&optimize=medium`);
347    picture.appendChild(source);
348  });
349
350  // fallback
351  breakpoints.forEach((br, i) => {
352    if (i < breakpoints.length - 1) {
353      const source = document.createElement('source');
354      if (br.media) source.setAttribute('media', br.media);
355      source.setAttribute('srcset', `${pathname}?width=${br.width}&format=${ext}&optimize=medium`);
356      picture.appendChild(source);
357    } else {
358      const img = document.createElement('img');
359      img.setAttribute('loading', eager ? 'eager' : 'lazy');
360      img.setAttribute('alt', alt);
361      picture.appendChild(img);
362      img.setAttribute('src', `${pathname}?width=${br.width}&format=${ext}&optimize=medium`);
363    }
364  });
365
366  return picture;
367}
368
369/**
370 * Set template (page structure) and theme (page styles).
371 */
372function decorateTemplateAndTheme() {
373  const addClasses = (element, classes) => {
374    classes.split(',').forEach((c) => {
375      element.classList.add(toClassName(c.trim()));
376    });
377  };
378  const template = getMetadata('template');
379  if (template) addClasses(document.body, template);
380  const theme = getMetadata('theme');
381  if (theme) addClasses(document.body, theme);
382}
383
384/**
385 * Wrap inline text content of block cells within a <p> tag.
386 * @param {Element} block the block element
387 */
388function wrapTextNodes(block) {
389  const validWrappers = [
390    'P',
391    'PRE',
392    'UL',
393    'OL',
394    'PICTURE',
395    'TABLE',
396    'H1',
397    'H2',
398    'H3',
399    'H4',
400    'HR',
401  ];
402
403  const wrap = (el) => {
404    const wrapper = document.createElement('p');
405    wrapper.append(...el.childNodes);
406    [...el.attributes]
407      // move the instrumentation from the cell to the new paragraph, also keep the class
408      // in case the content is a buttton and the cell the button-container
409      .filter(({ nodeName }) => nodeName === 'class'
410        || nodeName.startsWith('data-aue')
411        || nodeName.startsWith('data-richtext'))
412      .forEach(({ nodeName, nodeValue }) => {
413        wrapper.setAttribute(nodeName, nodeValue);
414        el.removeAttribute(nodeName);
415      });
416    el.append(wrapper);
417  };
418
419  block.querySelectorAll(':scope > div > div').forEach((blockColumn) => {
420    if (blockColumn.hasChildNodes()) {
421      const hasWrapper = !!blockColumn.firstElementChild
422        && validWrappers.some((tagName) => blockColumn.firstElementChild.tagName === tagName);
423      if (!hasWrapper) {
424        wrap(blockColumn);
425      } else if (
426        blockColumn.firstElementChild.tagName === 'PICTURE'
427        && (blockColumn.children.length > 1 || !!blockColumn.textContent.trim())
428      ) {
429        wrap(blockColumn);
430      }
431    }
432  });
433}
434
435/**
436 * Decorates paragraphs containing a single link as buttons.
437 * @param {Element} element container element
438 */
439function decorateButtons(element) {
440  element.querySelectorAll('a').forEach((a) => {
441    a.title = a.title || a.textContent;
442    if (a.closest('.cta')) return;
443    if (a.href !== a.textContent) {
444      const up = a.parentElement;
445      const twoup = a.parentElement.parentElement;
446      if (!a.querySelector('img')) {
447        if (up.childNodes.length === 1 && (up.tagName === 'P' || up.tagName === 'DIV')) {
448          a.className = 'button'; // default
449          up.classList.add('button-container');
450        }
451        if (
452          up.childNodes.length === 1
453          && up.tagName === 'STRONG'
454          && twoup.childNodes.length === 1
455          && twoup.tagName === 'P'
456        ) {
457          a.className = 'button primary';
458          twoup.classList.add('button-container');
459        }
460        if (
461          up.childNodes.length === 1
462          && up.tagName === 'EM'
463          && twoup.childNodes.length === 1
464          && twoup.tagName === 'P'
465        ) {
466          a.className = 'button secondary';
467          twoup.classList.add('button-container');
468        }
469      }
470    }
471  });
472}
473
474/**
475 * Add <img> for icon, prefixed with codeBasePath and optional prefix.
476 * @param {Element} [span] span element with icon classes
477 * @param {string} [prefix] prefix to be added to icon src
478 * @param {string} [alt] alt text to be added to icon
479 */
480function decorateIcon(span, prefix = '', alt = '') {
481  const iconName = Array.from(span.classList)
482    .find((c) => c.startsWith('icon-'))
483    .substring(5);
484  const img = document.createElement('img');
485  img.dataset.iconName = iconName;
486  img.src = `${window.hlx.codeBasePath}${prefix}/icons/${iconName}.svg`;
487  img.alt = alt;
488  img.loading = 'lazy';
489  img.width = 16;
490  img.height = 16;
491  span.append(img);
492}
493
494/**
495 * Add <img> for icons, prefixed with codeBasePath and optional prefix.
496 * @param {Element} [element] Element containing icons
497 * @param {string} [prefix] prefix to be added to icon the src
498 */
499function decorateIcons(element, prefix = '') {
500  const icons = element.querySelectorAll('span.icon');
501  icons.forEach((span) => {
502    decorateIcon(span, prefix);
503  });
504}
505
506/**
507 * Decorates all sections in a container element.
508 * @param {Element} main The container element
509 */
510function decorateSections(main) {
511  main.querySelectorAll(':scope > div:not([data-section-status])').forEach((section) => {
512    const wrappers = [];
513    let defaultContent = false;
514    [...section.children].forEach((e) => {
515      if ((e.tagName === 'DIV' && e.className) || !defaultContent) {
516        const wrapper = document.createElement('div');
517        wrappers.push(wrapper);
518        defaultContent = e.tagName !== 'DIV' || !e.className;
519        if (defaultContent) wrapper.classList.add('default-content-wrapper');
520      }
521      wrappers[wrappers.length - 1].append(e);
522    });
523    wrappers.forEach((wrapper) => section.append(wrapper));
524    section.classList.add('section');
525    section.dataset.sectionStatus = 'initialized';
526    section.style.display = 'none';
527
528    // Process section metadata
529    const sectionMeta = section.querySelector('div.section-metadata');
530    if (sectionMeta) {
531      const meta = readBlockConfig(sectionMeta);
532      Object.keys(meta).forEach((key) => {
533        if (key === 'style') {
534          const styles = meta.style
535            .split(',')
536            .filter((style) => style)
537            .map((style) => toClassName(style.trim()));
538          styles.forEach((style) => section.classList.add(style));
539        } else {
540          section.dataset[toCamelCase(key)] = meta[key];
541        }
542      });
543      sectionMeta.parentNode.remove();
544    }
545  });
546}
547
548/**
549 * Builds a block DOM Element from a two dimensional array, string, or object
550 * @param {string} blockName name of the block
551 * @param {*} content two dimensional array or string or object of content
552 */
553function buildBlock(blockName, content) {
554  const table = Array.isArray(content) ? content : [[content]];
555  const blockEl = document.createElement('div');
556  // build image block nested div structure
557  blockEl.classList.add(blockName);
558  table.forEach((row) => {
559    const rowEl = document.createElement('div');
560    row.forEach((col) => {
561      const colEl = document.createElement('div');
562      const vals = col.elems ? col.elems : [col];
563      vals.forEach((val) => {
564        if (val) {
565          if (typeof val === 'string') {
566            colEl.innerHTML += val;
567          } else {
568            colEl.appendChild(val);
569          }
570        }
571      });
572      rowEl.appendChild(colEl);
573    });
574    blockEl.appendChild(rowEl);
575  });
576  return blockEl;
577}
578
579/**
580 * Attempts to load a resource from multiple paths
581 * @param {string[]} paths Array of paths to try
582 * @param {Function} loader Function to load the resource
583 * @returns {Promise<any>} The loaded resource or null
584 */
585async function loadFromPaths(paths, loader) {
586  const attempted = [];
587  let lastError = null;
588  let failedPath = null;
589
590  for (const path of paths) {
591    const candidates = [];
592    const basePath = window.hlx?.codeBasePath || '';
593    candidates.push(`${basePath}${path}.js`);
594    candidates.push(`${path}.js`);
595
596    const scriptEls = [
597      ...document.querySelectorAll('script[src*="/scripts/scripts.js"]'),
598    ];
599    scriptEls.forEach((scriptEl) => {
600      try {
601        const scriptURL = new URL(scriptEl.src, window.location);
602        const [scriptBase] = scriptURL.href.split('/scripts/scripts.js');
603        if (scriptBase) {
604          candidates.push(`${scriptBase}${path}.js`);
605        }
606      } catch (error) {
607        // Ignore bad script URL entries and continue with other candidates.
608      }
609    });
610
611    const uniqueCandidates = [...new Set(candidates.filter(Boolean))];
612
613    for (let i = 0; i < uniqueCandidates.length; i += 1) {
614      const candidate = uniqueCandidates[i];
615      attempted.push(candidate);
616      try {
617        const result = await loader(candidate);
618        return {
619          result,
620          attempted,
621          failedPath: null,
622          error: null,
623        };
624      } catch (error) {
625        lastError = error;
626      }
627    }
628
629    if (lastError) failedPath = path;
630  }
631
632  return {
633    result: null,
634    attempted,
635    failedPath,
636    error: lastError,
637  };
638}
639
640/**
641 * Loads JS and CSS for a block with site resolution support.
642 * Resolution order: brands/{brand}/blocks → /blocks
643 * @param {Element} block The block element
644 */
645async function loadBlock(block) {
646  const status = block.dataset.blockStatus;
647  if (status !== 'loading' && status !== 'loaded') {
648    block.dataset.blockStatus = 'loading';
649    const { blockName } = block.dataset;
650
651    try {
652      // Import site resolver dynamically
653      const { getBlockPaths, getCurrentBrand, hasBrandCssOverride } = await import('./site-resolver.js');
654
655      // Get JS resolution paths (brand-specific only if declared in overrides.js)
656      const jsPaths = getBlockPaths(blockName);
657
658      // Load CSS in parallel: shared first (guaranteed), brand second (overrides via DOM order)
659      // Brand CSS only requested if declared in overrides — avoids 404s on every block
660      const brand = getCurrentBrand();
661      const sharedCss = loadCSS(
662        `${window.hlx.codeBasePath}/blocks/${blockName}/${blockName}.css`,
663      ).catch(() => { });
664      const brandCss = (brand && hasBrandCssOverride(blockName))
665        ? loadCSS(
666          `${window.hlx.codeBasePath}/brands/${brand}/blocks/${blockName}/${blockName}.css`,
667        ).catch(() => { })
668        : Promise.resolve();
669      const cssLoaded = Promise.all([sharedCss, brandCss]);
670
671      // Try to load JS from resolution paths
672      const decorationComplete = new Promise((resolve) => {
673        (async () => {
674          try {
675            const {
676              result: mod, attempted, failedPath, error,
677            } = await loadFromPaths(
678              jsPaths,
679              (url) => import(url),
680            );
681
682            if (mod && mod.default) {
683              await mod.default(block);
684            } else if (error) {
685              // eslint-disable-next-line no-console
686              console.error(
687                `failed to load module for ${blockName} from ${failedPath || 'unknown path'}`,
688                error,
689              );
690              // eslint-disable-next-line no-console
691              console.warn(`Attempted module URLs for ${blockName}: ${attempted.join(', ')}`);
692            } else {
693              // eslint-disable-next-line no-console
694              console.warn(`No module found for ${blockName} in any resolution path`);
695              // eslint-disable-next-line no-console
696              console.warn(`Attempted module URLs for ${blockName}: ${attempted.join(', ')}`);
697            }
698          } catch (error) {
699            // eslint-disable-next-line no-console
700            console.error(`failed to load module for ${blockName}`, error);
701          }
702          const { decorateExternalLinks } = await import('./link-utils.js');
703          decorateExternalLinks(block);
704          resolve();
705        })();
706      });
707
708      await Promise.all([cssLoaded, decorationComplete]);
709    } catch (error) {
710      // eslint-disable-next-line no-console
711      console.error(`failed to load block ${blockName}`, error);
712    }
713    block.dataset.blockStatus = 'loaded';
714  }
715  return block;
716}
717
718/**
719 * Decorates a block.
720 * @param {Element} block The block element
721 */
722function decorateBlock(block) {
723  const shortBlockName = block.classList[0];
724  if (shortBlockName && !block.dataset.blockStatus) {
725    block.classList.add('block');
726    block.dataset.blockName = shortBlockName;
727    block.dataset.blockStatus = 'initialized';
728    wrapTextNodes(block);
729    const blockWrapper = block.parentElement;
730    blockWrapper.classList.add(`${shortBlockName}-wrapper`);
731    const section = block.closest('.section');
732    if (section) section.classList.add(`${shortBlockName}-container`);
733    // eslint-disable-next-line no-use-before-define
734    decorateButtons(block);
735  }
736}
737
738/**
739 * Decorates all blocks in a container element.
740 * @param {Element} main The container element
741 */
742function decorateBlocks(main) {
743  main.querySelectorAll('div.section > div > div').forEach(decorateBlock);
744}
745
746/**
747 * Decorates and loads nested blocks inside a container element (e.g. tabs, columns).
748 * Container blocks call this after their own DOM restructuring to initialize
749 * any child blocks that the standard decorateBlocks() pipeline doesn't reach.
750 * @param {Element} container The container element to search for nested blocks
751 * @returns {Promise<void>}
752 */
753async function loadNestedBlocks(container) {
754  const nestedBlocks = [...container.querySelectorAll(':scope div[class]:not
754(.block)')]
755    .filter((el) => el.classList[0] && !el.dataset.blockStatus);
756  for (let i = 0; i < nestedBlocks.length; i += 1) {
757    const el = nestedBlocks[i];
758    // Ensure the element has a wrapper parent (decorateBlock assumes parentElement exists)
759    if (!el.parentElement || el.parentElement === container) {
760      const wrapper = document.createElement('div');
761      el.parentNode.insertBefore(wrapper, el);
762      wrapper.append(el);
763    }
764    decorateBlock(el);
765    // eslint-disable-next-line no-await-in-loop
766    await loadBlock(el);
767  }
768}
769
770/**
771 * Loads a block named 'header' into header
772 * @param {Element} header header element
773 * @returns {Promise}
774 */
775async function loadHeader(header) {
776  const headerBlock = buildBlock('header', '');
777  header.append(headerBlock);
778  decorateBlock(headerBlock);
779  return loadBlock(headerBlock);
780}
781
782/**
783 * Loads a block named 'footer' into footer
784 * @param footer footer element
785 * @returns {Promise}
786 */
787async function loadFooter(footer) {
788  const footerBlock = buildBlock('footer', '');
789  footer.append(footerBlock);
790  decorateBlock(footerBlock);
791  return loadBlock(footerBlock);
792}
793
794/**
795 * Wait for Image.
796 * @param {Element} section section element
797 */
798async function waitForFirstImage(section) {
799  const lcpCandidate = section.querySelector('img');
800  await new Promise((resolve) => {
801    if (lcpCandidate && !lcpCandidate.complete) {
802      lcpCandidate.setAttribute('loading', 'eager');
803      lcpCandidate.addEventListener('load', resolve);
804      lcpCandidate.addEventListener('error', resolve);
805    } else {
806      resolve();
807    }
808  });
809}
810
811/**
812 * Loads all blocks in a section.
813 * @param {Element} section The section element
814 */
815
816async function loadSection(section, loadCallback) {
817  const status = section.dataset.sectionStatus;
818  if (!status || status === 'initialized') {
819    section.dataset.sectionStatus = 'loading';
820    const blocks = [...section.querySelectorAll('div.block')];
821    for (let i = 0; i < blocks.length; i += 1) {
822      // eslint-disable-next-line no-await-in-loop
823      await loadBlock(blocks[i]);
824    }
825    if (loadCallback) await loadCallback(section);
826    section.dataset.sectionStatus = 'loaded';
827    section.style.display = null;
828  }
829}
830
831/**
832 * Loads all sections.
833 * @param {Element} element The parent element of sections to load
834 */
835
836async function loadSections(element) {
837  const sections = [...element.querySelectorAll('div.section')];
838  for (let i = 0; i < sections.length; i += 1) {
839    // eslint-disable-next-line no-await-in-loop
840    await loadSection(sections[i]);
841    if (i === 0 && sampleRUM.enhance) {
842      sampleRUM.enhance();
843    }
844  }
845}
846
847function extractAueConfig(block) {
848  const config = {};
849  const auePropElements = block.querySelectorAll('[data-aue-prop]');
850  auePropElements.forEach((el) => {
851    const prop = el.getAttribute('data-aue-prop');
852    const value = el.textContent.trim();
853    if (prop && value) {
854      config[prop] = value;
855    }
856  });
857  return config;
858}
859
860init();
861
862export {
863  buildBlock,
864  createOptimizedPicture,
865  extractAueConfig,
866  decorateBlock,
867  decorateBlocks,
868  decorateButtons,
869  decorateIcons,
870  decorateSections,
871  decorateTemplateAndTheme,
872  getMetadata,
873  loadBlock,
874  loadCSS,
875  loadFooter,
876  loadNestedBlocks,
877  loadHeader,
878  loadScript,
879  loadSection,
880  loadSections,
881  readBlockConfig,
882  sampleRUM,
883  setup,
884  toCamelCase,
885  toClassName,
886  waitForFirstImage,
887  wrapTextNodes,
888};

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.