1class CountdownClock { 2 #currentComponents; 3 #refreshRate; 4 #clockElements = {}; 5 #countdownContainerId; 6 #countdownContainerEl; 7 8 #allComponents = ['weeks', 'days', 'hours', 'minutes', 'seconds']; 9 10 // Default true so every existing caller is unchanged. The 2027 hero 11 // counter turns it off: with no weeks cell, days has to be the total or 12 // the clock silently reads six days out from the show. 13 #showWeeks = true; 14 #positions = { 15 tens: 'tens', 16 units: 'units' 17 }; 18 19 constructor({appendToId = '', showSeconds = true, showWeeks = true, date = null} = {}) { 20 this.appendToElement = document.getElementById(appendToId); 21 22 if (this.appendToElement === null) { 23 throw new Error(`Invalid element Id ${appendToId}`); 24 } 25 26 this.id = crypto.randomUUID(); 27 this.#refreshRate = showSeconds ? 1000 : 10000; 28 this.#showWeeks = showWeeks; 29 30 let components = showWeeks ? this.#allComponents : this.#allComponents.slice(1); 31 this.#currentComponents = showSeconds ? [...components] : components.slice(0, -1); 32 33 this.date = date === null ? new Date() : new Date(date); 34 } 35 36 get clock() { 37 return this.#clock; 38 } 39 40 get components() { 41 return this.#currentComponents; 42 } 43 44 get positions() { 45 return this.#positions; 46 } 47 48 get refreshRate() { 49 return this.#refreshRate; 50 } 51 52 get showWeeks() { 53 return this.#showWeeks; 54 } 55 56 get countdownContainerId () { 57 return this.#countdownContainerId; 58 } 59 60 get countdownContainerEl() { 61 return this.#countdownContainerEl; 62 } 63 64 initClockElements() { 65 for (let componentName of this.#currentComponents) { 66 this.#clockElements[componentName] = {}; 67 } 68 } 69 70 createContainer(containerCssClass) { 71 this.#countdownContainerId = window.crypto.randomUUID(); 72 const containerTemplate = document.createElement(HTMLElements.template); 73 containerTemplate.innerHTML = `<div id="${this.#countdownContainerId}" class="${containerCssClass}"></div>`; 74 this.appendToElement.innerHTML = ''; 75 this.appendToElement.appendChild(containerTemplate.content.firstElementChild); 76 this.#countdownContainerEl = document.getElementById(this.#countdownContainerId); 77 } 78 79 /*** 80 * 81 * @param value {number} 82 * @returns {string} 83 */ 84 formatTime(value) { 85 return value.toLocaleString('en-UK', {minimumIntegerDigits: 2, useGrouping: false}) 86 } 87 88 #clock = { 89 weeks: { 90 value: 0, 91 maxValue: 99 92 }, 93 days: { 94 value: 0, 95 maxValue: 7 96 }, 97 hours: { 98 value: 0, 99 maxValue: 24 100 }, 101 minutes: { 102 value: 0, 103 maxValue: 60 104 }, 105 seconds: { 106 value: 0, 107 maxValue: 60 108 } 109 } 110 111 getDistance() { 112 // Get today's date and time 113 const now = new Date().getTime(); 114 115 // Find the distance between now an the count down date 116 const distance = Math.max(this.date.getTime() - now, 0); 117 118 // Time calculations for weeks, days, hours, minutes and seconds. 119 // days is days-within-the-week when there is a weeks cell to carry the 120 // rest, and the total otherwise. 121 return { 122 weeks: Math.floor(distance / (1000 * 60 * 60 * 24 * 7)), 123 days: this.#showWeeks 124 ? Math.floor(distance % (1000 * 60 * 60 * 24 * 7) / (1000 * 60 * 60 * 24)) 125 : Math.floor(distance / (1000 * 60 * 60 * 24)), 126 hours: Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)), 127 minutes: Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)), 128 seconds: Math.floor((distance % (1000 * 60)) / 1000) 129 } 130 } 131}
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.