Dolla on GitHub

Dolla is a library of javascipt methods that augment existing DOM methods. Dolla is platform-agnotstic, with each method being fully tree-shakeable by any bundler. No dependencies, just helpful methods you can include as you need them.

Installation

npm install dolla

Usage

Import only the methods you use.

import {createElement} from 'dolla';

document.body.append(createElement('div', {
    class: 'text-bold',
    style: 'text-decoration: underline',
    content: ['Hello World']
}))

addEventListenerFor (element, selector, type, listener) #

This method adds a listener callback for an Element that is triggered when a containing target matching the selector is fired. Sets event.delegateTarget to the element that matches to selector, while target remains as element that fired the event.

Syntax

addEventListenerFor (element, selector, type, listener)
addEventListenerFor (element, selector, type, listener, [options={}])

Arguments

element

An Element to add the event listener to

selector

A valid CSS selector string

type

A case-sensitive string representing the event type to listen for

listener

An Object with a handleEvent() method or a function. Receives an Event as the param. Event has attribute delegateTarget added that is the element that matches the selector.

options optional

An Object with options for addEventListener

Return Value

undefined

Example

addEventListenerFor(el, 'checkbox', 'change', e => {
    console.log(e.delegateTarget.value)
}, {once: true})
SOURCE CODE
function addEventListenerFor (element, selector, type, listener, options={}) {
    element.addEventListener(type, e => {
        if (e.target.matches(selector)) {
            e.delegateTarget = e.target
            listener(e)
        } else if (e.target.closest(selector)) {
            e.delegateTarget = e.target.closest(selector)
            listener(e)
        }
    }, options)
}

ancestors (element, [selector]) #

This method traverses the element and it's parents returning all ancestor elements until the selector is matched.

Syntax

ancestor (element, [selector])
ancestor (element)

Arguments

element

An Element to add the event listener to

selector optional

A valid CSS selector string

Return Value

An Array of Element ordered by closest first.

Example

ancestors(el, '.container')
SOURCE CODE
function ancestors (el, selector) {
    if (selector && el.parentElement.matches(selector)) {
        return [el.parentElement]
    } else if (el.parentElement && el.parentElement.parentElement) {
        return [el.parentElement].concat(ancestors(el.parentElement, selector))
    } else if (el.parentElement) {
        return [el.parentElement]
    } else {
        return []
    }
}

append (element, content, [escape], [context], [method]) #

This method adds a listener callback for an Element that is triggered when a containing target matching the selector is fired. Sets event.delegateTarget to the element that matches to selector, while target remains as element that fired the event.

Syntax

append (element, content, [escape], [context], [method])
append (element, content)
append (element, content, escape)
append (element, content, context)
append (element, content, method)

Arguments

element

An Element to add the event listener to

content

A Element, NodeList, HTMLCollection, Array, Promise, String of text or html, Object passed to dolla's createElement.

escape optional

A Boolean directing method to escape or not escape content that is a string

context optional

The value to be passed as the this parameter if content is a method

method optional

A String stating which method of Element instance to use to add content. Default is "append"

Return Value

undefined

Example

append(el, el2)
append(el, [el2, el3, el4])
append(el, el2.children)
append(el, el2.childNodes)
append(el, new Promise(resolve => {
    records.load().then(records => {
        resolve(records.map(record => {
            template(record)
        }))
    })
}))
append(el, {
    class: 'label',
    content: "Hello World"
})
append(el, "<span>Hello World</span>")
SOURCE CODE
import createElement from './createElement.js';
import insertBefore from './insertBefore.js';
import remove from './remove.js';

function append(el, content, escape, context, method) {
    if (!method) method = 'append'
    if (Array.isArray(content) || content instanceof NodeList || content instanceof HTMLCollection) {
        let contents = Array.from(content)
        if (method == 'prepend') contents = contents.reverse()
        contents.forEach(i => append(el, i, escape, context, method));
    } else if (escape instanceof Element) {
        let contents = Array.from(arguments).slice(1).filter(x => x instanceof Element);
        if (method == 'prepend') contents = contents.reverse()
        contents.forEach(i => append(el, i, undefined, context, method));
    } else {
        if (typeof escape != "boolean") {
            context = escape;
            escape = undefined;
        }
      
        if (content === null || content === undefined) {
                    // do nothing
        } else if (content instanceof Promise || content.then) {
            const holder = document.createElement('span');
            el[method](holder);
            const timestamp = new Date().getMilliseconds()
            return content.then(resolvedItem => {
                append(holder, resolvedItem, escape, context);
                insertBefore(holder, holder.childNodes)
                remove(holder);
            });
        } else if (content instanceof Element || content instanceof Node) {
            return el[method](content);
        } else if (typeof content == "function") {
            return append(el, content.bind(context)(el), escape, context);
        } else if (typeof content == "object") {
            return el[method](createElement(content));
        } else {
            if (escape) {
                return el[method](content);
            } else {
                const container = document.createElement('div');
                container.innerHTML = content;
                return el[method](...container.childNodes);
            }
        }
    }
}

