Skip to content

Instantly share code, notes, and snippets.

@tomhodgins
Created September 10, 2020 14:03
Show Gist options
  • Save tomhodgins/cfcebe8006fa0a962cdc9bcfeea00ae0 to your computer and use it in GitHub Desktop.
Save tomhodgins/cfcebe8006fa0a962cdc9bcfeea00ae0 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Count Down Element</title>
<script type=module>
import html from 'https://v2.crocdn.com/_plugins/html.js'
class CountDown extends HTMLElement {
constructor() {
super()
this.time = new Date
}
connectedCallback() {
this.shadow = this.attachShadow({mode: 'open'})
// Adjust this.time according to attributes
if (Number(this.getAttribute('utc-offset'))) {
this.time.setHours(Number(this.hours) + Number(this.getAttribute('utc-offset')) || 0)
} else {
this.time.setHours(this.hours || 0)
}
this.time.setMinutes(this.minutes || 0)
this.time.setSeconds(this.seconds || 0)
// Adjust day if needed
if (this.time < Date.now()) {
this.time.setHours(this.time.getHours() + 24)
}
// Create markup to be populated later
if (this.shadow.childNodes.length === 0) {
this.shadow.append(
html`
<ul>
<li id=hours>
<li id=minutes>
<li id=seconds>
</ul>
<style>
ul {
list-style: none;
display: inline-flex;
margin: 0;
padding: 0;
}
li:not(:first-of-type)::before {
content: ':';
margin-left: .25em;
margin-right: .25em;
}
</style>
`
)
}
// Populate once right away
this.updateClock()
}
updateClock() {
const millisecond = 1
const second = millisecond * 1000
const minute = second * 60
const hour = minute * 60
const diff = this.time - Date.now()
this.shadow.querySelector('#hours').textContent = String(
Math.floor(diff / hour)
).padStart(2, 0)
this.shadow.querySelector('#minutes').textContent = String(
Math.floor((diff % hour) / minute)
).padStart(2, 0)
this.shadow.querySelector('#seconds').textContent = String(
Math.floor((diff % minute) / second)
).padStart(2, 0)
// Only repeat if not paused and before the timer ends
if (
this.hasAttribute('paused') === false
&& diff <= Date.now()
) {
window.setTimeout(tick => this.updateClock(), 1000)
}
}
static get observedAttributes() {
return ['paused', 'hours', 'minutes', 'seconds']
}
// hours=""
get hours() {
return this.getAttribute('hours')
}
set hours(string) {
return this.setAttribute('hours', Number(string))
}
// minutes=""
get minutes() {
return this.getAttribute('minutes')
}
set minutes(string) {
return this.setAttribute('minutes', Number(string))
}
// seconds=""
get seconds() {
return this.getAttribute('seconds')
}
set seconds(string) {
return this.setAttribute('seconds', Number(string))
}
// paused=""
get paused() {
return this.getAttribute('paused')
}
set paused(string) {
return string
? this.setAttribute('paused', '')
: this.removeAttribute('paused')
}
// Listed to changes in paused=""
attributeChangedCallback(name, oldValue, newValue) {
console.log(name, oldValue, newValue)
if (
name === 'paused'
&& newValue === null
) {
if (this.shadow) {
this.updateClock()
}
}
}
}
customElements.define('count-down', CountDown)
</script>
<h1>Count Down</h1>
<h2>Empty tag</h2>
<count-down></count-down>
<h2>Default content</h2>
<count-down>15:00</count-down>
<h2>Paused content</h2>
<count-down paused>15:00</count-down>
<h2>Normal Usage</h2>
<count-down hours=1 minutes=2>15:00</count-down>
<!-- <h2>UTC time zone offset</h2>
<count-down hours=1 minutes=2 seconds=3 utc-offset=-5 paused>15:00</count-down> -->
<h2>Shipping until 5pm</h2>
<div style="background: #cec">
Same-day dispatch if ordered within the next
<count-down hours=17>15:00</count-down>
hours
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment