Note: This site is currently "Under construction". I'm migrating to a new version of my site building software. Lots of things are in a state of disrepair as a result (for example, footnote links aren't working). It's all part of the process of building in public. Most things should still be readable though.

YAGNI JS

This is just an idea I'm playing around with. The core is that instead of a framework or a library to have a copy/pastable piece of code you can just drop on a page and get a solid foundation for buliding interactions

A Basic Idea

A YAGNI Foundation Example

function addToF(parent, tag, attrs = {}) {
  const target = getElF(parent)
  if (target) {
    const el = document.createElement(tag)
    updateAttrsF(attrs, el)
    target.appendChild(el)
    return el
  }
}

function errorF(msg) {
  console.error(`${Date.now()} - ERROR: ${msg}`)
}

function getElF(target) {
  if (typeof target === "string") {
    const el = document.querySelector(target)
    if (el) { return el } 
    else { 
      errorF(`Could not find querySelector for: ${target}`)
      return undefined 
    }
  } 
  else if (target) { 
    return target 
  } 
  else { 
    errorF(`Could not get element: ${target}`)
    return undefined 
  }
}

function getStorageF(key, defaultValue = undefined) {
  return localStorage.getItem(key) 
    ? JSON.parse(localStorage.getItem(key)).payload
    : defaultValue
}

function logF(msg) {
  console.log(`${Date.now()} - INFO: ${msg}`)
}

function setStorageF(key, value) {
  localStorage.setItem(key, JSON.stringify({ payload: value }))
}

function updateF(target, attrs = {}) {
  const el = getElF(target)
  if (el) {
    updateAttrsF(attrs, el)
  }
  return el
}

function updateAttrsF(attrs, el) {
  const nonAttrs = ['classes', 'data', 'listeners'] 
  for (let key in attrs) {
    if (!nonAttrs.includes(key)) {
      el[key] = attrs[key]
    }
  }
  for (let index in attrs.classes) {
    el.classList.add(attrs.classes[index])
  }
  for (let index in attrs.data) {
    el.dataset[attrs.data[index][0]] = attrs.data[index][1]
  }
  for (let index in attrs.listeners) {
    el.addEventListener(attrs.listeners[index][0], attrs.listeners[index][1])
  }
}

Basic Example

HTML

<div class="example-alfa"></div>

JavaScript

function initAlfaF() {
  addToF('.example-alfa', 'button', {
    innerHTML: "0",
    classes: ['green'],
    data: [ ['current', 0] ],
    listeners: [['click', (event) => {
      let value = parseInt(event.target.dataset.current, 10)
      value += 1
      event.target.dataset.current = value
      event.target.innerHTML = value
    } ]]
  })
}

document.addEventListener("DOMContentLoaded", async () => {
  initAlfaF()
})

More Complicated Example

Here's a more complicated example that shows interaction between elements and using local storage.

HTML

<div class="example-bravo"></div>

JavaScript

function initBravoF() {
  const defaultValue = 0

  addToF('.example-bravo', 'button', {
    innerHTML: "-",
    listeners: [['click', (event) => {
      setStorageF('counter', getStorageF('counter', defaultValue) - 1)
      updateF(getElF('.counter'), { 
        innerHTML: getStorageF('counter'), 
      })
    }]]
  })

  addToF('.example-bravo', 'button', {
    classes: ['counter'],
    innerHTML: getStorageF('counter', defaultValue)
  })

  addToF('.example-bravo', 'button', {
    innerHTML: "+",
    listeners: [['click', (event) => {
      setStorageF('counter', getStorageF('counter', defaultValue) + 1)
      updateF(getElF('.counter'), { 
        innerHTML: getStorageF('counter'), 
      })
    }]]
  })
}

document.addEventListener("DOMContentLoaded", async () => {
  initBravoF()
})