diff --git a/dom.js b/dom.js new file mode 100644 index 0000000..2ac54d5 --- /dev/null +++ b/dom.js @@ -0,0 +1 @@ +module.exports = require('./lib/dom') diff --git a/lib/append-child.js b/lib/append-child.js index 1404b8d..534a9ad 100644 --- a/lib/append-child.js +++ b/lib/append-child.js @@ -51,7 +51,7 @@ module.exports = function appendChild (el, childs) { // We didn't have a text node yet, create one } else { - node = document.createTextNode(node) + node = el.ownerDocument.createTextNode(node) el.appendChild(node) lastChild = node } diff --git a/lib/browser.js b/lib/browser.js index 2e48914..5791aa4 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -1,113 +1 @@ -'use strict' - -var hyperx = require('hyperx') -var appendChild = require('./append-child') -var SVG_TAGS = require('./svg-tags') -var BOOL_PROPS = require('./bool-props') -// Props that need to be set directly rather than with el.setAttribute() -var DIRECT_PROPS = require('./direct-props') - -var SVGNS = 'http://www.w3.org/2000/svg' -var XLINKNS = 'http://www.w3.org/1999/xlink' - -var COMMENT_TAG = '!--' - -function nanoHtmlCreateElement (tag, props, children) { - var el - - // If an svg tag, it needs a namespace - if (SVG_TAGS.indexOf(tag) !== -1) { - props.namespace = SVGNS - } - - // If we are using a namespace - var ns = false - if (props.namespace) { - ns = props.namespace - delete props.namespace - } - - // If we are extending a builtin element - var isCustomElement = false - if (props.is) { - isCustomElement = props.is - delete props.is - } - - // Create the element - if (ns) { - if (isCustomElement) { - el = document.createElementNS(ns, tag, { is: isCustomElement }) - } else { - el = document.createElementNS(ns, tag) - } - } else if (tag === COMMENT_TAG) { - return document.createComment(props.comment) - } else if (isCustomElement) { - el = document.createElement(tag, { is: isCustomElement }) - } else { - el = document.createElement(tag) - } - - // Create the properties - for (var p in props) { - if (props.hasOwnProperty(p)) { - var key = p.toLowerCase() - var val = props[p] - // Normalize className - if (key === 'classname') { - key = 'class' - p = 'class' - } - // The for attribute gets transformed to htmlFor, but we just set as for - if (p === 'htmlFor') { - p = 'for' - } - // If a property is boolean, set itself to the key - if (BOOL_PROPS.indexOf(key) !== -1) { - if (String(val) === 'true') val = key - else if (String(val) === 'false') continue - } - // If a property prefers being set directly vs setAttribute - if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) { - el[p] = val - } else { - if (ns) { - if (p === 'xlink:href') { - el.setAttributeNS(XLINKNS, p, val) - } else if (/^xmlns($|:)/i.test(p)) { - // skip xmlns definitions - } else { - el.setAttributeNS(null, p, val) - } - } else { - el.setAttribute(p, val) - } - } - } - } - - appendChild(el, children) - return el -} - -function createFragment (nodes) { - var fragment = document.createDocumentFragment() - for (var i = 0; i < nodes.length; i++) { - if (nodes[i] == null) continue - if (Array.isArray(nodes[i])) { - fragment.appendChild(createFragment(nodes[i])) - } else { - if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i]) - fragment.appendChild(nodes[i]) - } - } - return fragment -} - -module.exports = hyperx(nanoHtmlCreateElement, { - comments: true, - createFragment: createFragment -}) -module.exports.default = module.exports -module.exports.createElement = nanoHtmlCreateElement +module.exports = require('./dom')(document) diff --git a/lib/dom.js b/lib/dom.js new file mode 100644 index 0000000..097bd05 --- /dev/null +++ b/lib/dom.js @@ -0,0 +1,116 @@ +'use strict' + +var hyperx = require('hyperx') +var appendChild = require('./append-child') +var SVG_TAGS = require('./svg-tags') +var BOOL_PROPS = require('./bool-props') +// Props that need to be set directly rather than with el.setAttribute() +var DIRECT_PROPS = require('./direct-props') + +var SVGNS = 'http://www.w3.org/2000/svg' +var XLINKNS = 'http://www.w3.org/1999/xlink' + +var COMMENT_TAG = '!--' + +module.exports = function (document) { + function nanoHtmlCreateElement (tag, props, children) { + var el + + // If an svg tag, it needs a namespace + if (SVG_TAGS.indexOf(tag) !== -1) { + props.namespace = SVGNS + } + + // If we are using a namespace + var ns = false + if (props.namespace) { + ns = props.namespace + delete props.namespace + } + + // If we are extending a builtin element + var isCustomElement = false + if (props.is) { + isCustomElement = props.is + delete props.is + } + + // Create the element + if (ns) { + if (isCustomElement) { + el = document.createElementNS(ns, tag, { is: isCustomElement }) + } else { + el = document.createElementNS(ns, tag) + } + } else if (tag === COMMENT_TAG) { + return document.createComment(props.comment) + } else if (isCustomElement) { + el = document.createElement(tag, { is: isCustomElement }) + } else { + el = document.createElement(tag) + } + + // Create the properties + for (var p in props) { + if (props.hasOwnProperty(p)) { + var key = p.toLowerCase() + var val = props[p] + // Normalize className + if (key === 'classname') { + key = 'class' + p = 'class' + } + // The for attribute gets transformed to htmlFor, but we just set as for + if (p === 'htmlFor') { + p = 'for' + } + // If a property is boolean, set itself to the key + if (BOOL_PROPS.indexOf(key) !== -1) { + if (String(val) === 'true') val = key + else if (String(val) === 'false') continue + } + // If a property prefers being set directly vs setAttribute + if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) { + el[p] = val + } else { + if (ns) { + if (p === 'xlink:href') { + el.setAttributeNS(XLINKNS, p, val) + } else if (/^xmlns($|:)/i.test(p)) { + // skip xmlns definitions + } else { + el.setAttributeNS(null, p, val) + } + } else { + el.setAttribute(p, val) + } + } + } + } + + appendChild(el, children) + return el + } + + function createFragment (nodes) { + var fragment = document.createDocumentFragment() + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] == null) continue + if (Array.isArray(nodes[i])) { + fragment.appendChild(createFragment(nodes[i])) + } else { + if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i]) + fragment.appendChild(nodes[i]) + } + } + return fragment + } + + var exports = hyperx(nanoHtmlCreateElement, { + comments: true, + createFragment: createFragment + }) + exports.default = exports + exports.createComment = nanoHtmlCreateElement + return exports +} diff --git a/package.json b/package.json index be97dfe..9b62e86 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "files": [ "index.js", "raw.js", + "dom.js", "lib", "types", "dist" @@ -16,7 +17,7 @@ "bench": "node bench/server.js && browserify bench/client.js | tape-run", "build": "mkdir -p dist/ && browserify index -s html -p bundle-collapser/plugin > dist/bundle.js && browserify index -p tinyify > dist/bundle.min.js && cat dist/bundle.min.js | gzip --best --stdout | wc -c | pretty-bytes", "prepublishOnly": "npm run build", - "test": "npm run test:standard && npm run test:node && npm run test:browser && npm run test:browser && npm run test:transform-browser && npm run test:babel-browser", + "test": "npm run test:standard && npm run test:node && npm run test:browser && npm run test:transform-browser && npm run test:babel-browser", "test:standard": "standard", "test:node": "node tests", "test:browser": "browserify tests/browser | tape-run", @@ -46,6 +47,7 @@ "bubleify": "^1.2.0", "bundle-collapser": "^1.3.0", "choo": "^6.9.0", + "jsdom": "^15.2.0", "pify": "^3.0.0", "standard": "^10.0.3", "tape": "^4.8.0", diff --git a/tests/babel/build.js b/tests/babel/build.js index 9e8a18e..8a0227b 100644 --- a/tests/babel/build.js +++ b/tests/babel/build.js @@ -3,7 +3,10 @@ const nanohtml = require('../../') browserify(require.resolve('../browser')) .transform('aliasify', { - aliases: { '../../': 'nanohtml' } + aliases: { + '../../': 'nanohtml', + './html': 'nanohtml' + } }) .transform('babelify', { plugins: [ diff --git a/tests/browser/api.js b/tests/browser/api.js index e5ee260..5552940 100644 --- a/tests/browser/api.js +++ b/tests/browser/api.js @@ -1,5 +1,9 @@ var test = require('tape') -var html = require('../../') +if (typeof window !== 'undefined') { + var html = require('../../') +} else { + html = require('./html').html +} test('creates an element', function (t) { t.plan(3) diff --git a/tests/browser/elements.js b/tests/browser/elements.js index 48115a5..408a722 100644 --- a/tests/browser/elements.js +++ b/tests/browser/elements.js @@ -1,5 +1,12 @@ var test = require('tape') -var html = require('../../') +if (typeof window !== 'undefined') { + var document = window.document + var html = require('../../') +} else { + var nano = require('./html') + document = nano.document + html = nano.html +} test('create inputs', function (t) { t.plan(7) diff --git a/tests/browser/events.js b/tests/browser/events.js index 54b6ea2..ed99a83 100644 --- a/tests/browser/events.js +++ b/tests/browser/events.js @@ -1,5 +1,12 @@ let test = require('tape') -var html = require('../../') +if (typeof window !== 'undefined') { + var document = window.document + var html = require('../../') +} else { + var nano = require('./html') + document = nano.document + html = nano.html +} /* Note: Failing tests have been commented. They include the following: diff --git a/tests/browser/html.js b/tests/browser/html.js new file mode 100644 index 0000000..d62c21b --- /dev/null +++ b/tests/browser/html.js @@ -0,0 +1,4 @@ +var doc = new (require('js' + 'dom').JSDOM)().window.document + +module.exports.document = doc +module.exports.html = require('../../dom')(doc) diff --git a/tests/browser/multiple.js b/tests/browser/multiple.js index ab0526b..39e9b02 100644 --- a/tests/browser/multiple.js +++ b/tests/browser/multiple.js @@ -1,5 +1,12 @@ var test = require('tape') -var html = require('../../') +if (typeof window !== 'undefined') { + var document = window.document + var html = require('../../') +} else { + var nano = require('./html') + document = nano.document + html = nano.html +} test('multiple elements', function (t) { var multiple = html`
  • Hamburg
  • Helsinki
  • haha
  • Berlin
    test
  • ` diff --git a/tests/browser/raw.js b/tests/browser/raw.js index e2bca72..097c3b6 100644 --- a/tests/browser/raw.js +++ b/tests/browser/raw.js @@ -2,12 +2,14 @@ var test = require('tape') var html = require('../../') var raw = require('../../raw') -test('unescape html', function (t) { - t.plan(1) +if (typeof window !== 'undefined') { + test('unescape html', function (t) { + t.plan(1) - var expected = html`Hello there`.toString() - var result = raw('Hello there').toString() + var expected = html`Hello there`.toString() + var result = raw('Hello there').toString() - t.equal(expected, result) - t.end() -}) + t.equal(expected, result) + t.end() + }) +} diff --git a/tests/index.js b/tests/index.js index dff2f97..80fd953 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1,6 +1,12 @@ -if (typeof window !== 'undefined') { +function getNodeMajor () { + return process.version.split('.')[0].slice(1) +} + +if (typeof process === 'undefined' || getNodeMajor() >= 8) { require('./browser') -} else { +} + +if (typeof window === 'undefined') { require('./server') require('./transform') require('./babel') diff --git a/tests/transform/build.js b/tests/transform/build.js index d392e58..9d5f839 100644 --- a/tests/transform/build.js +++ b/tests/transform/build.js @@ -3,7 +3,10 @@ const nanohtml = require('../../') browserify(require.resolve('../browser')) .transform('aliasify', { - aliases: { '../../': 'nanohtml' } + aliases: { + './html': 'nanohtml', + '../../': 'nanohtml' + } }) .transform(nanohtml) .bundle()