bury (object, ...keys) #

Set a value of an object following a chain of nested keys.

Syntax

bury(object, ...keys)

Arguments

object

An Object to receive keys/value

keys

An array of Strings to use as a chain to bury the value

Return Value

object

Example

bury({foo: 1}, 'alpha', 'beta', 'charlie', 'Hello World')
// => {
    foo: 1,
    alpha: {
        beta: {
            charlie: "Hello World"
        }
    }
}
SOURCE CODE
function bury (object, ...keys) {
  if(keys.length == 2){
    object[keys[0]] = keys[1]
  } else {
    const key = keys.shift();
    if(!(object[key] instanceof Object)) object[key] = {}
    bury(object[key], ...keys)
  }
  return object
}

content (element, content) #

This method replaces the content of an element with new content.

Syntax

content(element, content)

Arguments

element

An Element

content

A Element, NodeList, HTMLCollection, Array, Promise, String of text or html, Object passed to dolla's createElement.

Return Value

undefined

SOURCE CODE
import append from './append.js';

function content (el, content) {
    el.innerHTML = '';
    return append(el, content)
}

createElement (tagName="div", attributes={}) #

This method mirrors document.createElement, but adds the ability to include attributes and content for the initialized Element

Syntax

createElement(tagName="div", attributes={})
createElement(attributes)

Arguments

tagName optional

A String declaring what type of HTML tag to create

attributes optional

An Object whose keys are used to set attributes on the created element. All HTMLElement attributes are accepted including an additional option to define content

  • content: The value of the key content is passed into dolla's append method. Reference the append() documentation for more details about possible content values.
  • tag: A String declaring the type of HTML tag, used as an alternative to the first parameter

Return Value

Element

Example

createElement('table', {
    class: 'uniformTable',
    cellpadding: 0,
    style: {
        verticalAlign: 'center'
    },
    content: [{
        tag: 'tr'
        content: [{
            tag: 'td',
            content: 'Hello World'
        }]
    }]
})
SOURCE CODE
import setAttributes from './setAttributes.js';

function createElement(tagName='div', attributes={}) {
    if (typeof tagName == 'object') {
        attributes = tagName;
        tagName = attributes.tag || 'div';
    }

    const el = document.createElement(tagName);
    setAttributes(el, attributes)
    return el;
}

css (element, rule) #

Syntax sugar for getComputedStyle

Syntax

css(element, rule)

Arguments

element

An Element

selector

A String of a valid CSS rule

Return Value

String representation of rule value

Example

css(el, 'width')
// => "800px"
SOURCE CODE
function css (el, rule) {
    return getComputedStyle(el).getPropertyValue(rule);
}

filter (nodes, predicate) #

This method filters a NodeList with a predicate.

Syntax

filter(nodes, predicate)

Arguments

nodes

An Array or NodeList

predicate

A function where parameter is each item or node of nodes. The function should return truthy to include.

Return Value

Array

Example

filter(el.childNodes, n => n.selected)
SOURCE CODE
function filter(nodes, predicate){
    const filteredNodes = [];
    nodes.forEach(node => {
      if (predicate(node)) filteredNodes.push(node);
    })
    return filteredNodes;
}

getBoundingClientRect (...elements) #

This method gets the bounding client rectangle of a group of elements. Similar to Element.getBoundingClientRect(), but for n elements.

Syntax

getBoundingClientRect(...elements)

Arguments

elements

An Array of Elements

Return Value

DOMRect

