Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
medikoo committed May 29, 2011
0 parents commit 980101a
Show file tree
Hide file tree
Showing 9 changed files with 426 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
node_modules
lib-cov
npm-debug.log
18 changes: 18 additions & 0 deletions Makefile
@@ -0,0 +1,18 @@
SHELL = bash

install:
npm install

lint:
find lib -name "*.js" -print0 | xargs -0 ./node_modules/jslint/bin/jslint.js -bitwise -es5 -newcap -node -nomen -onevar -regexp -undef -strict

lint-tests:
find test -name "*.js" -print0 | xargs -0 ./node_modules/jslint/bin/jslint.js -bitwise -es5 -newcap -node -nomen -onevar -regexp -undef -strict

test:
npm test

test-cov:
./node_modules/expresso/bin/expresso -c -q test/setup.js test/index.js

.PHONY: install lint lint-tests test test-cov
88 changes: 88 additions & 0 deletions README.md
@@ -0,0 +1,88 @@
# domjs - Client and server side dom template engine

Build dom structure easy way with plain JavaScript.
Can be used on both client and server side.
Due to its small footprint it suits small projects best.

## Instalation

When using node:

$ npm install domjs

_Instructions for browser side installation coming soon._

## Usage

What would be the easiest, most intuitive way to build html5 DOM tree with
plain JavaScript ?

var mytemplate = function () {
header(
h1('Heading'),
h2('Subheading'));

nav(
ul({ class: 'breadcrumbs' },
li(a({ href: '/' }, 'Home')),
li(a({ href: '/section/'}, 'Section')),
li(a('Subject'))));

article(
p('Lorem ipsum...'));

footer('Footer stuff');
};

This is how templates for domjs are written. To get `mytemplate` function
content turned into DOM (literally DocumentFragment):

var domjs = require('domjs/lib/html5')(document);

var mydom = domjs(mytemplate);

### Other notes

You can save references to elements and operate on them later:

var myul = ul(li('one'), li('two'), li('three'));

// ... some code ...

// add extra items to myul
myul(li('four'), li('five));

// append myul into other element
div(myul);

You can access DOM elements directly, just invoke returned function with no
arguments

(myul() instanceof DOMElement) === true

Comment type nodes:

_comment('my comment');

CDATA type nodes

_cdata('cdata text');

Text nodes in main scope:

_text('my text');

Elements with names that are reserved keywords in JavaScript language,
like 'var', should be created with preceding underscore added to its name:

_var('var content');

## Tests

When installed for node with npm (do _make install_ first)

$ make test

Tests with coverage report:

$ make test-cov
107 changes: 107 additions & 0 deletions lib/domjs.js
@@ -0,0 +1,107 @@
'use strict';

var reserved = require('es5-ext/lib/reserved').all
, isFunction = require('es5-ext/lib/Function/isFunction')
, dscope = require('es5-ext/lib/Function/dscope')
, slice = require('es5-ext/lib/List/slice').call
, toArray = require('es5-ext/lib/List/toArray').call
, bindMethods = require('es5-ext/lib/Object/bindMethods').call
, link = require('es5-ext/lib/Object/link').bind
, isPlainObject = require('es5-ext/lib/Object/isPlainObject').call

, renameReserved, nodeMap, nextInit;

renameReserved = (function (rename) {
return function (scope) {
Object.keys(scope).forEach(rename, scope);
};
}(function (key) {
if (reserved[key]) {
this['_' + key] = this[key];
delete this[key];
}
}));

nodeMap = (function (create) {
return {
_cdata: create('createCDATASection'),
_comment: create('createComment'),
_text: create('createTextNode')
};
}(function (method) {
return function (str) {
return this.df.appendChild(this.document[method](str));
};
}));

nextInit = function (document) {
this.document = document;
Object.freeze(bindMethods(this.map, this));
return this;
};

Object.freeze(module.exports = {
init: (function (setCreate) {
return function (elMap) {
this.map = {};
// attach node methods
Object.keys(nodeMap).forEach(link(this.map, nodeMap));
// attach element methods
elMap.forEach(setCreate, this);
renameReserved(this.map);

this.init = nextInit;
return this;
};
}(function (name) {
this.map[name] = this.getCreate(name);
})),
build: function (f) {
this.df = this.document.createDocumentFragment();
dscope(f, this.map);
return this.df;
},
processArguments: (function (getDOM) {
return function (args) {
args = toArray(args);
return [isPlainObject(args[0]) ? args.shift() : {}, args.map(getDOM)];
};
}(function (obj) {
return isFunction(obj) ? obj() : obj;
})),
getCreate: function (name) {
return function () {
return this.getUpdate(
this.createElement(name, this.processArguments(arguments)));
};
},
getUpdate: function (el) {
return function f () {
if (!arguments.length) {
return el;
}
this.updateElement(el, this.processArguments(arguments));
return f;
}.bind(this);
},
createElement: function (name, data) {
return this.updateElement(
this.df.appendChild(this.document.createElement(name)), data);
},
updateElement: function (el, data) {
var attrs = data[0], children = data[1];
Object.keys(attrs).forEach(function (name) {
this.setAttribute(el, name, attrs[name]);
}, this);
children.forEach(function (child) {
if (typeof child === "string") {
child = this.document.createTextNode(child);
}
el.appendChild(child);
}, this);
return el;
},
setAttribute: function (el, name, value) {
el.setAttribute(name, value);
}
});
36 changes: 36 additions & 0 deletions lib/html5.js
@@ -0,0 +1,36 @@
'use strict';

var domjs = require('./domjs')
, call = require('es5-ext/lib/Function/call')
, extend = require('es5-ext/lib/Object/extend').call

, html5js;

html5js = Object.freeze(extend(Object.create(domjs), {
setAttribute: function (parent, el, name, value) {
if (name.slice(0,2) === 'on') {
el[name] = value;
} else {
parent(this, el, name, value);
}
}
}).init(['a', 'abbr', 'address', 'area', 'article', 'aside', 'audio',
'b', 'bdi', 'bdo', 'blockquote', 'br', 'button', 'canvas', 'caption', 'cite',
'code', 'col', 'colgroup', 'command', 'datalist', 'dd', 'del', 'details',
'device','dfn', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption',
'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header',
'hgroup', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen',
'label', 'legend', 'li', 'link', 'map', 'mark', 'menu', 'meter', 'nav',
'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param',
'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section',
'select', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary',
'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time',
'tr', 'track', 'ul', 'var', 'video', 'wbr']));

module.exports = function (document) {
var builder = Object.create(html5js).init(document);

return function (f) {
return builder.build(f);
};
};
24 changes: 24 additions & 0 deletions package.json
@@ -0,0 +1,24 @@
{
"name": "domjs",
"version": "0.1.0",
"description": "Build dom structure easy way with plain js. Client and server side template engine",
"keywords": ["dom", "build", "builder", "template", "html"],
"author": "Mariusz Nowak <medikoo+domjs@medikoo.com> (http://www.medikoo.com/)",
"main": "lib/domjs",
"repository": {
"type": "git",
"url": "git://github.com/medikoo/domjs.git"
},
"bugs": {
"mail": "medikoo+domjs@medikoo.com",
"web": "https://github.com/medikoo/domjs/issues"
},
"scripts": { "test": "node test/run" },
"dependencies": { "es5-ext": "0.2.x" },
"devDependencies": {
"test": "0.1.x",
"expresso": "0.7.x",
"jslint": "0.1.x",
"jsdom": "0.2.x"
}
}

0 comments on commit 980101a

Please sign in to comment.