Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dom.js to allow custom document object #165

Merged
merged 6 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./lib/dom')
2 changes: 1 addition & 1 deletion lib/append-child.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
114 changes: 1 addition & 113 deletions lib/browser.js
Original file line number Diff line number Diff line change
@@ -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)
116 changes: 116 additions & 0 deletions lib/dom.js
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"files": [
"index.js",
"raw.js",
"dom.js",
"lib",
"types",
"dist"
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion tests/browser/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var test = require('tape')
var html = require('../../')
var { html } = require('./html')

test('creates an element', function (t) {
t.plan(3)
Expand Down
2 changes: 1 addition & 1 deletion tests/browser/elements.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var test = require('tape')
var html = require('../../')
var { document, html } = require('./html')

test('create inputs', function (t) {
t.plan(7)
Expand Down
2 changes: 1 addition & 1 deletion tests/browser/events.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
let test = require('tape')
var html = require('../../')
var { document, html } = require('./html')

/* Note:
Failing tests have been commented. They include the following:
Expand Down
8 changes: 8 additions & 0 deletions tests/browser/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var doc = typeof window !== 'undefined'
? document
: new (require('jsdom').JSDOM)().window.document
goto-bus-stop marked this conversation as resolved.
Show resolved Hide resolved

module.exports.document = doc
module.exports.html = typeof window !== 'undefined'
? require('../../')
: require('../../dom')(doc)
2 changes: 1 addition & 1 deletion tests/browser/multiple.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var test = require('tape')
var html = require('../../')
var { document, html } = require('./html')

test('multiple elements', function (t) {
var multiple = html`<li>Hamburg</li><li>Helsinki</li>haha<li>Berlin<div>test</div></li>`
Expand Down
16 changes: 9 additions & 7 deletions tests/browser/raw.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`<span>Hello there</span>`.toString()
var result = raw('<span>Hello&nbsp;there</span>').toString()
var expected = html`<span>Hello there</span>`.toString()
var result = raw('<span>Hello&nbsp;there</span>').toString()

t.equal(expected, result)
t.end()
})
t.equal(expected, result)
t.end()
})
}
5 changes: 2 additions & 3 deletions tests/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
if (typeof window !== 'undefined') {
require('./browser')
} else {
require('./browser')
goto-bus-stop marked this conversation as resolved.
Show resolved Hide resolved
if (typeof window === 'undefined') {
require('./server')
require('./transform')
require('./babel')
Expand Down