Skip to content

Instantly share code, notes, and snippets.

@jon49
Last active August 23, 2025 08:10
Show Gist options
  • Select an option

  • Save jon49/28f84694272e39e2b642efa69b507c6e to your computer and use it in GitHub Desktop.

Select an option

Save jon49/28f84694272e39e2b642efa69b507c6e to your computer and use it in GitHub Desktop.

Revisions

  1. jon49 revised this gist Aug 23, 2025. 2 changed files with 69 additions and 35 deletions.
    63 changes: 63 additions & 0 deletions adder-libs.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,63 @@
    const elHandler = {
    get(obj, prop) {
    if (prop[0] === "$") {
    return obj[prop.slice(1)]
    }
    let val = obj[prop]
    if (!(val instanceof HTMLElement)) return
    if (isInputElement(val)) {
    if (val.type === "number") {
    return +val.value
    }
    return val.value
    }
    return val.textContent
    },

    set(obj, prop, newVal) {
    let val = obj[prop]
    if (!(val instanceof HTMLElement)) return false
    if (isInputElement(val)) {
    val.value = newVal
    return true
    }
    val.textContent = newVal
    return true
    }
    }

    function isInputElement(obj) {
    return obj instanceof HTMLInputElement || obj instanceof HTMLSelectElement
    }

    export function getXElements(fragment) {
    let o = {}
    for (let el of fragment.querySelectorAll(`[x]`)) {
    o[el.getAttribute('x') || ''] = el
    el.removeAttribute('x')
    }
    return new Proxy(o, elHandler)
    }

    export function handleEvent(context, event) {
    let target = event.target
    if (target instanceof HTMLElement) {
    // @ts-ignore
    let action = target.dataset.action || target.closest('[data-action]')?.dataset?.action
    if (action) {
    if (context[action] instanceof Function) {
    requestAnimationFrame(() => {
    context[action](event)
    })
    event.stopPropagation()
    event.preventDefault()
    } else {
    console.error(`Action ${action} not implemented.`)
    }
    } else if (context[event.type] instanceof Function) {
    context[event.type](event)
    event.stopPropagation()
    event.preventDefault()
    }
    }
    }
    41 changes: 6 additions & 35 deletions adder.js
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,9 @@
    import { handleEvent, getXElements } from "./adder-libs.js"

    class Adder extends HTMLElement {
    constructor() {
    super()
    this.elements = getXElements(this)
    this.$ = getXElements(this)
    this.addEventListener('input', this)
    }

    @@ -10,40 +12,9 @@ class Adder extends HTMLElement {
    }

    add() {
    let num1 = +this.elements.num1.value
    let num2 = +this.elements.num2.value
    this.elements.target.textContent = `${num1} + ${num2} = ${num1 + num2}`
    }
    }

    customElements.define('x-adder', Adder)

    function getXElements(fragment) {
    let o = {}
    for (let el of fragment.querySelectorAll(`[x]`)) {
    o[el.getAttribute('x') || ''] = el
    el.removeAttribute('x')
    let $ = this.$
    $.target = `${$.num1} + ${$.num2} = ${$.num1 + $.num2}`
    }
    return o
    }

    function handleEvent(context, event) {
    event.stopPropagation()
    event.preventDefault()
    let target = event.target
    if (target instanceof HTMLElement) {
    // @ts-ignore
    let action = target.dataset.action || target.closest('[data-action]')?.dataset?.action
    if (action) {
    if (context[action] instanceof Function) {
    requestAnimationFrame(() => {
    context[action](event)
    })
    } else {
    console.error(`Action ${action} not implemented.`)
    }
    } else if (context[event.type] instanceof Function) {
    context[event.type](event)
    }
    }
    }
    customElements.define('x-adder', Adder)
  2. jon49 revised this gist Jul 22, 2025. 1 changed file with 0 additions and 9 deletions.
    9 changes: 0 additions & 9 deletions adder.js
    Original file line number Diff line number Diff line change
    @@ -18,15 +18,6 @@ class Adder extends HTMLElement {

    customElements.define('x-adder', Adder)

    function whenLoaded(element, callback) {
    // When all the children are loaded, call the callback
    if (element.content && element.content.readyState === 'complete') {
    callback()
    } else {
    element.addEventListener('load', callback, { once: true })
    }
    }

    function getXElements(fragment) {
    let o = {}
    for (let el of fragment.querySelectorAll(`[x]`)) {
  3. jon49 created this gist Jul 22, 2025.
    58 changes: 58 additions & 0 deletions adder.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    class Adder extends HTMLElement {
    constructor() {
    super()
    this.elements = getXElements(this)
    this.addEventListener('input', this)
    }

    handleEvent(event) {
    handleEvent(this, event)
    }

    add() {
    let num1 = +this.elements.num1.value
    let num2 = +this.elements.num2.value
    this.elements.target.textContent = `${num1} + ${num2} = ${num1 + num2}`
    }
    }

    customElements.define('x-adder', Adder)

    function whenLoaded(element, callback) {
    // When all the children are loaded, call the callback
    if (element.content && element.content.readyState === 'complete') {
    callback()
    } else {
    element.addEventListener('load', callback, { once: true })
    }
    }

    function getXElements(fragment) {
    let o = {}
    for (let el of fragment.querySelectorAll(`[x]`)) {
    o[el.getAttribute('x') || ''] = el
    el.removeAttribute('x')
    }
    return o
    }

    function handleEvent(context, event) {
    event.stopPropagation()
    event.preventDefault()
    let target = event.target
    if (target instanceof HTMLElement) {
    // @ts-ignore
    let action = target.dataset.action || target.closest('[data-action]')?.dataset?.action
    if (action) {
    if (context[action] instanceof Function) {
    requestAnimationFrame(() => {
    context[action](event)
    })
    } else {
    console.error(`Action ${action} not implemented.`)
    }
    } else if (context[event.type] instanceof Function) {
    context[event.type](event)
    }
    }
    }
    22 changes: 22 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>Adder</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>

    <h1>Add numbers!</h1>

    <x-adder>
    <input x=num1 data-action=add type="number">
    <input x=num2 data-action=add type="number">

    <p x=target></p>
    </x-adder>

    <script type=module src="./adder.js"></script>

    </body>
    </html>