PageSourceSearch

https://www.survival.it/assets/utils/init_link_preview_cards-46c914e0.js

js survival.it collected 2026-09-24 09:54:15 UTC 2,871 bytes, 69 lines download raw bytes

1function removeAllPreviewCards () {
2  document.querySelectorAll('.link-preview-card').forEach(card => card.remove())
3}
4
5function initPreviewCardLinks () {
6  // Clean up any orphaned preview cards from previous navigation
7  removeAllPreviewCards()
8
9  if (window.innerWidth < 768) { return } // Don't init preview cards on mobile
10
11  const mainElement = document.querySelector('main')
12  if (!mainElement) { return }
13
14  // Only init for .preview-card-link
15  const anchors = mainElement.querySelectorAll('a.preview-card-link[href]')
16  const survivalDomains = ['survival.es', 'survival.it', 'survivalinternational.fr', 'survivalinternational.de', 'survivalinternational.org', 'survivalbrasil.org']
17  const allowedSubdomains = ['', 'www', 'staging']
18
19  anchors.forEach(anchor => {
20    if (anchor.hasAttribute('data-controller')) { return }
21    if (anchor.classList.contains('card')) { return }
22    if (anchor.classList.contains('btn')) { return }
23    if (!anchor.classList.contains('preview-card-link')) { return }
24
25    const subdomain = matchedSubdomain(anchor.href, survivalDomains)
26    if (subdomain === null || !allowedSubdomains.includes(subdomain)) { return }
27
28    // Add preview controller attributes
29    anchor.setAttribute('data-controller', 'numiko--link-preview-card')
30    anchor.setAttribute('data-action', 'mouseenter->numiko--link-preview-card#showPreview mouseleave->numiko--link-preview-card#hidePreview mousemove->link-preview-card--preview#trackCursor')
31
32    // staging. has no www. counterpart, so unifying it would produce www.staging.
33    if (subdomain !== 'staging') { unifyDomainLinks(anchor) }
34  })
35}
36
37// Only content pages on the bare domain, www., or staging. should get a preview card -
38// this excludes asset/CDN subdomains (e.g. assets.) and other app subdomains (e.g. donate.).
39function matchedSubdomain (href, survivalDomains) {
40  const hostname = new URL(href).hostname
41  const matchedDomain = survivalDomains.find(domain => hostname === domain || hostname.endsWith(`.${domain}`))
42  if (!matchedDomain) { return null }
43
44  return hostname === matchedDomain ? '' : hostname.slice(0, -(matchedDomain.length + 1))
45}
46
47function unifyDomainLinks (anchor) {
48  const requiresWWW = window.location.hostname.includes('www.')
49  const anchorContainsWWW = anchor.href.includes('www.')
50  if (requiresWWW === anchorContainsWWW) { return }
51  if (requiresWWW && !anchorContainsWWW) {
52    anchor.href = anchor.href.replace('://', '://www.')
53  } else if (!requiresWWW && anchorContainsWWW) {
54    anchor.href = anchor.href.replace('://www.', '://')
55  }
56}
57
58function setupTurboCleanup () {
59  document.addEventListener('turbo:before-cache', () => {
60    removeAllPreviewCards()
61  })
62
63  document.addEventListener('turbo:load', () => {
64    removeAllPreviewCards()
65    initPreviewCardLinks()
66  })
67}
68
69export { initPreviewCardLinks, removeAllPreviewCards, setupTurboCleanup }

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.