npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dommini

v0.1.0

Published

JavaScript package for easy and lightweight creation of DOM trees and HTML files

Downloads

2

Readme

dommini

npm

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 dommini

Documentation

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.id and elem.class)
  • using elem.addClass to add class, passing
    • string
    • strings
    • array of strings
  • using context and utils.attr and utils.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:

  • add a single element
  • add multiple elements
  • add array of elements
  • add array of elements
  • put a 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) return elem
  • elem.put(child) return child
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.attr and utils.addClass functions 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()) // false

TODO

  • more DOM API functionality (insertAfter,...)?
  • pretty printing?

Contributing

is welcome :-)

Maintainer

Jan Stránský

Acknowledgement

  • inspired by dominate python package
    • the context-defined adding of new elements)
    • partially this README and some examples

License

MIT