SOURCE CODE
function getBoundingClientRect(...elements) {
    if (Array.isArray(elements[0]) && elements.length == 1) {
        elements = elements[0]
    }
    let rect = elements[0].getBoundingClientRect()
    rect = {
        left: rect.left,
        top: rect.top,
        right: rect.right,
        bottom: rect.bottom
    }
    elements.slice(1).forEach(el => {
        const thisRect = el.getBoundingClientRect()
        if (thisRect.left < rect.left) rect.left = thisRect.left
        if (thisRect.top < rect.top) rect.top = thisRect.top
        if (thisRect.bottom > rect.bottom) rect.bottom = thisRect.bottom
        if (thisRect.right > rect.right) rect.right = thisRect.right
    })
    
    return new DOMRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)
}

innerHeight (element) #

This method returns an element's height including padding, which is excluded from el.offsetHeigh.

Syntax

innerHeight(element)

Arguments

element

An Element

Return Value

Integer

SOURCE CODE
function innerHeight (el) {
    var style = getComputedStyle(el);
    return el.offsetHeight - parseInt(style.paddingTop) - parseInt(style.paddingBottom);
}

innerWidth (element) #

This method returns an element's width including padding, which is excluded from el.offsetWidth.

Syntax

innerWidth(element)

Arguments

element

An Element

Return Value

Integer

SOURCE CODE
function innerWidth (el) {
    var style = getComputedStyle(el);
    return el.offsetWidth - parseInt(style.paddingLeft) - parseInt(style.paddingRight);
}

insertAfter (anchor, element) #

This method appends an element after an anchor

Syntax

insertAfter(anchor, element)

Arguments

anchor

An Element

element

An Element, NodeList, HTMLCollection, Array

Return Value

Integer

Example

insertAfter(document.querySelector('#anchor'), document.createElement('button'))
insertAfter(document.querySelector('#anchor'), document.querySelector('#container').children)
insertAfter(document.querySelector('#anchor'), document.querySelector('#container').childNodes)
insertAfter(document.querySelector('#anchor'), [
    document.createElement('label'),
    document.createElement('button')
])
SOURCE CODE
function insertAfter(anchor, el) {
    if (Array.isArray(el) || el instanceof NodeList || el instanceof HTMLCollection) {
        const els = Array.from(el)
        while (els.length > 0) {
            anchor = insertAfter(anchor, els.shift());
        }
        return anchor
    } else if (Array.isArray(anchor) || anchor instanceof NodeList || anchor instanceof HTMLCollection) {
        return insertAfter(anchor[anchor.length - 1], el);
    } else if (anchor.parentNode) {
        if (!(el instanceof Node)) {
            el = new Text(el);
        }
        anchor.parentNode.insertBefore(el, anchor.nextSibling);
        return el
    } else {
        throw('argument of insertAfter unsupported')
    }
}

insertBefore (anchor, element) #

This method appends an element after an anchor

Syntax

insertBefore(anchor, element)

Arguments

anchor

An Element

element

An Element, NodeList, HTMLCollection, Array

Return Value

Integer

Example

insertBefore(document.querySelector('#anchor'), document.createElement('button'))
insertBefore(document.querySelector('#anchor'), document.querySelector('#container').children)
insertBefore(document.querySelector('#anchor'), document.querySelector('#container').childNodes)
insertBefore(document.querySelector('#anchor'), [
    document.createElement('label'),
    document.createElement('button')
])
SOURCE CODE
function insertBefore(anchor, el) {
    if (Array.isArray(el) || el instanceof NodeList || el instanceof HTMLCollection) {
        const els = Array.from(el)
        while (els.length > 0) {
            anchor = insertBefore(anchor, els.pop());
        }
        return anchor
    } else if (Array.isArray(anchor) || anchor instanceof NodeList || anchor instanceof HTMLCollection) {
        return insertBefore(anchor[0], el)
    }  else if (anchor.parentNode) {
        if (!(el instanceof Node)) {
            el = new Text(el);
        }
        anchor.parentNode.insertBefore(el, anchor);
        return el
    } else {
        throw('argument of insertBefore unsupported')
    }
}

isEmpty (element) #

This method returns if an element is empty

Syntax

isEmpty(element)

Arguments

element

An Element

Return Value

Boolean

SOURCE CODE
function isEmpty(element){
    return element.innerHTML === "";
}

isFocus (element) #

This method returns if an element is focused

Syntax

isFocus(element)

Arguments

element

An Element

Return Value

Boolean

SOURCE CODE
function isFocus(element){
    return document.activeElement === element;
}

isVisible (element) #

This method returns if an element is attached to the DOM

Syntax

