PageSourceSearch

https://www.sighenderson.com/assets/js/cookieconsent-config.js

js sighenderson.com collected 2026-10-08 21:26:47 UTC 16,833 bytes, 565 lines download raw bytes

1// cookieconsent-config.js
2
3import * as CookieConsent from "/assets/js/cookieconsent.esm.js";
4
5/**
6 * Per-site URLs — customize before deploy (see README section 10).
7 */
8const SITE_CONFIG = {
9  privacyPolicyUrl: "/privacy-policy",
10  contactUrl: "/contact/",
11};
12
13const CAT_NECESSARY = "necessary";
14const CAT_ANALYTICS = "analytics";
15const CAT_ADVERTISEMENT = "advertisement";
16const CAT_FUNCTIONALITY = "functionality";
17const CAT_SECURITY = "security";
18
19const SERVICE_AD_STORAGE = "ad_storage";
20const SERVICE_AD_USER_DATA = "ad_user_data";
21const SERVICE_AD_PERSONALIZATION = "ad_personalization";
22const SERVICE_ANALYTICS_STORAGE = "analytics_storage";
23const SERVICE_FUNCTIONALITY_STORAGE = "functionality_storage";
24const SERVICE_PERSONALIZATION_STORAGE = "personalization_storage";
25const SERVICE_SECURITY_STORAGE = "security_storage";
26
27const im = iframemanager();
28
29const TRADINGVIEW_MARKET_OVERVIEW_EMBED_URL = `https://s.tradingview.com/embed-widget/market-overview/?locale=en#${encodeURIComponent(
30  JSON.stringify({
31    colorTheme: "light",
32    dateRange: "12M",
33    showChart: false,
34    locale: "en",
35    largeChartUrl: "",
36    isTransparent: false,
37    showSymbolLogo: true,
38    width: "280",
39    height: "140",
40    tabs: [
41      {
42        title: "Indices",
43        symbols: [
44          { s: "FOREXCOM:SPXUSD", d: "S&P 500" },
45          { s: "FOREXCOM:NSXUSD", d: "Nasdaq 100" },
46          { s: "FOREXCOM:DJI", d: "Dow 30" },
47        ],
48        originalTitle: "Indices",
49      },
50    ],
51  }),
52)}`;
53
54/**
55 * Convert legacy embed iframes pasted in CMS content to IframeManager placeholders.
56 */
57function getYoutubeVideoId(url) {
58  if (!url) {
59    return null;
60  }
61
62  try {
63    const parsed = new URL(url, window.location.origin);
64    const host = parsed.hostname.replace(/^www\./, "");
65
66    if (host === "youtu.be") {
67      return parsed.pathname.slice(1).split("/")[0] || null;
68    }
69
70    if (host.includes("youtube.com") || host.includes("youtube-nocookie.com")) {
71      if (parsed.pathname.startsWith("/embed/")) {
72        return parsed.pathname.split("/")[2] || null;
73      }
74
75      return parsed.searchParams.get("v");
76    }
77  } catch (error) {
78    return null;
79  }
80
81  return null;
82}
83
84function getGoogleMapsPbId(url) {
85  if (!url) {
86    return null;
87  }
88
89  const pbMatch = url.match(/[?&]pb=([^&]*)/);
90
91  if (!pbMatch) {
92    return null;
93  }
94
95  // Keep percent-encoding intact — URL.searchParams decodes %23 to # which
96  // breaks embed URLs for places like "Shalom Tire Shop #2".
97  return pbMatch[1] || null;
98}
99
100function getEmbedQueryParams(url) {
101  if (!url) {
102    return "";
103  }
104
105  try {
106    return new URL(url, window.location.origin).searchParams.toString();
107  } catch (error) {
108    return "";
109  }
110}
111
112function getLegacyEmbedTarget(iframe) {
113  const src = iframe.getAttribute("src") || iframe.getAttribute("data-src");
114
115  if (!src) {
116    return null;
117  }
118
119  const youtubeId = getYoutubeVideoId(src);
120
121  if (youtubeId) {
122    return {
123      service: "youtube",
124      id: youtubeId,
125      params: getEmbedQueryParams(src),
126    };
127  }
128
129  const pb = src.includes("google.com/maps/embed")
130    ? getGoogleMapsPbId(src)
131    : null;
132
133  if (pb) {
134    return {
135      service: "googlemaps",
136      id: pb,
137      params: "",
138    };
139  }
140
141  return null;
142}
143
144function copyIframeAttributesToPlaceholder(iframe, placeholder) {
145  const passthroughAttributes = ["title", "loading", "referrerpolicy"];
146
147  passthroughAttributes.forEach((attribute) => {
148    const value = iframe.getAttribute(attribute);
149
150    if (!value) {
151      return;
152    }
153
154    if (attribute === "title") {
155      placeholder.setAttribute("data-title", value);
156      return;
157    }
158
159    placeholder.setAttribute(`data-iframe-${attribute}`, value);
160  });
161
162  iframe.getAttributeNames().forEach((attribute) => {
163    if (!attribute.startsWith("data-iframe-")) {
164      return;
165    }
166
167    placeholder.setAttribute(attribute, iframe.getAttribute(attribute));
168  });
169}
170
171function migrateLegacyCmsEmbeds() {
172  document
173    .querySelectorAll("iframe[src], iframe[data-src]")
174    .forEach((iframe) => {
175      if (iframe.closest("[data-service]")) {
176        return;
177      }
178
179      const target = getLegacyEmbedTarget(iframe);
180
181      if (!target) {
182        return;
183      }
184
185      const placeholder = document.createElement("div");
186      placeholder.setAttribute("data-service", target.service);
187      placeholder.setAttribute("data-id", target.id);
188
189      const width = iframe.getAttribute("width");
190      const height = iframe.getAttribute("height");
191      const isFixedSize =
192        width && height && width !== "100%" && !width.includes("%");
193
194      if (isFixedSize) {
195        placeholder.style.width = /^\d+$/.test(width) ? `${width}px` : width;
196        placeholder.style.height = /^\d+$/.test(height)
197          ? `${height}px`
198          : height;
199        placeholder.style.margin = "0 auto";
200      } else {
201        placeholder.setAttribute("data-autoscale", "");
202      }
203
204      if (target.params) {
205        placeholder.setAttribute("data-params", target.params);
206      }
207
208      copyIframeAttributesToPlaceholder(iframe, placeholder);
209      iframe.replaceWith(placeholder);
210    });
211}
212
213migrateLegacyCmsEmbeds();
214
215/**
216 * Update gtag consent according to the users choices made in CookieConsent UI
217 */
218function updateGtagConsent() {
219  if (typeof gtag !== "function") return;
220
221  gtag("consent", "update", {
222    [SERVICE_ANALYTICS_STORAGE]: CookieConsent.acceptedService(
223      SERVICE_ANALYTICS_STORAGE,
224      CAT_ANALYTICS,
225    )
226      ? "granted"
227      : "denied",
228    [SERVICE_AD_STORAGE]: CookieConsent.acceptedService(
229      SERVICE_AD_STORAGE,
230      CAT_ADVERTISEMENT,
231    )
232      ? "granted"
233      : "denied",
234    [SERVICE_AD_USER_DATA]: CookieConsent.acceptedService(
235      SERVICE_AD_USER_DATA,
236      CAT_ADVERTISEMENT,
237    )
238      ? "granted"
239      : "denied",
240    [SERVICE_AD_PERSONALIZATION]: CookieConsent.acceptedService(
241      SERVICE_AD_PERSONALIZATION,
242      CAT_ADVERTISEMENT,
243    )
244      ? "granted"
245      : "denied",
246    [SERVICE_FUNCTIONALITY_STORAGE]: CookieConsent.acceptedService(
247      SERVICE_FUNCTIONALITY_STORAGE,
248      CAT_FUNCTIONALITY,
249    )
250      ? "granted"
251      : "denied",
252    [SERVICE_PERSONALIZATION_STORAGE]: CookieConsent.acceptedService(
253      SERVICE_PERSONALIZATION_STORAGE,
254      CAT_FUNCTIONALITY,
255    )
256      ? "granted"
257      : "denied",
258    [SERVICE_SECURITY_STORAGE]: CookieConsent.acceptedService(
259      SERVICE_SECURITY_STORAGE,
260      CAT_SECURITY,
261    )
262      ? "granted"
263      : "denied",
264  });
265}
266
267function updateWidgetPlaceholders() {
268  document.querySelectorAll("[data-cc-placeholder]").forEach((el) => {
269    const category = el.getAttribute("data-cc-placeholder");
270    const service = el.getAttribute("data-cc-service");
271
272    let accepted = false;
273    if (category) {
274      accepted = CookieConsent.acceptedCategory(category);
275      if (service && !accepted) {
276        accepted = CookieConsent.acceptedService(service, category);
277      }
278    }
279
280    el.toggleAttribute("hidden", accepted);
281  });
282}
283
284function onConsentChange() {
285  updateGtagConsent();
286  updateWidgetPlaceholders();
287}
288
289im.run({
290  currLang: "en",
291
292  onChange: ({ changedServices, eventSource }) => {
293    if (eventSource.type === "click") {
294      const servicesToAccept = [
295        ...(CookieConsent.getUserPreferences().acceptedServices[
296          CAT_FUNCTIONALITY
297        ] || []),
298        ...changedServices,
299      ];
300
301      CookieConsent.acceptService(servicesToAccept, CAT_FUNCTIONALITY);
302    }
303  },
304
305  services: {
306    youtube: {
307      embedUrl: "https://www.youtube-nocookie.com/embed/{data-id}",
308      thumbnailUrl: "https://i3.ytimg.com/vi/{data-id}/hqdefault.jpg",
309      iframe: {
310        allow:
311          "accelerometer; encrypted-media; gyroscope; picture-in-picture; fullscreen;",
312        loading: "lazy",
313        frameborder: "0",
314      },
315      languages: {
316        en: {
317          notice:
318            'This content is hosted by a third party. By showing the external content you accept the <a rel="noreferrer noopener" href="https://www.youtube.com/t/terms" target="_blank">terms and conditions</a> of youtube.com.',
319          loadBtn: "Load video",
320          loadAllBtn: "Don't ask again",
321        },
322      },
323    },
324
325    googlemaps: {
326      embedUrl: "https://www.google.com/maps/embed?pb={data-id}",
327      iframe: {
328        allow: "picture-in-picture; fullscreen;",
329        loading: "lazy",
330        referrerpolicy: "no-referrer-when-downgrade",
331        frameborder: "0",
332      },
333      languages: {
334        en: {
335          notice:
336            'This content is hosted by a third party. By showing the external content you accept the <a rel="noreferrer noopener" href="https://cloud.google.com/maps-platform/terms" target="_blank">terms and conditions</a> of Google Maps.',
337          loadBtn: "Load map",
338          loadAllBtn: "Don't ask again",
339        },
340      },
341    },
342
343    apmex: {
344      embedUrl:
345        "https://widgets.apmex.com/widget/spotprice/?w=280&h=120&mtls=GSPL&arf=True&rint=1&srf=False&tId=2&cId=6d59eebb-6dd0-42d3-8a06-bf77298a83c5&wId=1",
346      iframe: {
347        frameborder: "0",
348        scrolling: "no",
349        loading: "lazy",
350      },
351      languages: {
352        en: {
353          notice:
354            'This content is hosted by a third party. By showing the external content you accept the <a rel="noreferrer noopener" href="https://www.apmex.com/" target="_blank">terms and conditions</a> of APMEX.',
355          loadBtn: "Load prices",
356          loadAllBtn: "Don't ask again",
357        },
358      },
359    },
360
361    tradingview: {
362      embedUrl: TRADINGVIEW_MARKET_OVERVIEW_EMBED_URL,
363      iframe: {
364        frameborder: "0",
365        scrolling: "no",
366        loading: "lazy",
367      },
368      languages: {
369        en: {
370          notice:
371            'This content is hosted by a third party. By showing the external content you accept the <a rel="noreferrer noopener" href="https://www.tradingview.com/policies/" target="_blank">terms and conditions</a> of TradingView.',
372          loadBtn: "Load prices",
373          loadAllBtn: "Don't ask again",
374        },
375      },
376    },
377  },
378});
379
380CookieConsent.run({
381  revision: 6,
382
383  cookie: {
384    secure: window.location.protocol === "https:",
385  },
386
387  guiOptions: {
388    consentModal: {
389      layout: "box",
390      position: "bottom right",
391    },
392    preferencesModal: {
393      layout: "box",
394    },
395  },
396
397  onFirstConsent: () => {
398    onConsentChange();
399  },
400  onConsent: () => {
401    onConsentChange();
402  },
403  onChange: () => {
404    onConsentChange();
405  },
406
407  categories: {
408    [CAT_NECESSARY]: {
409      enabled: true,
410      readOnly: true,
411    },
412    [CAT_ANALYTICS]: {
413      autoClear: {
414        cookies: [
415          {
416            name: /^_ga/,
417          },
418          {
419            name: "_gid",
420          },
421        ],
422      },
423      services: {
424        [SERVICE_ANALYTICS_STORAGE]: {
425          label:
426            "Enables storage (such as cookies) related to analytics e.g. visit duration.",
427        },
428      },
429    },
430    [CAT_ADVERTISEMENT]: {
431      services: {
432        [SERVICE_AD_STORAGE]: {
433          label: "Enables storage (such as cookies) related to advertising.",
434        },
435        [SERVICE_AD_USER_DATA]: {
436          label:
437            "Sets consent for sending user data related to advertising to Google.",
438        },
439        [SERVICE_AD_PERSONALIZATION]: {
440          label: "Sets consent for personalized advertising.",
441        },
442      },
443    },
444    [CAT_FUNCTIONALITY]: {
445      services: {
446        [SERVICE_FUNCTIONALITY_STORAGE]: {
447          label:
448            "Enables storage related to site functionality such as language preferences.",
449        },
450        youtube: {
451          label:
452            "Embeds YouTube videos, which may set cookies for playback and preferences.",
453          onAccept: () => im.acceptService("youtube"),
454          onReject: () => im.rejectService("youtube"),
455        },
456        googlemaps: {
457          label: "Embeds an interactive Google Maps view of our location.",
458          onAccept: () => im.acceptService("googlemaps"),
459          onReject: () => im.rejectService("googlemaps"),
460        },
461        apmex: {
462          label:
463            "Displays live precious metals spot prices from APMEX.",
464          onAccept: () => im.acceptService("apmex"),
465          onReject: () => im.rejectService("apmex"),
466        },
467        tradingview: {
468          label:
469            "Displays live stock index prices from TradingView.",
470          onAccept: () => im.acceptService("tradingview"),
471          onReject: () => im.rejectService("tradingview"),
472        },
473      },
474    },
475  },
476
477  language: {
478    default: "en",
479    translations: {
480      en: {
481        consentModal: {
482          title: "We use cookies",
483          description:
484            "We use cookies for specific <strong>purposes</strong> — essential operation, analytics, and functionality. Optional cookies may involve <strong>third parties</strong> such as Google, APMEX, and TradingView; you can <strong>withdraw</strong> consent anytime via Manage preferences or Cookie Settings.",
485          acceptAllBtn: "Accept all",
486          acceptNecessaryBtn: "Reject all",
487          showPreferencesBtn: "Manage preferences",
488          footer: `
489            <a href="${SITE_CONFIG.privacyPolicyUrl}">Privacy Policy</a>
490            <a href="${SITE_CONFIG.contactUrl}">Contact</a>
491          `,
492        },
493        preferencesModal: {
494          title: "Manage cookie preferences",
495          acceptAllBtn: "Accept all",
496          acceptNecessaryBtn: "Reject all",
497          savePreferencesBtn: "Accept current selection",
498          closeIconLabel: "Close modal",
499          sections: [
500            {
501              title: "Cookie usage",
502              description:
503                "We use cookies for specific purposes: essential site operation, analytics, and enhanced functionality. When you enable optional categories, data may be processed by third-parties such as Google Analytics, APMEX, and TradingView. See our privacy policy for full details.",
504            },
505            {
506              title: "Strictly necessary cookies",
507              description:
508                "These cookies are essential for the proper functioning of the website, for example for user authentication.",
509              linkedCategory: CAT_NECESSARY,
510            },
511            {
512              title: "Analytics",
513              description:
514                "Cookies used for analytics help collect data that allows services to understand how users interact with a particular service. Data may be shared with third-parties such as Google Analytics.",
515              linkedCategory: CAT_ANALYTICS,
516              cookieTable: {
517                headers: {
518                  name: "Name",
519                  domain: "Service",
520                  description: "Description",
521                  expiration: "Expiration",
522                },
523                body: [
524                  {
525                    name: "_ga",
526                    domain: "Google Analytics",
527                    description:
528                      'Cookie set by <a href="https://business.safety.google/adscookies/">Google Analytics</a>',
529                    expiration: "Expires after 12 days",
530                  },
531                  {
532                    name: "_gid",
533                    domain: "Google Analytics",
534                    description:
535                      'Cookie set by <a href="https://business.safety.google/adscookies/">Google Analytics</a>',
536                    expiration: "Session",
537                  },
538                ],
539              },
540            },
541            {
542              title: "Advertising",
543              description:
544                "These settings control Google Consent Mode storage keys for advertising-related data. We do not currently use third-party advertising trackers such as Meta or LinkedIn on this site.",
545              linkedCategory: CAT_ADVERTISEMENT,
546            },
547            {
548              title: "Functionality",
549              description:
550                "Cookies used for functionality enable embedded YouTube and Google Maps content, APMEX precious metals prices, and TradingView stock market data. These third-parties may set their own cookies when enabled.",
551              linkedCategory: CAT_FUNCTIONALITY,
552            },
553            {
554              title: "More information",
555              description: `Read our <a href="${SITE_CONFIG.privacyPolicyUrl}">Privacy Policy</a> for full details on purposes, third-parties, and data retention. You may withdraw or change your consent at any time using Manage preferences above or the Cookie Settings link in our site footer. For other queries, <a href="${SITE_CONFIG.contactUrl}">contact us</a>.`,
556            },
557          ],
558        },
559      },
560    },
561  },
562});
563
564window.showCookiePreferences = () => CookieConsent.showPreferences();
565updateWidgetPlaceholders();

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.