https://www.carwow.co.uk/assets/controllers/selling/approvals/checking_ticker_controller-a0d527bc.js
1import { Controller } from '@hotwired/stimulus' 2 3const INTERVAL_MS = 2000 4 5export default class extends Controller { 6 static targets = ['track', 'ring', 'badge'] 7 8 connect () { 9 this.index = 0 10 this.itemCount = this.trackTarget.children.length 11 this.stepHeight = this.itemCount > 1 12 ? this.trackTarget.children[1].offsetTop - this.trackTarget.children[0].offsetTop 13 : this.trackTarget.firstElementChild?.offsetHeight || 0 14 15 if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { 16 this.index = this.itemCount - 1 17 this.renderTicker() 18 this.setProgress(1) 19 this.complete() 20 this.ringTarget.classList.add('is-filled') 21 return 22 } 23 24 this.intervalId = setInterval(() => this.advance(), INTERVAL_MS) 25 26 this.ringDurationMs = INTERVAL_MS * this.itemCount 27 this.startedAt = performance.now() 28 this.frameId = requestAnimationFrame(() => this.animateRing()) 29 // Drives completion off a timer, not the rAF loop below: requestAnimationFrame is paused 30 // entirely in backgrounded/hidden tabs, which would otherwise leave the ring stuck 31 // mid-fill (and the poller never started) for as long as the seller is tabbed away. 32 this.completionTimeoutId = setTimeout(() => this.finishRing(), this.ringDurationMs) 33 } 34 35 disconnect () { 36 if (this.intervalId) { 37 clearInterval(this.intervalId) 38 } 39 40 if (this.frameId) { 41 cancelAnimationFrame(this.frameId) 42 } 43 44 if (this.completionTimeoutId) { 45 clearTimeout(this.completionTimeoutId) 46 } 47 } 48 49 advance () { 50 this.index += 1 51 this.renderTicker() 52 53 if (this.index >= this.itemCount - 1) { 54 clearInterval(this.intervalId) 55 } 56 } 57 58 renderTicker () { 59 this.trackTarget.style.transform = `translateY(-${this.index * this.stepHeight}px)` 60 } 61 62 animateRing () { 63 const ratio = Math.min((performance.now() - this.startedAt) / this.ringDurationMs, 1) 64 this.setProgress(ratio) 65 66 if (ratio < 1) { 67 this.frameId = requestAnimationFrame(() => this.animateRing()) 68 } 69 } 70 71 finishRing () { 72 this.setProgress(1) 73 this.complete() 74 this.ringTarget.classList.add('is-filled') 75 76 if (this.frameId) { 77 cancelAnimationFrame(this.frameId) 78 } 79 } 80 81 setProgress (ratio) { 82 this.ringTarget.style.setProperty('--progress', `${ratio * 100}%`) 83 } 84 85 complete () { 86 this.badgeTarget.classList.add('is-complete') 87 88 if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) { 89 // Deferred: this runs from connect(), synchronously with every other controller's own 90 // connect() on the same element â dispatching immediately can fire before 91 // completion-poller has connected and attached its listener, losing the event for good. 92 setTimeout(() => this.dispatch('complete'), 0) 93 return 94 } 95 96 const rightStroke = this.badgeTarget.querySelector('.approval-loading__tick-stroke--right') 97 rightStroke.addEventListener('transitionend', () => this.dispatch('complete'), { once: true }) 98 } 99}
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.