Add Use helper
This should finally solve the question of how to pull behaviour defined in JS modules into static HTML without bending over backwards.
This commit is contained in:
parent
f209112f58
commit
797b6448c8
2 changed files with 92 additions and 0 deletions
39
use.js
Normal file
39
use.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const apply = (func, node) => {
|
||||
if (typeof func == "function") {
|
||||
func(node)
|
||||
} else if ("then" in func) {
|
||||
func.then(result => apply(result, node))
|
||||
} else if ("default" in func) {
|
||||
func.default(node)
|
||||
}
|
||||
}
|
||||
|
||||
export const use = node => {
|
||||
const code = Function("return (" + node.getAttribute("use") + ")")
|
||||
const func = code()
|
||||
apply(func, node)
|
||||
}
|
||||
|
||||
export const observe = (root = document) => {
|
||||
const observer = new MutationObserver(mutations => {
|
||||
mutations.forEach(mutation => {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
if (node.hasAttribute("use")) {
|
||||
use(node)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
observer.observe(root, {subtree: true, childList: true})
|
||||
return observer
|
||||
}
|
||||
|
||||
export const run = (root = document) => {
|
||||
root.querySelectorAll("[use]").forEach(use)
|
||||
}
|
||||
|
||||
export const install = () => {
|
||||
observe(document)
|
||||
run(document)
|
||||
}
|
||||
export default install
|
53
use.md
Normal file
53
use.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Use
|
||||
|
||||
A helper module to connect the world of modular javascript with that of plain
|
||||
HTML.
|
||||
|
||||
## Rationale
|
||||
|
||||
The problem this module tries to solve is that of connecting behaviours defined
|
||||
in a JavaScript module to HTML tags without having to:
|
||||
|
||||
- Select elements by ID
|
||||
- Build a custom system to select elements uniquely
|
||||
- Generate the HTML nodes directly in JavaScript
|
||||
|
||||
The solution this module provides is a `use` attribute, which can be set on an
|
||||
element in HTML, which will be evaluated as JS and interpreted as follows:
|
||||
|
||||
- If it is a function, call it on the element
|
||||
- If it is a promise, await it and retry with its result
|
||||
- If it is a module, retry with its `default` value
|
||||
|
||||
This allows setting specific functionality on individual elements.
|
||||
|
||||
**Note** the adjacency to custom elements and customized builtin elements, and
|
||||
how patterns in the usage of `use` may often be refactored into either of these.
|
||||
|
||||
## Limitations
|
||||
|
||||
For performance reasons, this module does not listen on attribute changes.
|
||||
Since the focus of this module is to interact with plain HTML, any nodes
|
||||
modified within JavaScript fall outside of its scope, and any code that adds a
|
||||
`use` attribute to them should just call the desired function directly on the
|
||||
node.
|
||||
|
||||
## Interface / Examples
|
||||
|
||||
```js
|
||||
use.run(root=document)
|
||||
// Runs once on all the children of its root.
|
||||
|
||||
use.observe(root=document)
|
||||
// Observes the given root and runs on all newly added
|
||||
// child elements. Does not perform an initial run over
|
||||
// already existing elements.
|
||||
|
||||
use.use(element)
|
||||
// Runs once on a selected element.
|
||||
// Normally not recommended.
|
||||
|
||||
use.install()
|
||||
// Observes the entire document and performs
|
||||
// an initial scan over existing elements.
|
||||
```
|
Loading…
Reference in a new issue