dommini
v0.1.0
Published
JavaScript package for easy and lightweight creation of DOM trees and HTML files
Maintainers
Readme
dommini
JavaScript package for easy and lightweight creation of DOM trees and HTML files. May be used as a template language (originally created from a module used for a private JSDoc template)
Features:
- no dependencies
- minimalistic syntax (see below demo and examples)
const {Document,tags,utils} = require("dommini")
const {link,script,div,span,ol,li,a,p} = tags
const {text,comment,attr,addClass,shortcut} = utils
const customtag = shortcut("customtag")
doc = new Document({title:"dommini demo"})
doc.head.add([
link().attr({rel:"stylesheet",href:"style.css"}),
script().attr({type:"text/javascript",src:"script.js"})
])
doc.body.add(function(){
div(ol(["home", "about", "contact"].map(title => {
return li(a(title).attr({href:`${title}.html`}))
}))).id("header").class("h-cls")
comment("some comment")
div(function(){
attr({id:"body",class:"some-class"})
addClass("another-class")
p("Lorem ipsum")
text("dolor sit amet")
})
customtag(div(),span())
})
console.log(doc.toString())Output:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="generator" content="dommini 0.1.0">
<title>dommini demo</title>
<link rel="stylesheet" href="style.css">,
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div id="header" class="h-cls">
<ol>
<li>
<a href="home.html">home</a>
</li>
<li>
<a href="about.html">about</a>
</li>
<li>
<a href="contact.html">contact</a>
</li>
</ol>
</div>
<!--some comment-->
<div id="body" class="some-class another-class">
<p>Lorem ipsum</p>
dolor sit amet
</div>
<customtag>
<div></div>
<span></span>
</customtag>
</body>
</html>See usage section for more details.
Disclaimer: the true dommini output is "one-line" HTML code, please use an external lib to prettify it.
Installation
npm install domminiDocumentation
- inside this README
- inside source code :-)
- to build JSDoc html documentation:
- run
npm run doc - see
doc/outdirectory
- run
Usage / documentation
Table of Contents
Hello, world!
const {html,body,h1} = require("dommini").tags
var e = html(body(h1('Hello, world!')))
console.log(e.toString())<html>
<body>
<h1>
Hello, world!
</h1>
</body>
</html>Elements
Creating
With new keyword
as new Element(tag,...), new CommentNode(comment) or new TextNode(text):
const {Element,TextNode,CommentNode} = require("dommini")
var e = new Element("html", new Element("body",
new CommentNode("some comment"),
new Element("h1", "Hello"),
new TextNode("world!")
))
console.log(e.toString())<html>
<body>
<!--some comment-->
<h1>Hello</h1>
world!
</body>
</html>Shortcuts
dommini.tags (should) contain shortcuts for all HTML5 tags.
dommini.utils defines shortcut for text node and comment node.
const {tags,utils} = require("dommini")
const {html,body,h1} = tags
const {text,comment} = utils
var e = html(body(
comment("some comment"),
h1("Hello"),
text("world!")
))
console.log(e.toString())<html>
<body>
<!--some comment-->
<h1>Hello</h1>
world!
</body>
</html>Custom elements
Element tag can be any string.
dommini.utils.shortcut can also be used to shortcut it.
const {Element,utils} = require("dommini")
const {shortcut} = utils
const [customdiv,customspan] = [shortcut("customdiv"),shortcut("customspan")]
var e = customdiv([
new Element("customh1"),
customspan(),
])
console.log(e.toString())<customdiv>
<customh1></customh1>
<customspan></customspan>
</customdiv>Attributes
Setting
Set attributes
- with
elem.attr(...)method passing an- key-value as two parameters
- object of key-value pairs
- using shortcuts methods (currently for
elem.idandelem.class) - using
elem.addClassto add class, passing- string
- strings
- array of strings
- using context and
utils.attrandutils.addClass:
const {tags,utils} = require("dommini")
const {div} = tags
const {attr,addClass} = utils
// key-value two parameters
var e = div().attr("k1","val1")
console.log(e.toString())
// key-value object
var e = div().attr({k1:"val1",k2:"val2"})
console.log(e.toString())
// attr shortcuts
var e = div().id("42").class("cls")
console.log(e.toString())
// addClass - one string
var e = div().class("cls").addClass("cls-2")
console.log(e.toString())
// addClass - strings
var e = div().class("cls").addClass("cls-2","cls-3")
console.log(e.toString())
// addClass - array of strings
var e = div().class("cls").addClass(["cls-2","cls-3"])
console.log(e.toString())
// context
var e = div().context(function(){
addClass("cls")
attr({k1:"val1",k3:"val3"})
addClass("cls-2")
})
console.log(e.toString())<div k1="val1"></div>
<div k1="val1" k2="val2"></div>
<div id="42" class="cls"></div>
<div class="cls cls-2"></div>
<div class="cls cls-2 cls-3"></div>
<div class="cls cls-2 cls-3"></div>
<div k1="val1" k3="val3" class="cls cls-2"></div>Getting
To get currently set attributes, just call elem.attr() with no argument:
const {div} = require("dommini").tags
var e = div().id("42").class("cls").attr("key","val")
console.log(e.attr()){ id: '42', key: 'val', class: 'cls' }Adding children
At creation
Child nodes can be added at creation time:
- as a single element
- as multiple elements
- as an array of elements
- using context node
const {div,span,h1} = require("dommini").tags
// add one element
var e = div(span())
console.log(e.toString())
// add elements
var e = div(h1(),span())
console.log(e.toString())
// add array of elements
var e = div([h1(),span()])
console.log(e.toString())
// context
var e = div(function(){
h1()
span()
})
console.log(e.toString())<div><span></span></div>
<div><h1></h1><span></span></div>
<div><h1></h1><span></span></div>
<div><h1></h1><span></span></div>Using element.add
Child nodes can be added using elem.add:
adda single elementaddmultiple elementsaddarray of elementsaddarray of elementsputa single element- using context node
const {div,span,h1} = require("dommini").tags
// add one element
var e = div().add(span())
console.log(e.toString())
// add elements
var e = div().add(h1(),span())
console.log(e.toString())
// add array of elements
var e = div().add([h1(),span()])
console.log(e.toString())
// context
var e = div().add(function(){
h1()
span()
})
console.log(e.toString())<div><span></span></div>
<div><h1></h1><span></span></div>
<div><h1></h1><span></span></div>
<div><h1></h1><span></span></div>Instead of add, one can put an element.
The difference between add and put:
elem.add(child)returnelemelem.put(child)returnchild
const {div,span} = require("dommini").tags
var d = div()
var a = d.add(span())
console.log(a.toString()) // <div><span></span></div>
var s = d.put(span())
console.log(s.toString()) // <span></span><div><span></span></div>
<span></span>Using context
Using elem.add or elem.context method, all elements directly created inside given callback are added to the context element:
const {div,span,h1} = require("dommini").tags
var e = div().context(function(){
h1()
span()
})
console.log(e.toString())<div><h1></h1><span></span></div>Context
Using a function as a parameter of element constructor, elem.add or elem.context methods, the element is considered as the context element.
This means, that:
utils.attrandutils.addClassfunctions are applied to that node- all newly created "free" elements are added to the context element (in the order of creation)
const {tags,utils} = require("dommini")
const {section,div,span,h1} = tags
const {attr,addClass} = utils
var e = section()
e.context(function(){
attr({id:"context",class:"cls"}) // attr of the context
addClass("cls-2") // add class to the context
var d = div().class("free") // "free" element
var s = span().class("not-free") // NOT "free" element, added to "d"
d.add(h1(),s)
})
console.log(e.toString())<section id="context" class="cls cls-2">
<div class="free">
<h1></h1>
<span class="not-free"></span>
</div>
</section>Context can also be nested
const {tags,utils} = require("dommini")
const {section,div,span,h1} = tags
const {attr,addClass} = utils
var e = section().context(function(){
attr({id:"section-1"})
h1("section 1")
div(function(){
attr({id:"subsection-1.1"})
h1("subsection 1.1")
span()
})
})
console.log(e.toString())<section id="section-1">
<h1>section 1</h1>
<div id="subsection-1.1">
<h1>subsection 1.1</h1>
<span></span>
</div>
</section>The concept is mainly useful for more complex code:
- conditions and cycles
- external functions
- ...
const {tags,utils} = require("dommini")
const {main,section,div,span,h1,h2,a} = tags
const {attr,addClass} = utils
function box(title,content,level=1) {
if (level === 1) {
var sec = section(h1(title)).put(div(content))
} else if (level === 2) {
var sec = div(span(h2(title))).put(span(content))
} else {
var sec = span(title)
}
sec.context(function(){
a(`see ${title}`).attr({href:`http://${title}`})
if (title.endsWith("3")) addClass("title3")
})
return sec
}
var e = main(function(){
box("main title",box("sub-sub-title","sub-sub-content",3))
var subs = ["sub1","sub2","sub3"]
subs.forEach(s => box(s,s.repeat(2),2))
})
console.log(e.toString())<main>
<section>
<h1>main title</h1>
<div>
<span>
sub-sub-title
<a href="http://sub-sub-title">see sub-sub-title</a>
</span>
<a href="http://main title">see main title</a>
</div>
</section>
<div>
<span>
<h2>sub1</h2>
</span>
<span>
sub1sub1
<a href="http://sub1">see sub1</a>
</span>
</div>
<div>
<span>
<h2>sub2</h2>
</span>
<span>
sub2sub2
<a href="http://sub2">see sub2</a>
</span>
</div>
<div>
<span>
<h2>sub3</h2>
</span>
<span class="title3">
sub3sub3
<a href="http://sub3">see sub3</a>
</span>
</div>
</main>Extending
Element class can be easily extended
const {Element,tags} = require("dommini")
Element.prototype.href = function(address) {
return this.attr("href",address)
}
var e = tags.a().href("https://github.com/")
console.log(e.toString())<a href="https://github.com/"></a>Other
parent and children
Elements have parent and children attributes:
const {div,span,h1} = require("dommini").tags
var h = h1()
var s = span()
var d = div(h,s)
console.log(d.parent) // null
console.log(s.parent) // Element{_tag:'div',...}
console.log(s.children) // []
console.log(d.children) // [Element{_tag:'h1',...},Element{_tag:'span',...}]remove
Node can be removed if needed.
const {div,span} = require("dommini").tags
var d = div()
var s = d.put(span())
console.log(d.toString()) // <div><span></span></div>
s.remove()
console.log(d.toString()) // <div></div>clone
Elements can be cloned.
const {div,span} = require("dommini").tags
var d = div()
var s = span().id("span1")
d.add(s)
d.add(s) // s is removed before adding! so d has only 1 child
console.log(d.toString())
d.add(s.clone().id("span2")) // now it has 2 children
console.log(d.toString())<div><span id="span1"></span></div>
<div><span id="span1"></span><span id="span2"></span></div>Document
dommini.Document represents the complete document. it is created as new Document(attrs), where attrs is an object with string values and keys:
- doctype="html"
- lang="en"
- charset="utf-8"
- title
- keywords
- author
- "application-name"
- description
- generator="dommini {version}" Values are defaulted or optional.
const {Document} = require("dommini")
var doc = new Document({keywords:"dommini js"})
console.log(doc.toString())<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="keywords" content="dommini js">
<meta name="generator" content="dommini 0.1.0">
</head>
<body></body>
</html>html, head, body
html, head and body elements are attributes of the Document instance
const {Document,tags} = require("dommini")
const {div,span,script} = tags
var doc = new Document({generator:undefined})
doc.html.attr("manifest","/example.appcache")
doc.head.add(script())
doc.body.context(function(){
div()
span()
})
console.log(doc.toString())<!DOCTYPE html>
<html manifest="/example.appcache" lang="en">
<head>
<meta charset="utf-8">
<script></script>
</head>
<body>
<div></div>
<span></span>
</body>
</html>Attributes
Similarly to element.attr, document.attr() works as a getter and document.attr(...) can set attributes as key-value two arguments or as an object of key-value pairs.
Have a look at Document construction for available attributes.
In fact, you can set anything to the Document, but only the implemented stuff is meaningful and will have effect.
To create a (not yet) unsupported meta input, you can always create a meta element in document.head.
const {Document,tags} = require("dommini")
var {meta} = tags
var doc = new Document()
doc.attr({
description:"document.attr",
title:"attr",
whatever: "anything",
})
doc.head.add(meta().attr({name:"some-name",content:"some-content"}))
console.log(doc.attr())
console.log(doc.toString()){
doctype: 'html',
lang: 'en',
title: 'attr',
charset: 'utf-8',
keywords: '',
author: '',
'application-name': '',
description: 'document.attr',
generator: 'dommini 0.1.0',
whatever: 'anything'
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="document.attr">
<meta name="generator" content="dommini 0.1.0">
<title>attr</title>
<meta name="some-name" content="some-content">
</head>
<body></body>
</html>Other
Document can be cloned.
const {Document} = require("dommini")
var doc = new Document()
var doc2 = doc.clone()
console.log(doc.toString() === doc2.toString()) // true
doc.attr({title:"title"})
console.log(doc.toString() === doc2.toString()) // falseTODO
- more DOM API functionality (insertAfter,...)?
- pretty printing?
Contributing
is welcome :-)
Maintainer
Acknowledgement
- inspired by dominate python package
- the context-defined adding of new elements)
- partially this README and some examples