isVisible(element)

Arguments

element

An Element

Return Value

Boolean

SOURCE CODE
function isVisible (el) {
    return el.offsetParent !== null;
}

listenerElement ([tagName], [attributes], listenerType, listenerCallback) #

This method returns a HTMLElement with an event listener

Syntax

listenerElement([tagName], [attributes], listenerType, listenerCallback)

Arguments

tagName optional

A String for html element

attributes optional

An Object of attributes for dolla's createElement

listenerType

A String representing the event type to listen to

listenerCallback

A function that receives an Event as a parameter

Return Value

Element

Example

listenerElement('button', {
    class: 'btn',
    content: 'Confirm'
}, 'click', e => {
    console.log(e)
})

listenerElement({
    class: 'btn',
    content: 'Confirm'
}, e => {
    console.log(e)
})
SOURCE CODE
import createElement from './createElement.js';

function listenerElement (...args) {
    let callback = args.pop()
    let listener = args.pop()
    if (typeof listener != 'string' && !Array.isArray(listener)) {
        args = args.concat(listener)
        listener = 'click'
    }
    if (typeof args[0] != 'string') {
        args.unshift('button')
    }
    const el = createElement(...args)
    if (!Array.isArray(listener)) listener = [listener]
    listener.forEach(listener => el.addEventListener(listener, callback))
    return el
}

map (elements, iteratee) #

This method returns if an element is attached to the DOM

Syntax

map(elements, iteratee)

Arguments

elements

An Array, HTMLCollection, NodeList

iteratee

A Function that receives each item in elements as an argument, the return of which is set as the index of the return array

Return Value

Array

Example

map(element.children, el => el.offsetHeight)
map(element.childNodes, el => el.offsetHeight)
map([
    el1,
    el2,
    el3
], el => el.offsetHeight)
SOURCE CODE
function map (elements, iteratee){
    var results = [];
    Array.from(elements).forEach((el, i) => {
      results.push(iteratee(el, i))
    })
    return results;
}

nextElementSiblings (element, filter) #

This method returns an element's following siblings.

Syntax

nextElementSibling(element, filter)

Arguments

element

An Element

filter

A method that receives the next sibling as a paramter, and returns true or false

Return Value

Array

Example

nextElementSiblings(el, sibling => {
    return sibling.tagName == "checkbox"
})
SOURCE CODE
function nextElementSiblings (el, filter) {
  const siblings = [];
  while(el = el.nextElementSibling) {
    if (!filter || filter(el)) {
      siblings.push(el)
    }
  }
  return siblings
}

offset (element) #

This method returns an element's DOMRect in relation to it's offsetParent

Syntax

offset(element)

Arguments

element

An Element or HTMLCollection

Return Value

DOMRect

SOURCE CODE
import offsetTo from './offsetTo.js';

function offset (el) {
    const parent = el.offsetParent
    const rect = el.getBoundingClientRect();
    if (parent) {
        return offsetTo(el, el.offsetParent);
    } else {
        return el.getBoundingClientRect()
    }
}

offsetTo (element, target) #

This method returns an elements position {top, left} in relation to a target element

Syntax

offsetTo(element, target)

Arguments

element

An Element or HTMLCollection

target

An Element

Return Value

DOMRect

SOURCE CODE
import offsetToBody from './offsetToBody.js';
function offsetTo(el, target) {
    const elRect = offsetToBody(el);
    const targetRect = offsetToBody(target);
    
    elRect.x = elRect.x - targetRect.x
    elRect.y = elRect.y - targetRect.y
    
    return elRect;
}

offsetToBody (element) #

This method returns an element's bounding DOMRect in relation to the rootNode (typically document.body)

Syntax

offsetToBody(element)

Arguments

element

An Element or HTMLCollection

Return Value

DOMRect

SOURCE CODE
import getBoundingClientRect from './getBoundingClientRect.js';
function offsetToBody (...el) {
    const rect = getBoundingClientRect(...el)
    rect.x = rect.x - window.scrollX
    rect.y = rect.y - window.scrollY
    return rect
}

offsetToViewport (element) #

This method returns an elements position {top, left} in relation to the viewport

Syntax

offsetToViewport(element)

Arguments

element

An Element or HTMLCollection

Return Value

DOMRect

SOURCE CODE
import getBoundingClientRect from './getBoundingClientRect.js';
function offsetToViewport (...el) {
    return getBoundingClientRect(...el);
}

