PageSourceSearch

https://uflgame.com/wp-content/themes/theme/assets/js/download-screen.js?ver=1789650020

js uflgame.com collected 2026-09-24 10:47:11 UTC 6,690 bytes, 195 lines download raw bytes

1;(function () {
2  // Client download screen for launcher download buttons.
3  //
4  // Two jobs, one per page:
5  //   1. On a page with a launcher CTA — send the click to the same URL with
6  //      ?status=downloading, where the block renders the screen server-side
7  //      instead of its CTA content (see include/download-screen.php).
8  //   2. On the screen itself — start the download, and report the retry click.
9  //
10  // Without JS the CTA stays a plain link to the launcher, so the download keeps
11  // working; only the screen is skipped.
12
13  // Only CTAs of blocks that actually render the screen opt in with
14  // data-download-screen (see include/download-screen.php) — elsewhere the link
15  // has to keep downloading directly.
16  var TRIGGER_SELECTOR = 'a[data-download-screen]'
17  var LAUNCHER_RE = /gdn\.gaijin\.net\/launcher/i
18  var START_SELECTOR = '[data-download-screen-start]'
19
20  var STATUS_PARAM = 'status'
21  var STATUS_VALUE = 'downloading'
22
23  var DISTR_PARAM = 'distr'
24  var GSID_COOKIE = 'gsid'
25
26  var CLICK_EVENT = 'download_launcher_button_click'
27  var RETRY_EVENT = 'download_launcher_try_again_click'
28
29  // Gamesight event + GTM/GA signal. Both are best-effort: analytics.js owns
30  // consent handling, GTM enforces its own.
31  function track(eventName) {
32    if (window.UFL_ANALYTICS && typeof window.UFL_ANALYTICS.send === 'function') {
33      window.UFL_ANALYTICS.send(eventName)
34    }
35    if (window.dataLayer && typeof window.dataLayer.push === 'function') {
36      window.dataLayer.push({ event: eventName })
37    }
38  }
39
40  /*
41   * Gamesight attribution id, mirrored into a first-party cookie by
42   * assets/js/gsid.js. It is read here rather than rendered into the screen's
43   * HTML: the markup then holds nothing visitor-specific, so a cached copy can
44   * never hand one visitor's id to another. The cookie is already set by the time
45   * the screen is reached (it is the second page view), so the download does not
46   * have to wait for the SDK either.
47   */
48  // Parsed with string operations on purpose: Autoptimize's JS minifier drops the
49  // line break after a regex literal that has no flags, and this file relies on
50  // ASI — /…/ followed by the next `var` then reads as invalid regex flags and
51  // takes down the whole script.
52  function gsidFromCookie() {
53    var parts = document.cookie ? document.cookie.split(';') : []
54
55    for (var i = 0; i < parts.length; i++) {
56      var pair = parts[i].split('=')
57      if (pair.shift().trim() !== GSID_COOKIE) continue
58
59      var value = pair.join('=')
60      try {
61        return decodeURIComponent(value)
62      } catch (e) {
63        return value
64      }
65    }
66
67    return ''
68  }
69
70  // `set`, not append: gsid.js targets launcher links too, so this must stay
71  // idempotent whichever of the two runs first.
72  function withDistr(href) {
73    var gsid = gsidFromCookie()
74    if (!href || !gsid) return href
75    try {
76      var url = new URL(href, window.location.href)
77      url.searchParams.set(DISTR_PARAM, gsid)
78      return url.toString()
79    } catch (e) {
80      return href
81    }
82  }
83
84  function triggerDownload(href) {
85    if (!href) return
86    var link = document.createElement('a')
87    link.href = href
88    link.rel = 'noopener noreferrer'
89    document.body.appendChild(link)
90    link.click()
91    link.remove()
92  }
93
94  function isPlainClick(event) {
95    return !(
96      event.defaultPrevented ||
97      event.button !== 0 ||
98      event.metaKey ||
99      event.ctrlKey ||
100      event.shiftKey ||
101      event.altKey
102    )
103  }
104
105  /* ── 1. CTA page ──────────────────────────────────────────────────────── */
106
107  function screenUrl() {
108    var url = new URL(window.location.href)
109    url.searchParams.set(STATUS_PARAM, STATUS_VALUE)
110    return url.toString()
111  }
112
113  function onCtaClick(event) {
114    var link = event.target && event.target.closest ? event.target.closest(TRIGGER_SELECTOR) : null
115    if (!link || !isPlainClick(event)) return
116
117    var href = link.getAttribute('href') || ''
118
119    // AppsFlyer rewrote this button to a OneLink (store redirect, not a direct
120    // launcher download) — that flow leaves the page, so no screen.
121    if (link.hasAttribute('data-af-btn') && !LAUNCHER_RE.test(href)) return
122
123    var target = ''
124    try {
125      target = screenUrl()
126    } catch (e) {
127      return // malformed location: leave the plain download link alone
128    }
129
130    event.preventDefault()
131    track(CLICK_EVENT)
132    window.location.assign(target)
133  }
134
135  /* ── 2. Download screen ───────────────────────────────────────────────── */
136
137  /*
138   * The automatic start belongs to a fresh navigation onto the screen only. On a
139   * reload — or a back/forward step onto it — the installer must not be fetched
140   * again: refreshing after a finished download started a second one. The visible
141   * "Try again" link stays as the deliberate retry.
142   */
143  function isFreshNavigation() {
144    try {
145      var entries = performance.getEntriesByType ? performance.getEntriesByType('navigation') : null
146      if (entries && entries.length && entries[0].type) return entries[0].type === 'navigate'
147      if (performance.navigation) return performance.navigation.type === 0
148    } catch (e) {
149      // Timing API unavailable: fall through and start as before.
150    }
151
152    return true
153  }
154
155  function initScreen(startLink) {
156    // Applied to the link itself, so the automatic start and a manual "Try again"
157    // both carry the attribution id.
158    var href = withDistr(startLink.getAttribute('href'))
159    if (href) startLink.setAttribute('href', href)
160
161    startLink.addEventListener('click', function () {
162      track(RETRY_EVENT)
163    })
164
165    if (!isFreshNavigation()) return
166
167    // Start once the screen has been painted, so the browser's download UI never
168    // appears over the previous page.
169    var start = function () {
170      triggerDownload(startLink.getAttribute('href'))
171    }
172
173    if (window.requestAnimationFrame) {
174      window.requestAnimationFrame(function () {
175        window.requestAnimationFrame(start)
176      })
177    } else {
178      start()
179    }
180  }
181
182  function init() {
183    var startLink = document.querySelector(START_SELECTOR)
184    if (startLink) {
185      initScreen(startLink)
186      return
187    }
188
189    // Bound unconditionally: gsid.js and appsflyer.js rewrite these hrefs after
190    // load, so what matches the selector is not settled at this point.
191    document.addEventListener('click', onCtaClick)
192  }
193
194  document.addEventListener('DOMContentLoaded', init)
195})()

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.