pax_global_header 0000666 0000000 0000000 00000000064 13041145525 0014512 g ustar 00root root 0000000 0000000 52 comment=6999583bd348795671c46361349fef9b227ae469
vdom-to-html-2.3.1/ 0000775 0000000 0000000 00000000000 13041145525 0014044 5 ustar 00root root 0000000 0000000 vdom-to-html-2.3.1/.gitignore 0000664 0000000 0000000 00000000062 13041145525 0016032 0 ustar 00root root 0000000 0000000 .DS_Store*
*.log
*.gz
node_modules
coverage
cache vdom-to-html-2.3.1/.travis.yml 0000664 0000000 0000000 00000000233 13041145525 0016153 0 ustar 00root root 0000000 0000000 node_js:
- "4"
- "5"
language: node_js
script: "npm run-script test-travis"
after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" vdom-to-html-2.3.1/LICENSE 0000664 0000000 0000000 00000002110 13041145525 0015043 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2014 Nathan Tran ntran013@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. vdom-to-html-2.3.1/README.md 0000664 0000000 0000000 00000004417 13041145525 0015331 0 ustar 00root root 0000000 0000000
# vdom-to-html
[![NPM version][npm-image]][npm-url]
[![Github release][github-image]][github-url]
[![Build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![Dependency Status][david-image]][david-url]
[![License][license-image]][license-url]
Turn [virtual-dom](https://github.com/Matt-Esch/virtual-dom/) nodes into HTML
## Installation
```sh
npm install --save vdom-to-html
```
## Usage
```js
var VNode = require('virtual-dom/vnode/vnode');
var toHTML = require('vdom-to-html');
toHTML(new VNode('input', { className: 'name', type: 'text' }));
// => ''
```
### Special case for Widgets
>Widgets are used to take control of the patching process, allowing the user to create stateful components, control sub-tree rendering, and hook into element removal.
[Documentation is available here](https://github.com/Matt-Esch/virtual-dom/blob/master/docs/widget.md).
Widgets are given an opportunity to provide a vdom representation through an optional `render` method. If the `render` method is not found an empty string will be used instead.
```js
var Widget = function(text) {
this.text = text;
}
Widget.prototype.type = 'Widget';
// provide a vdom representation of the widget
Widget.prototype.render = function() {
return new VNode('span', null, [new VText(this.text)]);
};
// other widget prototype methods would be implemented
toHTML(new Widget('hello'));
// => 'hello'
```
[npm-image]: https://img.shields.io/npm/v/vdom-to-html.svg?style=flat-square
[npm-url]: https://npmjs.org/package/vdom-to-html
[github-image]: http://img.shields.io/github/release/nthtran/vdom-to-html.svg?style=flat-square
[github-url]: https://github.com/nthtran/vdom-to-html/releases
[travis-image]: https://img.shields.io/travis/nthtran/vdom-to-html.svg?style=flat-square
[travis-url]: https://travis-ci.org/nthtran/vdom-to-html
[coveralls-image]: https://img.shields.io/coveralls/nthtran/vdom-to-html.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/nthtran/vdom-to-html?branch=master
[david-image]: http://img.shields.io/david/nthtran/vdom-to-html.svg?style=flat-square
[david-url]: https://david-dm.org/nthtran/vdom-to-html
[license-image]: http://img.shields.io/npm/l/vdom-to-html.svg?style=flat-square
[license-url]: LICENSE
vdom-to-html-2.3.1/create-attribute.js 0000664 0000000 0000000 00000003735 13041145525 0017656 0 ustar 00root root 0000000 0000000 var escape = require('escape-html');
var propConfig = require('./property-config');
var types = propConfig.attributeTypes;
var properties = propConfig.properties;
var attributeNames = propConfig.attributeNames;
var prefixAttribute = memoizeString(function (name) {
return escape(name) + '="';
});
module.exports = createAttribute;
/**
* Create attribute string.
*
* @param {String} name The name of the property or attribute
* @param {*} value The value
* @param {Boolean} [isAttribute] Denotes whether `name` is an attribute.
* @return {?String} Attribute string || null if not a valid property or custom attribute.
*/
function createAttribute(name, value, isAttribute) {
if (properties.hasOwnProperty(name)) {
if (shouldSkip(name, value)) return '';
name = (attributeNames[name] || name).toLowerCase();
var attrType = properties[name];
// for BOOLEAN `value` only has to be truthy
// for OVERLOADED_BOOLEAN `value` has to be === true
if ((attrType === types.BOOLEAN) ||
(attrType === types.OVERLOADED_BOOLEAN && value === true)) {
return escape(name);
}
return prefixAttribute(name) + escape(value) + '"';
} else if (isAttribute) {
if (value == null) return '';
return prefixAttribute(name) + escape(value) + '"';
}
// return null if `name` is neither a valid property nor an attribute
return null;
}
/**
* Should skip false boolean attributes.
*/
function shouldSkip(name, value) {
var attrType = properties[name];
return value == null ||
(attrType === types.BOOLEAN && !value) ||
(attrType === types.OVERLOADED_BOOLEAN && value === false);
}
/**
* Memoizes the return value of a function that accepts one string argument.
*
* @param {function} callback
* @return {function}
*/
function memoizeString(callback) {
var cache = {};
return function(string) {
if (cache.hasOwnProperty(string)) {
return cache[string];
} else {
return cache[string] = callback.call(this, string);
}
};
} vdom-to-html-2.3.1/index.js 0000664 0000000 0000000 00000005206 13041145525 0015514 0 ustar 00root root 0000000 0000000 var escape = require('escape-html');
var extend = require('xtend');
var isVNode = require('virtual-dom/vnode/is-vnode');
var isVText = require('virtual-dom/vnode/is-vtext');
var isThunk = require('virtual-dom/vnode/is-thunk');
var isWidget = require('virtual-dom/vnode/is-widget');
var softHook = require('virtual-dom/virtual-hyperscript/hooks/soft-set-hook');
var attrHook = require('virtual-dom/virtual-hyperscript/hooks/attribute-hook');
var paramCase = require('param-case');
var createAttribute = require('./create-attribute');
var voidElements = require('./void-elements');
module.exports = toHTML;
function toHTML(node, parent) {
if (!node) return '';
if (isThunk(node)) {
node = node.render();
}
if (isWidget(node) && node.render) {
node = node.render();
}
if (isVNode(node)) {
return openTag(node) + tagContent(node) + closeTag(node);
} else if (isVText(node)) {
if (parent && (parent.tagName.toLowerCase() === 'script'
|| parent.tagName.toLowerCase() === 'style'))
return String(node.text);
return escape(String(node.text));
}
return '';
}
function openTag(node) {
var props = node.properties;
var ret = '<' + node.tagName.toLowerCase();
for (var name in props) {
var value = props[name];
if (value == null) continue;
if (name == 'attributes') {
value = extend({}, value);
for (var attrProp in value) {
ret += ' ' + createAttribute(attrProp, value[attrProp], true);
}
continue;
}
if (name == 'dataset') {
value = extend({}, value);
for (var dataProp in value) {
ret += ' ' + createAttribute('data-' + paramCase(dataProp), value[dataProp], true);
}
continue;
}
if (name == 'style') {
var css = '';
value = extend({}, value);
for (var styleProp in value) {
css += paramCase(styleProp) + ': ' + value[styleProp] + '; ';
}
value = css.trim();
}
if (value instanceof softHook || value instanceof attrHook) {
ret += ' ' + createAttribute(name, value.value, true);
continue;
}
var attr = createAttribute(name, value);
if (attr) ret += ' ' + attr;
}
return ret + '>';
}
function tagContent(node) {
var innerHTML = node.properties.innerHTML;
if (innerHTML != null) return innerHTML;
else {
var ret = '';
if (node.children && node.children.length) {
for (var i = 0, l = node.children.length; i';
}
vdom-to-html-2.3.1/package.json 0000664 0000000 0000000 00000001363 13041145525 0016335 0 ustar 00root root 0000000 0000000 {
"name": "vdom-to-html",
"description": "Turn virtual-dom nodes into HTML",
"version": "2.3.1",
"author": "Nathan Tran ",
"license": "MIT",
"repository": "nthtran/vdom-to-html",
"keywords": [],
"dependencies": {
"escape-html": "^1.0.1",
"param-case": "^1.0.1",
"xtend": "^4.0.0"
},
"devDependencies": {
"istanbul": "0",
"mocha": "2",
"vdom-thunk": "^3.0.0",
"virtual-dom": "^2.0.0"
},
"peerDependencies": {
"virtual-dom": "^2.0.0"
},
"scripts": {
"test": "mocha --reporter spec",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot"
}
}
vdom-to-html-2.3.1/property-config.js 0000664 0000000 0000000 00000005756 13041145525 0017546 0 ustar 00root root 0000000 0000000 /**
* Attribute types.
*/
var types = {
BOOLEAN: 1,
OVERLOADED_BOOLEAN: 2
};
/**
* Properties.
*
* Taken from https://github.com/facebook/react/blob/847357e42e5267b04dd6e297219eaa125ab2f9f4/src/browser/ui/dom/HTMLDOMPropertyConfig.js
*
*/
var properties = {
/**
* Standard Properties
*/
accept: true,
acceptCharset: true,
accessKey: true,
action: true,
allowFullScreen: types.BOOLEAN,
allowTransparency: true,
alt: true,
async: types.BOOLEAN,
autocomplete: true,
autofocus: types.BOOLEAN,
autoplay: types.BOOLEAN,
cellPadding: true,
cellSpacing: true,
charset: true,
checked: types.BOOLEAN,
classID: true,
className: true,
cols: true,
colSpan: true,
content: true,
contentEditable: true,
contextMenu: true,
controls: types.BOOLEAN,
coords: true,
crossOrigin: true,
data: true, // For `` acts as `src`.
dateTime: true,
defer: types.BOOLEAN,
dir: true,
disabled: types.BOOLEAN,
download: types.OVERLOADED_BOOLEAN,
draggable: true,
enctype: true,
form: true,
formAction: true,
formEncType: true,
formMethod: true,
formNoValidate: types.BOOLEAN,
formTarget: true,
frameBorder: true,
headers: true,
height: true,
hidden: types.BOOLEAN,
href: true,
hreflang: true,
htmlFor: true,
httpEquiv: true,
icon: true,
id: true,
label: true,
lang: true,
list: true,
loop: types.BOOLEAN,
manifest: true,
marginHeight: true,
marginWidth: true,
max: true,
maxLength: true,
media: true,
mediaGroup: true,
method: true,
min: true,
multiple: types.BOOLEAN,
muted: types.BOOLEAN,
name: true,
noValidate: types.BOOLEAN,
open: true,
pattern: true,
placeholder: true,
poster: true,
preload: true,
radiogroup: true,
readOnly: types.BOOLEAN,
rel: true,
required: types.BOOLEAN,
role: true,
rows: true,
rowSpan: true,
sandbox: true,
scope: true,
scrolling: true,
seamless: types.BOOLEAN,
selected: types.BOOLEAN,
shape: true,
size: true,
sizes: true,
span: true,
spellcheck: true,
src: true,
srcdoc: true,
srcset: true,
start: true,
step: true,
style: true,
tabIndex: true,
target: true,
title: true,
type: true,
useMap: true,
value: true,
width: true,
wmode: true,
/**
* Non-standard Properties
*/
// autoCapitalize and autoCorrect are supported in Mobile Safari for
// keyboard hints.
autocapitalize: true,
autocorrect: true,
// itemProp, itemScope, itemType are for Microdata support. See
// http://schema.org/docs/gs.html
itemProp: true,
itemScope: types.BOOLEAN,
itemType: true,
// property is supported for OpenGraph in meta tags.
property: true
};
/**
* Properties to attributes mapping.
*
* The ones not here are simply converted to lower case.
*/
var attributeNames = {
acceptCharset: 'accept-charset',
className: 'class',
htmlFor: 'for',
httpEquiv: 'http-equiv'
};
/**
* Exports.
*/
module.exports = {
attributeTypes: types,
properties: properties,
attributeNames: attributeNames
}; vdom-to-html-2.3.1/test/ 0000775 0000000 0000000 00000000000 13041145525 0015023 5 ustar 00root root 0000000 0000000 vdom-to-html-2.3.1/test/test.js 0000664 0000000 0000000 00000017064 13041145525 0016350 0 ustar 00root root 0000000 0000000
var VNode = require('virtual-dom/vnode/vnode');
var VText = require('virtual-dom/vnode/vtext');
var h = require('virtual-dom/h');
var svg = require('virtual-dom/virtual-hyperscript/svg');
var partial = require('vdom-thunk');
var assert = require('assert');
var toHTML = require('..');
describe('toHTML()', function () {
it('should not render invalid virtual nodes', function () {
assert.equal(toHTML(null), '');
assert.equal(toHTML('hi'), '');
});
it('should render simple HTML', function () {
var node = new VNode('span');
assert.equal(toHTML(node), '');
});
it('should render inner text', function () {
var node = new VNode('span', null, [new VText('hello')]);
assert.equal(toHTML(node), 'hello');
});
it('should convert properties to attributes', function () {
var node = new VNode('form', {
className: 'login',
acceptCharset: 'ISO-8859-1',
accessKey: 'h' // prop to lower case
});
assert.equal(toHTML(node), '');
});
it('should not render end tags for void elements', function () {
var node = new VNode('input');
assert.equal(toHTML(node), '');
node = new VNode('br');
assert.equal(toHTML(node), ' ');
});
it('should not render non-standard properties', function () {
var node = new VNode('web-component', {
'ev-click': function () {},
'random-prop': 'random!',
toString: function () {}
});
assert.equal(toHTML(node), '');
});
it('should not render null properties', function () {
var node = new VNode('web-component', {
'className': null,
'id': null
});
assert.equal(toHTML(node), '');
});
it('should render CSS for style property', function () {
var node = new VNode('div', {
style: {
background: 'black',
color: 'red'
}
});
assert.equal(toHTML(node), '');
});
it('should convert style property to param-case', function () {
var node = new VNode('div', {
style: {
background: 'black',
color: 'red',
zIndex: '1'
}
});
assert.equal(toHTML(node), '');
});
it('should render style element correctly', function(){
var node = new VNode('style',{},[
new VText(".logo {background-image: url('/mylogo.png');}")
]);
assert.equal(toHTML(node),"");
});
it('should render data- attributes for dataset properties', function () {
var node = new VNode('div', {
dataset: {
foo: 'bar',
num: 42
}
});
assert.equal(toHTML(node), '');
});
it('should convert data- attributes to param-case', function () {
var node = new VNode('div', {
dataset: {
fooBar: 'baz'
}
});
assert.equal(toHTML(node), '');
});
it('should render boolean properties', function () {
var node = new VNode('input', {
autofocus: true,
disabled: false
});
assert.equal(toHTML(node), '');
});
it('should render overloaded boolean properties', function () {
var node = new VNode('a', {
href: '/images/xxx.jpg',
download: true
});
assert.equal(toHTML(node), '');
node = new VNode('a', {
href: '/images/xxx.jpg',
download: 'sfw'
});
assert.equal(toHTML(node), '');
});
it('should render any attributes', function () {
var node = new VNode('circle', {
attributes: {
cx: "60",
cy: "60",
r: "50"
}
});
assert.equal(toHTML(node), '');
});
it('should not render null attributes', function () {
var node = new VNode('circle', {
attributes: {
cx: "60",
cy: "60",
r: null
}
});
assert.equal(toHTML(node), '');
});
it('should render nested children', function () {
var node = new VNode('div', null, [
new VNode('div', { id: 'a-div' }, [
new VNode('div', null, [new VText('HI!')])
]),
new VNode('div', { className: 'just-another-div' })
]);
assert.equal(toHTML(node), '
HI!
');
});
it('should encode attribute names/values and text contents', function () {
var node = new VNode('div', {
attributes: {
'data-"hi"': '"hello"'
}
}, [new VText('sup')]);
assert.equal(toHTML(node), '
<span>sup</span>
');
});
it('should not encode script tag contents', function () {
var node = new VNode('div', null, [
new VNode('script', null, [new VText('console.log("zzz");')])
]);
assert.equal(toHTML(node), '');
});
it('should render `innerHTML`', function () {
var node = new VNode('div', {
innerHTML: 'sup'
});
assert.equal(toHTML(node), '
sup
');
});
it('should render thunks', function () {
var fn = function fn(text) {
return new VNode('span', null, [new VText(text)]);
};
var node = partial(fn, 'hello');
assert.equal(toHTML(node), 'hello');
});
it('should render widgets', function () {
var Widget = function(text) {
this.text = text;
}
Widget.prototype.type = 'Widget';
Widget.prototype.render = function() {
return new VNode('span', null, [new VText(this.text)]);
};
var node = new Widget('hello');
assert.equal(toHTML(node), 'hello');
});
it('should render tag in lowercase', function () {
var node = new VNode('SPAN', null, [new VText('hello')]);
assert.equal(toHTML(node), 'hello');
});
it('should render hyperscript', function () {
var node = h('span', null, 'test');
assert.equal(toHTML(node), 'test');
});
it('should not encode script tag contents, when using hyperscript', function () {
var node = h('div', null, [
h('script', null, 'console.log("zzz");')
]);
assert.equal(toHTML(node), '');
});
it('should not render end tags for void elements, when using hyperscript', function () {
var node = h('input');
assert.equal(toHTML(node), '');
node = h('br');
assert.equal(toHTML(node), ' ');
});
it('should preserve UTF-8 entities and escape special html characters', function () {
var node = h('span', null, '测试&\"\'<>');
assert.equal(toHTML(node), '测试&"'<>');
});
it('should render svg with attributes in default namespace', function () {
var node = svg('svg', {
'viewBox': '0 0 10 10'
});
assert.equal(toHTML(node), '');
});
it('should render svg with attributes in non-default namespace', function () {
var node = svg('use', {
'xlink:href': '/abc.jpg'
});
assert.equal(toHTML(node), '');
});
it('should render input value', function () {
var node = h('input', { type: 'submit', value: 'add' });
assert.equal(toHTML(node), '');
});
});
vdom-to-html-2.3.1/void-elements.js 0000664 0000000 0000000 00000000576 13041145525 0017165 0 ustar 00root root 0000000 0000000
/**
* Void elements.
*
* https://github.com/facebook/react/blob/v0.12.0/src/browser/ui/ReactDOMComponent.js#L99
*/
module.exports = {
'area': true,
'base': true,
'br': true,
'col': true,
'embed': true,
'hr': true,
'img': true,
'input': true,
'keygen': true,
'link': true,
'meta': true,
'param': true,
'source': true,
'track': true,
'wbr': true
};