outerHeight (element) #

This method returns the height of an element including margin

Syntax

outerHeight(element)

Arguments

element

An Element

Return Value

Integer

SOURCE CODE
function outerHeight (el) {
    var style = getComputedStyle(el);
    return el.offsetHeight + parseInt(style.marginTop) + parseInt(style.marginBottom);
}

outerWidth (element) #

This method returns the width of an element including margin

Syntax

outerWidth(element)

Arguments

element

An Element

Return Value

Integer

SOURCE CODE
function outerWidth (el) {
    var style = getComputedStyle(el);
    return el.offsetWidth + parseInt(style.marginLeft) + parseInt(style.marginRight);
}

prepend (element, content) #

This method is a same as append, but inserts content at the start of an elements children.

Syntax

prepend (element, content)
prepend (element, content, escape)
prepend (element, content, context)
prepend (element, content, method)
prepend (element, content, escape, context, method)

Arguments

element

An Element to add the event listener to

content

A Element, NodeList, HTMLCollection, Array, Promise, String of text or html, Object passed to dolla's createElement.

escape optional

A Boolean directing method to escape or not escape content that is a string

context optional

The value to be passed as the this parameter if content is a method

method optional

A String stating which method of Element instance to use to add content. Default is "append"

Return Value

undefined

Example

prepend(el, el2)
prepend(el, [el2, el3, el4])
prepend(el, el2.children)
prepend(el, el2.childNodes)
prepend(el, new Promise(resolve => {
    records.load().then(records => {
        resolve(records.map(record => {
            template(record)
        }))
    })
}))
prepend(el, {
    class: 'label',
    content: "Hello World"
})
prepend(el, "<span>Hello World</span>")
SOURCE CODE
import append from './append.js';

function prepend (el, item, escape, context) {
    return append(el, item, escape, context, 'prepend')
}

previousElementSiblings (element, filter) #

This method returns an element's previous siblings.

Syntax

previousElementSiblings(element, filter)

Arguments

element

An Element

filter

A method that receives the previous sibling as a paramter, and returns true or false

Return Value

Array

Example

previousElementSiblings(el, sibling => {
    return sibling.tagName == "checkbox"
})
SOURCE CODE
function previousElementSiblings (el, filter) {
  const siblings = [];
  while(el = el.previousElementSibling) {
    if(!filter || filter(el)) {
      siblings.push(el)
    }
  }
  return siblings.reverse()
}

remove (element) #

This method removes an element from the document/fragment to which it is attached

Syntax

remove(element)

Arguments

element

An Element

Return Value

Element

SOURCE CODE
function remove (el) {
    if (el instanceof NodeList || el instanceof Array || el instanceof HTMLCollection) {
        el = Array.from(el)
        el.forEach(remove);
    } else {
        el.parentNode.removeChild(el);
    }
    return el
}

replaceContents (element, ...nodes) #

This method replaces an element's content with new content

Syntax

remove(element, ...nodes)

Arguments

element

An Element

nodes

A Element, NodeList, HTMLCollection, Array, Promise, String of text or html, Object passed to dolla's createElement. Checkout append for more details about what content can be used

Return Value

undefined

Example

replaceContents(el, anotherElement.children)
replaceContents(el, {
    tag: 'button',
    class: 'btn'
})
SOURCE CODE
import remove from './remove.js';
import append from './append.js';

function replaceContents (el, ...nodes) {
    remove(el.childNodes);
    append(el, nodes);
}

serializeForm (form) #

This method returns object of a form element's key and value pairs

Syntax

serializeForm(form)

Arguments

form

An FormElement

Return Value

Object

Example

<form>
    <input name="user[name]" />
    <input name="user[email_address]" />
    <input name="team[is_active]" />
</form>
serializeForm(form)
// => {
//  [user]name: 'Rod Kimble',
//  [user]emailAddress: 'rod.kimble@hot-rod-productions.com',
//  [team][is_active]: true
//}
SOURCE CODE
function serializeForm (form) {
  var formData = {};
  for(var pair of new FormData(form).entries()) {
    formData[pair[0]] = pair[1];
  }
  return formData;
}

serializeFormToJSON (form) #

This method returns JSON of a form element's key and value pairs. This function unlike serializeForm allows the keys to nest keys (see usage)

Syntax

serializeFormToJSON(form)

Arguments

form

An FormElement

Return Value

