PageSourceSearch

https://www.blueacornici.com/scripts/lib-franklin.js

js blueacornici.com collected 2026-09-26 02:03:25 UTC 13,343 bytes, 389 lines download raw bytes

1/*
2 * Copyright 2022 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
13import { loadBlock } from './load.js';
14
15/**
16 * log RUM if part of the sample.
17 * @param {string} checkpoint identifies the checkpoint in funnel
18 * @param {Object} data additional data for RUM sample
19 */
20export function sampleRUM(checkpoint, data = {}) {
21  sampleRUM.defer = sampleRUM.defer || [];
22  const defer = (fnname) => {
23    sampleRUM[fnname] = sampleRUM[fnname]
24      || ((...args) => sampleRUM.defer.push({ fnname, args }));
25  };
26  sampleRUM.drain = sampleRUM.drain
27    || ((dfnname, fn) => {
28      sampleRUM[dfnname] = fn;
29      sampleRUM.defer
30        .filter(({ fnname }) => dfnname === fnname)
31        .forEach(({ fnname, args }) => sampleRUM[fnname](...args));
32    });
33  sampleRUM.on = (chkpnt, fn) => { sampleRUM.cases[chkpnt] = fn; };
34  defer('observe');
35  defer('cwv');
36  try {
37    window.hlx = window.hlx || {};
38    if (!window.hlx.rum) {
39      const usp = new URLSearchParams(window.location.search);
40      const weight = (usp.get('rum') === 'on') ? 1 : 100; // with parameter, weight is 1. Defaults to 100.
41      // eslint-disable-next-line no-bitwise
42      const hashCode = (s) => s.split('').reduce((a, b) => (((a << 5) - a) + b.charCodeAt(0)) | 0, 0);
43      const id = `${hashCode(window.location.href)}-${new Date().getTime()}-${Math.random().toString(16).substr(2, 14)}`;
44      const random = Math.random();
45      const isSelected = (random * weight < 1);
46      const urlSanitizers = {
47        full: () => window.location.href,
48        origin: () => window.location.origin,
49        path: () => window.location.href.replace(/\?.*$/, ''),
50      };
51      // eslint-disable-next-line object-curly-newline
52      window.hlx.rum = { weight, id, random, isSelected, sampleRUM, sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'] };
53    }
54    const { weight, id } = window.hlx.rum;
55    if (window.hlx && window.hlx.rum && window.hlx.rum.isSelected) {
56      const sendPing = (pdata = data) => {
57        // eslint-disable-next-line object-curly-newline, max-len
58        const body = JSON.stringify({ weight, id, referer: window.hlx.rum.sanitizeURL(), checkpoint, ...data });
59        const url = `https://rum.hlx.page/.rum/${weight}`;
60
61        navigator.sendBeacon(url, body);
62
63        console.debug(`ping:${checkpoint}`, pdata);
64      };
65      sampleRUM.cases = sampleRUM.cases || {
66        cwv: () => sampleRUM.cwv(data) || true,
67        lazy: () => {
68          // use classic script to avoid CORS issues
69          const script = document.createElement('script');
70          script.src = 'https://rum.hlx.page/.rum/@adobe/helix-rum-enhancer@^1/src/index.js';
71          document.head.appendChild(script);
72          return true;
73        },
74      };
75      sendPing(data);
76      if (sampleRUM.cases[checkpoint]) { sampleRUM.cases[checkpoint](); }
77    }
78  } catch (error) {
79    // something went wrong
80    console.error('Failed to sample RUM', error);
81  }
82}
83
84/**
85 * Retrieves the content of metadata tags.
86 * @param {string} name The metadata name (or property)
87 * @returns {string} The metadata value(s)
88 */
89export function getMetadata(name) {
90  const attr = name && name.includes(':') ? 'property' : 'name';
91  const meta = [...document.head.querySelectorAll(`meta[${attr}="${name}"]`)].map((m) => m.content).join(', ');
92  return meta || '';
93}
94
95/**
96 * Sanitizes a string for use as class name.
97 * @param {string} name The unsanitized string
98 * @returns {string} The class name
99 */
100export function toClassName(name) {
101  return typeof name === 'string'
102    ? name.toLowerCase().replace(/[^0-9a-z]/gi, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')
103    : '';
104}
105
106/**
107 * Sanitizes a string for use as a js property name.
108 * @param {string} name The unsanitized string
109 * @returns {string} The camelCased name
110 */
111export function toCamelCase(name) {
112  return toClassName(name).replace(/-([a-z])/g, (g) => g[1].toUpperCase());
113}
114
115/**
116 * Gets placeholders object.
117 * @param {string} [prefix] Location of placeholders
118 * @returns {object} Window placeholders object
119 */
120export async function fetchPlaceholders(prefix = 'default') {
121  window.placeholders = window.placeholders || {};
122  const loaded = window.placeholders[`${prefix}-loaded`];
123  if (!loaded) {
124    window.placeholders[`${prefix}-loaded`] = new Promise((resolve, reject) => {
125      fetch(`${prefix === 'default' ? '' : prefix}/placeholders.json`)
126        .then((resp) => {
127          if (resp.ok) {
128            return resp.json();
129          }
130          throw new Error(`${resp.status}: ${resp.statusText}`);
131        }).then((json) => {
132          const placeholders = {};
133          json.data
134            .filter((placeholder) => placeholder.Key)
135            .forEach((placeholder) => {
136              placeholders[toCamelCase(placeholder.Key)] = placeholder.Text;
137            });
138          window.placeholders[prefix] = placeholders;
139          resolve();
140        }).catch((error) => {
141          // error loading placeholders
142          window.placeholders[prefix] = {};
143          reject(error);
144        });
145    });
146  }
147  await window.placeholders[`${prefix}-loaded`];
148  return window.placeholders[prefix];
149}
150
151/**
152 * Extracts the config from a block.
153 * @param {Element} block The block element
154 * @returns {object} The block config
155 */
156export function readBlockConfig(block) {
157  const config = {};
158  block.querySelectorAll(':scope > div').forEach((row) => {
159    if (row.children) {
160      const cols = [...row.children];
161      if (cols[1]) {
162        const col = cols[1];
163        const name = toClassName(cols[0].textContent);
164        let value = '';
165        if (col.querySelector('a')) {
166          const as = [...col.querySelectorAll('a')];
167          if (as.length === 1) {
168            value = as[0].href;
169          } else {
170            value = as.map((a) => a.href);
171          }
172        } else if (col.querySelector('img')) {
173          const imgs = [...col.querySelectorAll('img')];
174          if (imgs.length === 1) {
175            value = imgs[0].src;
176          } else {
177            value = imgs.map((img) => img.src);
178          }
179        } else if (col.querySelector('p')) {
180          const ps = [...col.querySelectorAll('p')];
181          if (ps.length === 1) {
182            value = ps[0].textContent;
183          } else {
184            value = ps.map((p) => p.textContent);
185          }
186        } else value = row.children[1].textContent;
187        config[name] = value;
188      }
189    }
190  });
191  return config;
192}
193
194/**
195 * Updates all section status in a container element.
196 * @param {Element} main The container element
197 */
198export function updateSectionsStatus(main) {
199  const sections = [...main.querySelectorAll(':scope > div.section')];
200  for (let i = 0; i < sections.length; i += 1) {
201    const section = sections[i];
202    const status = section.dataset.sectionStatus;
203    if (status !== 'loaded') {
204      const loadingBlock = section.querySelector('.block[data-block-status="initialized"], .block[data-block-status="loading"]');
205      if (loadingBlock) {
206        section.dataset.sectionStatus = 'loading';
207        break;
208      } else {
209        section.dataset.sectionStatus = 'loaded';
210        section.style.display = null;
211      }
212    }
213  }
214}
215
216/**
217 * Builds a block DOM Element from a two dimensional array, string, or object
218 * @param {string} blockName name of the block
219 * @param {*} content two dimensional array or string or object of content
220 */
221export function buildBlock(blockName, content) {
222  const table = Array.isArray(content) ? content : [[content]];
223  const blockEl = document.createElement('div');
224  // build image block nested div structure
225  blockEl.classList.add(blockName);
226  table.forEach((row) => {
227    const rowEl = document.createElement('div');
228    row.forEach((col) => {
229      const colEl = document.createElement('div');
230      const vals = col.elems ? col.elems : [col];
231      vals.forEach((val) => {
232        if (val) {
233          if (typeof val === 'string') {
234            colEl.innerHTML += val;
235          } else {
236            colEl.appendChild(val);
237          }
238        }
239      });
240      rowEl.appendChild(colEl);
241    });
242    blockEl.appendChild(rowEl);
243  });
244  return (blockEl);
245}
246
247/**
248 * Returns a picture element with webp and fallbacks
249 * @param {string} src The image URL
250 * @param {string} [alt] The image alternative text
251 * @param {boolean} [eager] Set loading attribute to eager
252 * @param {Array} [breakpoints] Breakpoints and corresponding params (eg. width)
253 * @returns {Element} The picture element
254 */
255export function createOptimizedPicture(src, alt = '', eager = false, breakpoints = [{ media: '(min-width: 600px)', width: '2000' }, { width: '750' }]) {
256  const url = new URL(src, document.baseURI);
257  const picture = document.createElement('picture');
258  const { pathname } = url;
259  const ext = pathname.substring(pathname.lastIndexOf('.') + 1);
260
261  // webp
262  breakpoints.forEach((br) => {
263    const source = document.createElement('source');
264    if (br.media) source.setAttribute('media', br.media);
265    source.setAttribute('type', 'image/webp');
266    source.setAttribute('srcset', `${pathname}?width=${br.width}&format=webp&optimize=medium`);
267    picture.appendChild(source);
268  });
269
270  // fallback
271  breakpoints.forEach((br, i) => {
272    if (i < breakpoints.length - 1) {
273      const source = document.createElement('source');
274      if (br.media) source.setAttribute('media', br.media);
275      source.setAttribute('srcset', `${pathname}?width=${br.width}&format=${ext}&optimize=medium`);
276      picture.appendChild(source);
277    } else {
278      const img = document.createElement('img');
279      img.setAttribute('loading', eager ? 'eager' : 'lazy');
280      img.setAttribute('alt', alt);
281      picture.appendChild(img);
282      img.setAttribute('src', `${pathname}?width=${br.width}&format=${ext}&optimize=medium`);
283    }
284  });
285
286  return picture;
287}
288
289/**
290 * Normalizes all headings within a container element.
291 * @param {Element} el The container element
292 * @param {string} allowedHeadings The list of allowed headings (h1 ... h6)
293 */
294export function normalizeHeadings(el, allowedHeadings) {
295  const allowed = allowedHeadings.map((h) => h.toLowerCase());
296  el.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach((tag) => {
297    const h = tag.tagName.toLowerCase();
298    if (allowed.indexOf(h) === -1) {
299      // current heading is not in the allowed list -> try first to "promote" the heading
300      let level = parseInt(h.charAt(1), 10) - 1;
301      while (allowed.indexOf(`h${level}`) === -1 && level > 0) {
302        level -= 1;
303      }
304      if (level === 0) {
305        // did not find a match -> try to "downgrade" the heading
306        while (allowed.indexOf(`h${level}`) === -1 && level < 7) {
307          level += 1;
308        }
309      }
310      if (level !== 7) {
311        tag.outerHTML = `<h${level} id="${tag.id}">${tag.textContent}</h${level}>`;
312      }
313    }
314  });
315}
316
317/**
318 * Load LCP block and/or wait for LCP in default content.
319 */
320export async function waitForLCP(lcpBlocks) {
321  const block = document.querySelector('.block');
322  const hasLCPBlock = (block && lcpBlocks.includes(block.dataset.blockName));
323  if (hasLCPBlock) await loadBlock(block);
324
325  document.body.style.display = null;
326  const lcpCandidate = document.querySelector('main img');
327  await new Promise((resolve) => {
328    if (lcpCandidate && !lcpCandidate.complete) {
329      lcpCandidate.setAttribute('loading', 'eager');
330      lcpCandidate.addEventListener('load', resolve);
331      lcpCandidate.addEventListener('error', resolve);
332    } else {
333      resolve();
334    }
335  });
336}
337
338export function getEnvironment() {
339  const { hostname } = window.location;
340
341  if (hostname.includes('localhost')) {
342    return 'dev';
343  } if (hostname.includes('hlx.page')) {
344    return 'staging';
345  } if (hostname.includes('hlx.live')) {
346    return 'production';
347  }
348  return 'unknown';
349}
350
351/**
352 * Setup block utils.
353 */
354export function setup() {
355  window.hlx = window.hlx || {};
356  window.hlx.RUM_MASK_URL = 'full';
357  window.hlx.codeBasePath = '';
358  window.hlx.lighthouse = new URLSearchParams(window.location.search).get('lighthouse') === 'on';
359
360  const scriptEl = document.querySelector('script[src$="/scripts/scripts.js"]');
361  if (scriptEl) {
362    try {
363      [window.hlx.codeBasePath] = new URL(scriptEl.src).pathname.split('/scripts/scripts.js');
364    } catch (error) {
365      // eslint-disable-next-line no-console
366      console.log(error);
367    }
368  }
369}
370
371/**
372 * Auto initializiation.
373 */
374function init() {
375  setup();
376  sampleRUM('top');
377
378  window.addEventListener('load', () => sampleRUM('load'));
379
380  window.addEventListener('unhandledrejection', (event) => {
381    sampleRUM('error', { source: event.reason.sourceURL, target: event.reason.line });
382  });
383
384  window.addEventListener('error', (event) => {
385    sampleRUM('error', { source: event.filename, target: event.lineno });
386  });
387}
388
389init();

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.