|
|
@@ -1,46 +1,11 @@
|
|
|
|
|
|
-
|
|
|
-// TODO: search for .childNodes
|
|
|
-export function queryChildren(parent: HTMLElement, selector?: string): HTMLElement[] {
|
|
|
- let childNodes = parent.childNodes
|
|
|
- let a = []
|
|
|
-
|
|
|
- for (let i = 0; i < childNodes.length; i++) {
|
|
|
- let childNode = childNodes[i]
|
|
|
- if (
|
|
|
- childNode.nodeType === 1 && // an element
|
|
|
- (!selector || elementMatches(childNode as HTMLElement, selector))
|
|
|
- ) {
|
|
|
- a.push(childNode)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return a
|
|
|
-}
|
|
|
-
|
|
|
-export function queryChild(parent: HTMLElement, selector?: string): HTMLElement | null {
|
|
|
- let childNodes = parent.childNodes
|
|
|
-
|
|
|
- for (let i = 0; i < childNodes.length; i++) {
|
|
|
- let childNode = childNodes[i]
|
|
|
- if (
|
|
|
- childNode.nodeType === 1 && // an element
|
|
|
- (!selector || elementMatches(childNode as HTMLElement, selector))
|
|
|
- ) {
|
|
|
- return childNode as HTMLElement
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return null
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
// TODO: util for animation end
|
|
|
// TODO: get straight the distinction between HTMLElement and Element
|
|
|
|
|
|
+
|
|
|
+// Creating
|
|
|
+// ----------------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
// TODO: use in other places
|
|
|
// TODO: rename to createElement
|
|
|
export function makeElement(tagName, attrs, content?): HTMLElement {
|
|
|
@@ -67,39 +32,6 @@ export function makeElement(tagName, attrs, content?): HTMLElement {
|
|
|
return el
|
|
|
}
|
|
|
|
|
|
-const PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i
|
|
|
-
|
|
|
-// find other places to do this
|
|
|
-export function applyStyle(el: HTMLElement, props: object | string, propVal?: any) {
|
|
|
- if (typeof props === 'object') {
|
|
|
- for (let propName in props) {
|
|
|
- applyStyleProp(el, propName, props[propName])
|
|
|
- }
|
|
|
- } else if (typeof props === 'string') {
|
|
|
- applyStyleProp(el, props, propVal)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// TODO: just expose this?
|
|
|
-function applyStyleProp(el, name, val) {
|
|
|
- if (val == null) {
|
|
|
- el.style[name] = ''
|
|
|
- } else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) {
|
|
|
- el.style[name] = val + 'px'
|
|
|
- } else {
|
|
|
- el.style[name] = val
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-export type ElementContent = string | Node | NodeList | Node[]
|
|
|
-
|
|
|
-export function appendContentTo(el: HTMLElement, content: ElementContent) {
|
|
|
- let childNodes = normalizeContent(content)
|
|
|
- for (let i = 0; i < childNodes.length; i++) {
|
|
|
- el.appendChild(childNodes[i])
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
export function htmlToElement(htmlString): HTMLElement {
|
|
|
htmlString = htmlString.trim()
|
|
|
let container = document.createElement(computeContainerTag(htmlString))
|
|
|
@@ -129,18 +61,58 @@ function computeContainerTag(html: string) {
|
|
|
}
|
|
|
|
|
|
|
|
|
-// TODO: rename to listenByClassName
|
|
|
-export function listenViaDelegation(container: HTMLElement, eventType, childClassName, handler) {
|
|
|
- container.addEventListener(eventType, function(ev: Event) {
|
|
|
- for (let node = ev.target as HTMLElement; node !== container; node = node.parentNode as HTMLElement) {
|
|
|
- if (node.classList.contains(childClassName)) {
|
|
|
- handler.call(node, ev)
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
+// Inserting / Removing
|
|
|
+// ----------------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+export type ElementContent = string | Node | NodeList | Node[]
|
|
|
+
|
|
|
+export function appendContentTo(el: HTMLElement, content: ElementContent) {
|
|
|
+ let childNodes = normalizeContent(content)
|
|
|
+ for (let i = 0; i < childNodes.length; i++) {
|
|
|
+ el.appendChild(childNodes[i])
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function prependWithinEl(parent: HTMLElement, content: ElementContent) {
|
|
|
+ let newEls = normalizeContent(content)
|
|
|
+ let afterEl = parent.firstChild || null // if no firstChild, will append to end, but that's okay, b/c there were no children
|
|
|
+
|
|
|
+ for (let i = 0; i < newEls.length; i++) {
|
|
|
+ parent.insertBefore(newEls[i], afterEl)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function insertAfterEl(refEl: HTMLElement, content: ElementContent) {
|
|
|
+ let newEls = normalizeContent(content)
|
|
|
+ let afterEl = refEl.nextSibling || null
|
|
|
+
|
|
|
+ for (let i = 0; i < newEls.length; i++) {
|
|
|
+ refEl.parentNode.insertBefore(newEls[i], afterEl)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function normalizeContent(content: ElementContent): NodeList | Node[] {
|
|
|
+ let els
|
|
|
+ if (typeof content === 'string') {
|
|
|
+ els = htmlToElements(content) // TODO: optimization, htmlToNodeList
|
|
|
+ } else if (content instanceof Node) {
|
|
|
+ els = [ content ]
|
|
|
+ } else { // assumed to be HTMLElement[]
|
|
|
+ els = content
|
|
|
+ }
|
|
|
+ return els
|
|
|
+}
|
|
|
+
|
|
|
+export function removeElement(el: HTMLElement) {
|
|
|
+ if (el.parentNode) {
|
|
|
+ el.parentNode.removeChild(el)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+// Querying
|
|
|
+// ----------------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
// from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
|
|
|
const matchesMethod =
|
|
|
Element.prototype.matches ||
|
|
|
@@ -172,6 +144,61 @@ export function elementMatches(el: HTMLElement, selector: string) {
|
|
|
return matchesMethod.call(el, selector)
|
|
|
}
|
|
|
|
|
|
+// TODO: user new signature in other places
|
|
|
+// this is only func that accepts array :(
|
|
|
+export function findElsWithin(containers: HTMLElement[] | HTMLElement, selector: string): HTMLElement[] {
|
|
|
+ if (containers instanceof HTMLElement) {
|
|
|
+ containers = [ containers ]
|
|
|
+ }
|
|
|
+ let allChildEls: HTMLElement[] = []
|
|
|
+
|
|
|
+ for (let i = 0; i < containers.length; i++) {
|
|
|
+ let childEls = containers[i].querySelectorAll(selector)
|
|
|
+ for (let j = 0; j < childEls.length; j++) {
|
|
|
+ allChildEls.push(childEls[j] as HTMLElement)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return allChildEls
|
|
|
+}
|
|
|
+
|
|
|
+export function queryChildren(parent: HTMLElement, selector?: string): HTMLElement[] {
|
|
|
+ let childNodes = parent.childNodes
|
|
|
+ let a = []
|
|
|
+
|
|
|
+ for (let i = 0; i < childNodes.length; i++) {
|
|
|
+ let childNode = childNodes[i]
|
|
|
+ if (
|
|
|
+ childNode.nodeType === 1 && // an element
|
|
|
+ (!selector || elementMatches(childNode as HTMLElement, selector))
|
|
|
+ ) {
|
|
|
+ a.push(childNode)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return a
|
|
|
+}
|
|
|
+
|
|
|
+export function queryChild(parent: HTMLElement, selector?: string): HTMLElement | null {
|
|
|
+ let childNodes = parent.childNodes
|
|
|
+
|
|
|
+ for (let i = 0; i < childNodes.length; i++) {
|
|
|
+ let childNode = childNodes[i]
|
|
|
+ if (
|
|
|
+ childNode.nodeType === 1 && // an element
|
|
|
+ (!selector || elementMatches(childNode as HTMLElement, selector))
|
|
|
+ ) {
|
|
|
+ return childNode as HTMLElement
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// Event Delegation
|
|
|
+// ----------------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
export function listenBySelector(
|
|
|
container: HTMLElement,
|
|
|
eventType: string,
|
|
|
@@ -217,68 +244,31 @@ export function listenToHoverBySelector(
|
|
|
}
|
|
|
|
|
|
|
|
|
-// TODO: user new signature in other places
|
|
|
-// this is only func that accepts array :(
|
|
|
-export function findElsWithin(containers: HTMLElement[] | HTMLElement, selector: string): HTMLElement[] {
|
|
|
- if (containers instanceof HTMLElement) {
|
|
|
- containers = [ containers ]
|
|
|
- }
|
|
|
- let allChildEls: HTMLElement[] = []
|
|
|
-
|
|
|
- for (let i = 0; i < containers.length; i++) {
|
|
|
- let childEls = containers[i].querySelectorAll(selector)
|
|
|
- for (let j = 0; j < childEls.length; j++) {
|
|
|
- allChildEls.push(childEls[j] as HTMLElement)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return allChildEls
|
|
|
-}
|
|
|
-
|
|
|
-export function removeElement(el: HTMLElement) {
|
|
|
- if (el.parentNode) {
|
|
|
- el.parentNode.removeChild(el)
|
|
|
- }
|
|
|
-}
|
|
|
+// Style
|
|
|
+// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
-export function prependWithinEl(parent: HTMLElement, content: ElementContent) {
|
|
|
- let newEls = normalizeContent(content)
|
|
|
- let afterEl = parent.firstChild || null // if no firstChild, will append to end, but that's okay, b/c there were no children
|
|
|
+const PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i
|
|
|
|
|
|
- for (let i = 0; i < newEls.length; i++) {
|
|
|
- parent.insertBefore(newEls[i], afterEl)
|
|
|
+// find other places to do this
|
|
|
+export function applyStyle(el: HTMLElement, props: object, propVal?: any) {
|
|
|
+ for (let propName in props) {
|
|
|
+ applyStyleProp(el, propName, props[propName])
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export function insertAfterEl(refEl: HTMLElement, content: ElementContent) {
|
|
|
- let newEls = normalizeContent(content)
|
|
|
- let afterEl = refEl.nextSibling || null
|
|
|
-
|
|
|
- for (let i = 0; i < newEls.length; i++) {
|
|
|
- refEl.parentNode.insertBefore(newEls[i], afterEl)
|
|
|
+export function applyStyleProp(el: HTMLElement, name: string, val) {
|
|
|
+ if (val == null) {
|
|
|
+ el.style[name] = ''
|
|
|
+ } else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) {
|
|
|
+ el.style[name] = val + 'px'
|
|
|
+ } else {
|
|
|
+ el.style[name] = val
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function normalizeContent(content: ElementContent): NodeList | Node[] {
|
|
|
- let els
|
|
|
- if (typeof content === 'string') {
|
|
|
- els = htmlToElements(content) // TODO: optimization, htmlToNodeList
|
|
|
- } else if (content instanceof Node) {
|
|
|
- els = [ content ]
|
|
|
- } else { // assumed to be HTMLElement[]
|
|
|
- els = content
|
|
|
- }
|
|
|
- return els
|
|
|
-}
|
|
|
|
|
|
-// TODO: switch to tokenList.toggle
|
|
|
-export function toggleClassName(el, className, bool) {
|
|
|
- if (bool) {
|
|
|
- el.classList.add(className)
|
|
|
- } else {
|
|
|
- el.classList.remove(className)
|
|
|
- }
|
|
|
-}
|
|
|
+// Dimensions
|
|
|
+// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
export function computeHeightAndMargins(el: HTMLElement) {
|
|
|
let computed = window.getComputedStyle(el)
|