JSON

Example

<form>
    <input name="user[name]">
    <input name="user[email_address]">
    <input name="team[is_active]">
</form>
serializeForm(form)
// => {
//  user: {
//      name: 'Rod Kimble',
//      emailAddress: 'rod.kimble@hot-rod-productions.com'
//  },
//  team: {
//      is_active: true
//  }
//}
SOURCE CODE
import serializeForm from './serializeForm.js';
import bury from './bury.js';

function serializeFormToJSON (form) {
  const formData = serializeForm(form);
  Object.keys(formData).forEach(key => {
    const keys = key.replace(']', '').split('[')
    if(keys.length > 1){
      formData[keys.shift()] = bury({}, ...(keys.concat(formData[key])))
      delete formData[key];
    }
  })
  return formData;
}

setAttributes (el, attributes={}) #

Assigns attributes and content for an Element

Syntax

assignAttributes(el, attributes={})

Arguments

el

An Element to assign attributes too

attributes optional

An Object whose keys are used to set attributes on the created element. All HTMLElement attributes are accepted including an additional option to define content

  • content: The value of the key content is passed into dolla's append method. Reference the append() documentation for more details about possible content values.
  • tag: A String declaring the type of HTML tag, used as an alternative to the first parameter

Return Value

Element

Example

assignAttributes(el, {
    class: 'uniformTable',
    cellpadding: 0,
    style: {
        verticalAlign: 'center'
    },
    content: [{
        tag: 'tr'
        content: [{
            tag: 'td',
            content: 'Hello World'
        }]
    }]
})
SOURCE CODE
import { BOOLEAN_ATTRIBUTES, HTML_ATTRIBUTES } from './constants.js';
import StateBus from './StateBus.js';
import content from './content.js';

function setAttributes(el, attributes={}) {
    Object.keys(attributes).forEach(key => setAttribute(el, key, attributes[key]));
    return el
}

function setAttribute(el, key, value) {
    if (value instanceof Promise) {
        value.then(v => setAttribute(el, key, v))
    } else if (value instanceof StateBus) {
        value.addListener(v => setAttribute(el, key, v))
        if (key == "content") {
            content(el, value.value)
        } else {
            setAttribute(el, key, value.value)
        }
    } else {
        if (key == "value") {
            el.value = value;
        } else if (key == "data" && typeof value == 'object') {
            Object.keys(value).forEach(key => {
                el.dataset[key] = typeof value[key] == "object" ? JSON.stringify(value[key]) : value[key];
            });
        } else if (key == "style" && typeof value == 'object') {
            Object.keys(value).forEach(key => {
                if (value[key] instanceof StateBus) {
                    value[key].addListener(v => el.style[key] = v)
                    el.style.setProperty(key, value[key].value)
                } else {
                    el.style.setProperty(key, value[key]);
                }
            });
        } else if (key == "content" || key == "children") {
            content(el, value)
        } else if (key.match(/^on[a-z]/)) {
            el[key] = value
        } else if (BOOLEAN_ATTRIBUTES.find(a => a.toUpperCase() == key.toUpperCase())) {
            key = BOOLEAN_ATTRIBUTES.find(a => a.toUpperCase() == key.toUpperCase())
            el[key] = value !== false;
        } else if (HTML_ATTRIBUTES.find(a => key.match(new RegExp(a)))) {
            el.setAttribute(key, value)
        }
    }
}

stateAttribute (value) #

Initializes StateBus with value

Syntax

stateAttribute(value)

Arguments

value

Initial value of attribute

Return Value

StateBus

Example

const el = createElement('button')
const isOpen = stateAttribute(true)
isOpen.addListener(v => el.disabled = v.value)
SOURCE CODE
import StateBus from './StateBus.js';

function stateAttribute(value) {
    return new StateBus(value)
}

StateBus (value) #

StateBus is a simple javascript class that hold a value and calls listener callbacks when it changes

Syntax

new StateBus(value)

Constructor

value

Initial value of attribute

Return Value

StateBus

Example

const el = createElement('button')
const isOpen = new StateBus(true)
isOpen.addListener(v => el.disabled = v.value)

Instance Methods

get()

Returns value

set(v)

Sets state

addListener(callback:function)

Add listener

removeListener(callback:function)

Remove Listener

valueOf()

Returns value

transform(transformation:function)

Returns a new StateBus that follows changes to this StateBus, with the transformation applied to value everytime it changes

