pax_global_header00006660000000000000000000000064130411455250014512gustar00rootroot0000000000000052 comment=6999583bd348795671c46361349fef9b227ae469 vdom-to-html-2.3.1/000077500000000000000000000000001304114552500140445ustar00rootroot00000000000000vdom-to-html-2.3.1/.gitignore000066400000000000000000000000621304114552500160320ustar00rootroot00000000000000.DS_Store* *.log *.gz node_modules coverage cachevdom-to-html-2.3.1/.travis.yml000066400000000000000000000002331304114552500161530ustar00rootroot00000000000000node_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/LICENSE000066400000000000000000000021101304114552500150430ustar00rootroot00000000000000The 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.md000066400000000000000000000044171304114552500153310ustar00rootroot00000000000000 # 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.js000066400000000000000000000037351304114552500176560ustar00rootroot00000000000000var 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.js000066400000000000000000000052061304114552500155140ustar00rootroot00000000000000var 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.json000066400000000000000000000013631304114552500163350ustar00rootroot00000000000000{ "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.js000066400000000000000000000057561304114552500175460ustar00rootroot00000000000000/** * 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/000077500000000000000000000000001304114552500150235ustar00rootroot00000000000000vdom-to-html-2.3.1/test/test.js000066400000000000000000000170641304114552500163500ustar00rootroot00000000000000 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.js000066400000000000000000000005761304114552500171650ustar00rootroot00000000000000 /** * 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 };