Browse files

Initial commit

  • Loading branch information...
0 parents commit 4b89e9cb3d35d23b329a90f964072f29bc2a7017 @matthewmueller committed Dec 8, 2012
Showing with 5,585 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. 0 History.md
  3. +11 −0 Makefile
  4. +127 −0 Readme.md
  5. +18 −0 component.json
  6. +53 −0 index.js
  7. +22 −0 test/index.html
  8. +112 −0 test/json-to-dom.js
  9. +227 −0 test/mocha.css
  10. +5,013 −0 test/mocha.js
2 .gitignore
@@ -0,0 +1,2 @@
+components
+build
0 History.md
No changes.
11 Makefile
@@ -0,0 +1,11 @@
+
+build: components index.js
+ @component build --dev
+
+components: component.json
+ @component install --dev
+
+clean:
+ rm -fr build components template.js
+
+.PHONY: clean
127 Readme.md
@@ -0,0 +1,127 @@
+
+# json-to-dom
+
+ Fill in the DOM with JSON.
+
+## Example
+
+```html
+<div class="note">
+ <p class="title">title</p>
+ <ul class="tags">
+ <li class="tag">
+ <span class="name">tag</span>
+ </li>
+ </ul>
+</div>
+```
+
+```js
+var json = {
+ title : 'Javascript',
+ tags : [
+ { name : 'programming' },
+ { name : 'javascript' }
+ ]
+};
+
+var render = require('json-to-dom');
+render(document.querySelector('.note'), json);
+```
+
+outputs:
+
+```html
+<div class="note">
+ <p class="title">Javascript</p>
+ <ul class="tags">
+ <li class="tag">
+ <span class="name">programming</span>
+ </li>
+ <li class="tag">
+ <span class="name">javascript</span>
+ </li>
+ </ul>
+</div>
+```
+
+## Installation
+
+ $ component install matthewmueller/json-to-dom
+
+## Motivation
+
+It's much more flexible and simpler than most templating / binding engines.
+
+## Design
+
+* JSON-to-DOM assumes the tags you are interested in are classes and that you are looking to replace `innerText`. I'm looking for ways to make this more flexible.
+
+* When json-to-dom encounters an arrays, it will repeat that block, even if you don't have any tags to match:
+
+```html
+<ul class="people">
+ <li class="person">
+ <span class="first">First Name<span>
+ <span class="last">Last Name</span>
+ </li>
+</ul>
+```
+
+```js
+var people = [
+ { first : "matt", last : "mueller" },
+ { first : "drew", last : "quinn" }
+];
+
+render(document.querySelector('.people'), people);
+```
+
+outputs:
+
+```html
+<ul class="people">
+ <li class="person">
+ <span class="first">matt<span>
+ <span class="last">mueller</span>
+ </li>
+ <li class="person">
+ <span class="first">drew<span>
+ <span class="last">quinn</span>
+ </li>
+</ul>
+```
+
+* When json-to-dom encounters an object, it will fill in the classes it finds in the block using the object's keys:
+
+```html
+<div class="email">
+ <div class="subject">subject</div>
+ <div class="from">from</div>
+ <div class="to">to</div>
+ <div class="message">message</div>
+</div>
+```
+
+```js
+var email = {
+ subject : 'You inherited $11.3 million from the death of your uncle',
+ from : 'money@nigeria.com',
+ to : 'matt@matt.com',
+ message : 'Reply with your bank credentials so we can send you the money'
+}
+
+outputs:
+
+```html
+<div class="email">
+ <div class="subject">You inherited $11.3 million from the death of your uncle</div>
+ <div class="from">money@nigeria.com</div>
+ <div class="to">matt@matt.com</div>
+ <div class="message">Reply with your bank credentials so we can send you the money</div>
+</div>
+```
+
+## License
+
+ MIT
18 component.json
@@ -0,0 +1,18 @@
+{
+ "name": "json-to-dom",
+ "repo": "matthewmueller/json-to-dom",
+ "description": "fill in the dom with json",
+ "version": "0.0.1",
+ "keywords": [],
+ "dependencies": {
+ "yields/isArray" : "*",
+ "matthewmueller/isObject" : "*"
+ },
+ "development": {
+ "component/assert" : "*"
+ },
+ "license": "MIT",
+ "scripts": [
+ "index.js"
+ ]
+}
53 index.js
@@ -0,0 +1,53 @@
+/**
+ * Module dependencies
+ */
+
+var isArray = require('isArray'),
+ isObject = require('isObject');
+
+/**
+ * Export `json-to-dom`
+ */
+
+module.exports = json_to_dom;
+
+/**
+ * json-to-dom
+ *
+ * @param {DomNode} el
+ * @param {Mixed} val
+ * @return {DomNode}
+ */
+
+function json_to_dom(el, val, key) {
+ var node = el;
+
+ if(key && typeof key == 'string')
+ node = el.querySelector('.' + key);
+ if(!node) return el;
+
+ if(isArray(val)) {
+ var out = [], clone;
+
+ for(var i = 0, len = val.length; i < len; i++) {
+ clone = node.cloneNode(true);
+ clone = json_to_dom(clone, val[i], i);
+ out.push(clone.innerHTML);
+ }
+
+ node.innerHTML = out.join('');
+
+ } else if(isObject(val)) {
+ for(var k in val) {
+ if(val.hasOwnProperty(k)) {
+ json_to_dom(node, val[k], k);
+ }
+ }
+ } else {
+ var keyNode = node.querySelector('.key');
+ if(typeof key != 'number') return node.innerText = val;
+ else if(keyNode) keyNode.innerText = val;
+ }
+
+ return el;
+}
22 test/index.html
@@ -0,0 +1,22 @@
+<html>
+ <head>
+ <title>JSON-to-DOM tests</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <link rel="stylesheet" href="mocha.css" />
+ <style>
+ h1 {
+ font-size: 14px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="mocha"></div>
+ <script src="../build/build.js"></script>
+ <script src="mocha.js"></script>
+ <script>mocha.setup('bdd')</script>
+ <script src="json-to-dom.js"></script>
+ <script>
+ mocha.run();
+ </script>
+ </body>
+</html>
112 test/json-to-dom.js
@@ -0,0 +1,112 @@
+var render = require('json-to-dom'),
+ assert = require('component-assert');
+
+var note = {
+ title : 'this is a note',
+ date : new Date(),
+ tags : [ 'javascript', 'travel' ],
+ authors : [
+ {
+ name : 'matt',
+ email : 'mattmuelle@gmail.com'
+ },
+ {
+ name : 'andrew',
+ email : 'andrew@drew.com'
+ }
+ ],
+ stats : {
+ favoriteTags : ['travel', 'blog']
+ }
+};
+
+var dom = document.createElement('div');
+dom.setAttribute('class', 'note');
+
+describe('render', function() {
+ var html;
+ beforeEach(function() {
+ html = dom.cloneNode(true);
+ });
+
+ it('should insert at classes', function() {
+ html.innerHTML = '<div class="title">title</div>';
+ html = render(html, note);
+ assert(html.querySelector('.title').innerText === 'this is a note');
+ });
+
+ it('should not overwrite other nodes', function() {
+ html.innerHTML = 'lol<div class="title">title</div>wahoo!';
+ html = render(html, note);
+ assert(html.innerHTML === 'lol<div class="title">this is a note</div>wahoo!');
+ });
+
+ it('should insert tags in an array using .key', function() {
+ html.innerHTML = '<div class="tags"><div class="key"></div></div>';
+ html = render(html, note);
+ var tags = html.querySelectorAll('.key');
+ assert(tags.length === 2);
+ assert(tags[0].innerText === 'javascript');
+ assert(tags[1].innerText === 'travel');
+ });
+
+ it('should repeat the block if .key isnt present', function() {
+ html.innerHTML = '<div class="tags"><div class="tag">tag</div></div>';
+ html = render(html, note);
+ var tags = html.querySelectorAll('.tag');
+ assert(tags.length === 2);
+ assert(tags[0].innerText === 'tag');
+ assert(tags[1].innerText === 'tag');
+ });
+
+ it('should handle objects within arrays', function() {
+ html.innerHTML = '<div class="authors"><span class="name"></span><span class="email"></span></div>';
+ html = render(html, note);
+
+ var names = html.querySelectorAll('.name');
+ assert(names.length === 2);
+ assert(names[0].innerText === 'matt');
+ assert(names[1].innerText === 'andrew');
+
+ var emails = html.querySelectorAll('.email');
+ assert(emails.length === 2);
+ assert(emails[0].innerText === 'mattmuelle@gmail.com');
+ assert(emails[1].innerText === 'andrew@drew.com');
+ });
+
+ it('array of objects places nodes in the correct order', function() {
+ html.innerHTML = '<div class="authors"><span class="name"></span><span class="email"></span></div>';
+ html = render(html, note);
+
+ var names = html.querySelectorAll('.name'),
+ emails = html.querySelectorAll('.email');
+
+ // Ensure correct order
+ assert(names[0].parentNode.className === 'authors');
+ assert(names[0].nextSibling.innerText === 'mattmuelle@gmail.com');
+ assert(emails[0].parentNode.className === 'authors');
+ assert(emails[0].nextSibling.innerText === 'andrew');
+ assert(names[1].parentNode.className === 'authors');
+ assert(names[1].nextSibling.innerText === 'andrew@drew.com');
+ assert(emails[1].parentNode.className === 'authors');
+ });
+
+ it('should handle complex json objects', function() {
+ html.innerHTML = '<div class="stats"><div class="favoriteTags"><span class="key"></span><span class="extra">hi</span></div></div>';
+ html = render(html, note);
+ var expected = '<div class="stats"><div class="favoriteTags"><span class="key">travel</span><span class="extra">hi</span><span class="key">blog</span><span class="extra">hi</span></div></div>';
+ assert(html.innerHTML === expected);
+ });
+
+ it('should handle arrays as the initial value', function() {
+ html.innerHTML = '<div class="people"><span class="first">First Name</span><span class="last">Last Name</span></div>';
+ // console.log(html.firstChild);
+ html = render(html.firstChild, [
+ { first : "matt", last : "mueller" },
+ { first : "andrew", last : "quinn" }
+ ]);
+ var expected = '<div class="people"><span class="first">matt</span><span class="last">mueller</span><span class="first">andrew</span><span class="last">quinn</span></div>';
+ assert(html.outerHTML === expected);
+ });
+});
+
227 test/mocha.css
@@ -0,0 +1,227 @@
+@charset "UTF-8";
+body {
+ font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
+ padding: 60px 50px;
+}
+
+#mocha ul, #mocha li {
+ margin: 0;
+ padding: 0;
+}
+
+#mocha ul {
+ list-style: none;
+}
+
+#mocha h1, #mocha h2 {
+ margin: 0;
+}
+
+#mocha h1 {
+ margin-top: 15px;
+ font-size: 1em;
+ font-weight: 200;
+}
+
+#mocha h1 a {
+ text-decoration: none;
+ color: inherit;
+}
+
+#mocha h1 a:hover {
+ text-decoration: underline;
+}
+
+#mocha .suite .suite h1 {
+ margin-top: 0;
+ font-size: .8em;
+}
+
+.hidden {
+ display: none;
+}
+
+#mocha h2 {
+ font-size: 12px;
+ font-weight: normal;
+ cursor: pointer;
+}
+
+#mocha .suite {
+ margin-left: 15px;
+}
+
+#mocha .test {
+ margin-left: 15px;
+}
+
+#mocha .test.pending:hover h2::after {
+ content: '(pending)';
+ font-family: arial;
+}
+
+#mocha .test.pass.medium .duration {
+ background: #C09853;
+}
+
+#mocha .test.pass.slow .duration {
+ background: #B94A48;
+}
+
+#mocha .test.pass::before {
+ content: '';
+ font-size: 12px;
+ display: block;
+ float: left;
+ margin-right: 5px;
+ color: #00d6b2;
+}
+
+#mocha .test.pass .duration {
+ font-size: 9px;
+ margin-left: 5px;
+ padding: 2px 5px;
+ color: white;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -ms-border-radius: 5px;
+ -o-border-radius: 5px;
+ border-radius: 5px;
+}
+
+#mocha .test.pass.fast .duration {
+ display: none;
+}
+
+#mocha .test.pending {
+ color: #0b97c4;
+}
+
+#mocha .test.pending::before {
+ content: '';
+ color: #0b97c4;
+}
+
+#mocha .test.fail {
+ color: #c00;
+}
+
+#mocha .test.fail pre {
+ color: black;
+}
+
+#mocha .test.fail::before {
+ content: '';
+ font-size: 12px;
+ display: block;
+ float: left;
+ margin-right: 5px;
+ color: #c00;
+}
+
+#mocha .test pre.error {
+ color: #c00;
+ max-height: 300px;
+ overflow: auto;
+}
+
+#mocha .test pre {
+ display: inline-block;
+ font: 12px/1.5 monaco, monospace;
+ margin: 5px;
+ padding: 15px;
+ border: 1px solid #eee;
+ border-bottom-color: #ddd;
+ -webkit-border-radius: 3px;
+ -webkit-box-shadow: 0 1px 3px #eee;
+ -moz-border-radius: 3px;
+ -moz-box-shadow: 0 1px 3px #eee;
+}
+
+#mocha .test h2 {
+ position: relative;
+}
+
+#mocha .test a.replay {
+ position: absolute;
+ top: 3px;
+ right: -20px;
+ text-decoration: none;
+ vertical-align: middle;
+ display: block;
+ width: 15px;
+ height: 15px;
+ line-height: 15px;
+ text-align: center;
+ background: #eee;
+ font-size: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+ -webkit-transition: opacity 200ms;
+ -moz-transition: opacity 200ms;
+ transition: opacity 200ms;
+ opacity: 0.2;
+ color: #888;
+}
+
+#mocha .test:hover a.replay {
+ opacity: 1;
+}
+
+#mocha-report.pass .test.fail {
+ display: none;
+}
+
+#mocha-report.fail .test.pass {
+ display: none;
+}
+
+#mocha-error {
+ color: #c00;
+ font-size: 1.5 em;
+ font-weight: 100;
+ letter-spacing: 1px;
+}
+
+#mocha-stats {
+ position: fixed;
+ top: 15px;
+ right: 10px;
+ font-size: 12px;
+ margin: 0;
+ color: #888;
+}
+
+#mocha-stats .progress {
+ float: right;
+ padding-top: 0;
+}
+
+#mocha-stats em {
+ color: black;
+}
+
+#mocha-stats a {
+ text-decoration: none;
+ color: inherit;
+}
+
+#mocha-stats a:hover {
+ border-bottom: 1px solid #eee;
+}
+
+#mocha-stats li {
+ display: inline-block;
+ margin: 0 5px;
+ list-style: none;
+ padding-top: 11px;
+}
+
+code .comment { color: #ddd }
+code .init { color: #2F6FAD }
+code .string { color: #5890AD }
+code .keyword { color: #8A6343 }
+code .number { color: #2F6FAD }
5,013 test/mocha.js
5,013 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.

0 comments on commit 4b89e9c

Please sign in to comment.