SOURCE CODE
class StateBus {
    value = null;
    listens = []
    
    constructor(v) {
        this.value = v
    }
    valueOf () {
        return this.value
    }
    get () {
        return this.value
    }
    set (v, metadata) {
        const valueWas = this.value
        if (valueWas != v) {
            this.dispatch(v, valueWas, metadata)
            this.value = v
        }
        return this
    }
    dispatch (v, valueWas, metadata) {
        if (v == undefined) v = this.value
        this.listens.forEach(callback => {
            callback(v, valueWas, metadata)
        })
    }
    addListener (callback) {
        this.listens.push(callback)
    }
    removeListener (callback) {
        this.listens = this.listens.filter(x => x !== callback)
    }
    transform (transformation) {
        const spawn = new StateBus(transformation(this.value))
        this.addListener((...args) => spawn.set(transformation(...args)))
        return spawn
    }
}

StuckObserver (options={}) #

Extends IntersectionObserver to default callback to toggle a desigated class when element is stuck

Syntax

const observer = new StuckObserver(options={})
const el = createElement({style: {position: 'sticky', top: 0}})
observer.observe(el)

Constructor

options

root

Same as IntersectionObserver

top

Number | pixel inset into root to determine sticky state, default: 1

right

Number | pixel inset into root to determine sticky state, default: -9999, which essentially removes it as a boundary

bottom

Number | pixel inset into root to determine sticky state, default: -9999, which essentially removes it as a boundary

left

Number | pixel inset into root to determine sticky state, default: -9999, which essentially removes it as a boundary

class

String | class to toggle, when stuck, class is added, default: stuck

Return Value

StuckObserver

Instance Methods

Inherits from IntersectionObserver

SOURCE CODE
class StuckObserver extends IntersectionObserver {
    
    constructor (options={}) {
        options = Object.assign({
            top: 1,
            right: -9999,
            bottom: -9999,
            left: -9999,
            class: 'stuck'
        }, options)
        const margin = ['top', 'right', 'bottom', 'left'].map(dir => options[dir] * -1 + "px").join(" ")
        super (entries => {
            entries.forEach(entry => {
                entry.target.classList.toggle(options.class, entry.intersectionRatio < 1);
            })
        }, {
            root: options.root,
            rootMargin: margin,
            threshold: 1
        })
    }
}

toElements (content) #

This method converts a string of HTML to Elements

Syntax

toElements(content)

Arguments

content

A String of HTML or a Function that retuns a string of HTML

Return Value

NodeList

Example

toElements("<div class='container'><label>Label</label><input type='checkbox'></div>")
toElements(() => "<div class='container'><label>Label</label><input type='checkbox'></div>")
SOURCE CODE
function toElements (content) {
    if (typeof content == "function") {
        return toElements(content())
    } else if (typeof content == "string") {
        const container = document.createElement('template')
        container.innerHTML = content.trim();
        return container.content.childNodes
    } else {
        return content
    }
}

toggleCollapse (function) #

SOURCE CODE
function toggleCollapse (el, show, options={}) {
    if (typeof show == "object") {
        options = show
        show = undefined
    }
    el.isCollapsed = typeof show == "boolean" ? show : el.isCollapsed != true
    if (el.isCollapsed) {
        el.style.height = (options.height || 0) + 'px'
    } else {
        el.style.overflow = "scroll"
        const height = el.scrollHeight
        el.style.removeProperty('overflow')
        el.style.height = height + 'px'
    }
    return el.isCollapsed
}

trigger (element, eventName) #

This method calls an element's dispatchEvent with a custom event.

Syntax

trigger(element, eventName)

Arguments

element

An Element

eventName

A String representing the event type

options

Object passed to CustomEvent constructor. Defaults target, bubbles, cancelable

Return Value

false if event is cancelable, and at least one of the event handlers which received event called Event.preventDefault(). Otherwise true.

Example

el.addEventListener('attachedToDOM', e => el.style.background = 'green')
trigger(el, 'attachedToDOM')
SOURCE CODE
function trigger(el, eventName, options) {
    options = Object.assign({
        bubbles: true,
        cancelable: true
    }, options)
    return el.dispatchEvent(new CustomEvent(eventName, options));
}

Contributors

Bug Reporting

Please report bugs in GitHub Issues

Licensing

Uniform is released under the MIT License

© 2024 Ben Ehmke