├── .gitignore ├── .npmignore ├── README.md ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | test.js 3 | example 4 | examples 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## html-patcher 2 | 3 | Virtual DOM Diff & Patch with HTML Templates. Based on [the virtual-dom on NPM](http://npmjs.org/virtual-dom) 4 | 5 | ## Install 6 | 7 | ```bash 8 | $ npm install html-patch 9 | ``` 10 | 11 | ## Usage 12 | 13 | A simple app to show epoch time every second: 14 | 15 | ```js 16 | var patcher = require('html-patcher') 17 | 18 | var patch = patcher(document.body, render()); 19 | 20 | setInterval(function () { 21 | patch(render()) 22 | }, 1000); 23 | 24 | function render () { 25 | return '

' + Date.now() + '

'; 26 | } 27 | ``` 28 | 29 | See `test.js` for more info. 30 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var createRootNode = require('virtual-dom/create-element'); 2 | var diff = require('virtual-dom/diff'); 3 | var applyPatches = require('virtual-dom/patch'); 4 | var virtualHTML = require("virtual-html"); 5 | 6 | module.exports = newPatch; 7 | 8 | function newPatch (parentNode, html) { 9 | var tree; 10 | var rootNode; 11 | 12 | patch(html); 13 | 14 | return patch; 15 | 16 | function patch (newHtml) { 17 | var vdom = virtualHTML(newHtml || html); 18 | 19 | if (!tree) { 20 | tree = vdom; 21 | rootNode = createRootNode(vdom); 22 | parentNode.appendChild(rootNode); 23 | return patch; 24 | } 25 | 26 | var patches = diff(tree, vdom); 27 | applyPatches(rootNode, patches); 28 | tree = vdom; 29 | 30 | return patch; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html-patcher", 3 | "version": "1.0.0", 4 | "description": "Virtual DOM Diff & Patch with HTML Templates", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test" 8 | }, 9 | "keywords": [ 10 | "html", 11 | "virtual dom", 12 | "domdiff", 13 | "dom diffing", 14 | "patch", 15 | "virtualdom" 16 | ], 17 | "repository": { 18 | "url": "git@github.com:azer/html-patcher.git", 19 | "type": "git" 20 | }, 21 | "author": "azer", 22 | "license": "BSD", 23 | "dependencies": { 24 | "virtual-dom": "^2.0.1", 25 | "virtual-html": "^1.2.0" 26 | }, 27 | "devDependencies": { 28 | "prova": "^1.15.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var test = require("prova"); 2 | var patcher = require('./'); 3 | 4 | var fruits = ['apple', 'grape', 'orange']; 5 | var moreFruits = ['apple', 'grape', 'cherry', 'melon', 'orange']; 6 | 7 | test('Basic DOM diffing and patching', function (t) { 8 | t.plan(3); 9 | clear(); 10 | 11 | var patch = patcher(document.body, basic('hi')); 12 | t.equal(document.body.innerHTML.trim(), '

hi

'); 13 | 14 | var root = document.querySelector('basic'); 15 | 16 | patch(basic('yo')); 17 | t.equal(document.body.innerHTML.trim(), '

yo

'); 18 | t.equal(document.querySelector('basic'), document.querySelector('basic')); 19 | }); 20 | 21 | test('Lists', function (t) { 22 | t.plan(9); 23 | clear(); 24 | 25 | var patch = patcher(document.body, list(fruits)); 26 | t.equal(document.body.innerHTML.trim(), list(fruits)); 27 | 28 | Array.prototype.forEach.call(document.querySelectorAll('li'), function (el) { 29 | el.style.color = 'purple'; 30 | t.equal(el.style.color, 'purple'); 31 | }); 32 | 33 | patch(list(moreFruits)); 34 | 35 | Array.prototype.forEach.call(document.querySelectorAll('li'), function (el, ind) { 36 | if (ind > 2) { // cherry, melon or orange 37 | t.notOk(el.style.color); 38 | return; 39 | }; 40 | 41 | t.equal(el.style.color, 'purple'); 42 | }); 43 | }); 44 | 45 | test('Countback example', function (t) { 46 | t.plan(2); 47 | 48 | clear(); 49 | 50 | var n = 3; 51 | var patch = patcher(document.body, render); 52 | var timer = setInterval(patch, 1000); 53 | 54 | function render () { 55 | if (n == 1) { 56 | clearInterval(timer); 57 | } 58 | 59 | if (n < 3) { 60 | t.equal(document.body.innerHTML.trim(), countback(n + 1)); 61 | } 62 | 63 | return countback(n--); 64 | } 65 | }); 66 | 67 | function basic (content) { 68 | return '

' + content + '

'; 69 | } 70 | 71 | function list (content) { 72 | var html = ''; 79 | 80 | return html; 81 | } 82 | 83 | function countback (n) { 84 | var size = 48 - (n * 5); 85 | var colors = ['red', 'blue', 'green']; 86 | return '

' + n + '

'; 87 | } 88 | 89 | function clear () { 90 | document.body.innerHTML = ''; 91 | } 92 | --------------------------------------------------------------------------------