Skip to content

Commit bfb3aef

Browse files
saschanazgoto-bus-stop
authored andcommitted
Add dom.js to allow custom document object (#165)
* Add dom.js to allow custom document object * fix test by keeping require() * node version check * fix standardjs errors * unconditional html.js * Also detect ./html in the babel plugin
1 parent a79e024 commit bfb3aef

File tree

14 files changed

+180
-130
lines changed

14 files changed

+180
-130
lines changed

dom.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./lib/dom')

lib/append-child.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ module.exports = function appendChild (el, childs) {
5151

5252
// We didn't have a text node yet, create one
5353
} else {
54-
node = document.createTextNode(node)
54+
node = el.ownerDocument.createTextNode(node)
5555
el.appendChild(node)
5656
lastChild = node
5757
}

lib/browser.js

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1 @@
1-
'use strict'
2-
3-
var hyperx = require('hyperx')
4-
var appendChild = require('./append-child')
5-
var SVG_TAGS = require('./svg-tags')
6-
var BOOL_PROPS = require('./bool-props')
7-
// Props that need to be set directly rather than with el.setAttribute()
8-
var DIRECT_PROPS = require('./direct-props')
9-
10-
var SVGNS = 'http://www.w3.org/2000/svg'
11-
var XLINKNS = 'http://www.w3.org/1999/xlink'
12-
13-
var COMMENT_TAG = '!--'
14-
15-
function nanoHtmlCreateElement (tag, props, children) {
16-
var el
17-
18-
// If an svg tag, it needs a namespace
19-
if (SVG_TAGS.indexOf(tag) !== -1) {
20-
props.namespace = SVGNS
21-
}
22-
23-
// If we are using a namespace
24-
var ns = false
25-
if (props.namespace) {
26-
ns = props.namespace
27-
delete props.namespace
28-
}
29-
30-
// If we are extending a builtin element
31-
var isCustomElement = false
32-
if (props.is) {
33-
isCustomElement = props.is
34-
delete props.is
35-
}
36-
37-
// Create the element
38-
if (ns) {
39-
if (isCustomElement) {
40-
el = document.createElementNS(ns, tag, { is: isCustomElement })
41-
} else {
42-
el = document.createElementNS(ns, tag)
43-
}
44-
} else if (tag === COMMENT_TAG) {
45-
return document.createComment(props.comment)
46-
} else if (isCustomElement) {
47-
el = document.createElement(tag, { is: isCustomElement })
48-
} else {
49-
el = document.createElement(tag)
50-
}
51-
52-
// Create the properties
53-
for (var p in props) {
54-
if (props.hasOwnProperty(p)) {
55-
var key = p.toLowerCase()
56-
var val = props[p]
57-
// Normalize className
58-
if (key === 'classname') {
59-
key = 'class'
60-
p = 'class'
61-
}
62-
// The for attribute gets transformed to htmlFor, but we just set as for
63-
if (p === 'htmlFor') {
64-
p = 'for'
65-
}
66-
// If a property is boolean, set itself to the key
67-
if (BOOL_PROPS.indexOf(key) !== -1) {
68-
if (String(val) === 'true') val = key
69-
else if (String(val) === 'false') continue
70-
}
71-
// If a property prefers being set directly vs setAttribute
72-
if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) {
73-
el[p] = val
74-
} else {
75-
if (ns) {
76-
if (p === 'xlink:href') {
77-
el.setAttributeNS(XLINKNS, p, val)
78-
} else if (/^xmlns($|:)/i.test(p)) {
79-
// skip xmlns definitions
80-
} else {
81-
el.setAttributeNS(null, p, val)
82-
}
83-
} else {
84-
el.setAttribute(p, val)
85-
}
86-
}
87-
}
88-
}
89-
90-
appendChild(el, children)
91-
return el
92-
}
93-
94-
function createFragment (nodes) {
95-
var fragment = document.createDocumentFragment()
96-
for (var i = 0; i < nodes.length; i++) {
97-
if (nodes[i] == null) continue
98-
if (Array.isArray(nodes[i])) {
99-
fragment.appendChild(createFragment(nodes[i]))
100-
} else {
101-
if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i])
102-
fragment.appendChild(nodes[i])
103-
}
104-
}
105-
return fragment
106-
}
107-
108-
module.exports = hyperx(nanoHtmlCreateElement, {
109-
comments: true,
110-
createFragment: createFragment
111-
})
112-
module.exports.default = module.exports
113-
module.exports.createElement = nanoHtmlCreateElement
1+
module.exports = require('./dom')(document)

lib/dom.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
'use strict'
2+
3+
var hyperx = require('hyperx')
4+
var appendChild = require('./append-child')
5+
var SVG_TAGS = require('./svg-tags')
6+
var BOOL_PROPS = require('./bool-props')
7+
// Props that need to be set directly rather than with el.setAttribute()
8+
var DIRECT_PROPS = require('./direct-props')
9+
10+
var SVGNS = 'http://www.w3.org/2000/svg'
11+
var XLINKNS = 'http://www.w3.org/1999/xlink'
12+
13+
var COMMENT_TAG = '!--'
14+
15+
module.exports = function (document) {
16+
function nanoHtmlCreateElement (tag, props, children) {
17+
var el
18+
19+
// If an svg tag, it needs a namespace
20+
if (SVG_TAGS.indexOf(tag) !== -1) {
21+
props.namespace = SVGNS
22+
}
23+
24+
// If we are using a namespace
25+
var ns = false
26+
if (props.namespace) {
27+
ns = props.namespace
28+
delete props.namespace
29+
}
30+
31+
// If we are extending a builtin element
32+
var isCustomElement = false
33+
if (props.is) {
34+
isCustomElement = props.is
35+
delete props.is
36+
}
37+
38+
// Create the element
39+
if (ns) {
40+
if (isCustomElement) {
41+
el = document.createElementNS(ns, tag, { is: isCustomElement })
42+
} else {
43+
el = document.createElementNS(ns, tag)
44+
}
45+
} else if (tag === COMMENT_TAG) {
46+
return document.createComment(props.comment)
47+
} else if (isCustomElement) {
48+
el = document.createElement(tag, { is: isCustomElement })
49+
} else {
50+
el = document.createElement(tag)
51+
}
52+
53+
// Create the properties
54+
for (var p in props) {
55+
if (props.hasOwnProperty(p)) {
56+
var key = p.toLowerCase()
57+
var val = props[p]
58+
// Normalize className
59+
if (key === 'classname') {
60+
key = 'class'
61+
p = 'class'
62+
}
63+
// The for attribute gets transformed to htmlFor, but we just set as for
64+
if (p === 'htmlFor') {
65+
p = 'for'
66+
}
67+
// If a property is boolean, set itself to the key
68+
if (BOOL_PROPS.indexOf(key) !== -1) {
69+
if (String(val) === 'true') val = key
70+
else if (String(val) === 'false') continue
71+
}
72+
// If a property prefers being set directly vs setAttribute
73+
if (key.slice(0, 2) === 'on' || DIRECT_PROPS.indexOf(key) !== -1) {
74+
el[p] = val
75+
} else {
76+
if (ns) {
77+
if (p === 'xlink:href') {
78+
el.setAttributeNS(XLINKNS, p, val)
79+
} else if (/^xmlns($|:)/i.test(p)) {
80+
// skip xmlns definitions
81+
} else {
82+
el.setAttributeNS(null, p, val)
83+
}
84+
} else {
85+
el.setAttribute(p, val)
86+
}
87+
}
88+
}
89+
}
90+
91+
appendChild(el, children)
92+
return el
93+
}
94+
95+
function createFragment (nodes) {
96+
var fragment = document.createDocumentFragment()
97+
for (var i = 0; i < nodes.length; i++) {
98+
if (nodes[i] == null) continue
99+
if (Array.isArray(nodes[i])) {
100+
fragment.appendChild(createFragment(nodes[i]))
101+
} else {
102+
if (typeof nodes[i] === 'string') nodes[i] = document.createTextNode(nodes[i])
103+
fragment.appendChild(nodes[i])
104+
}
105+
}
106+
return fragment
107+
}
108+
109+
var exports = hyperx(nanoHtmlCreateElement, {
110+
comments: true,
111+
createFragment: createFragment
112+
})
113+
exports.default = exports
114+
exports.createComment = nanoHtmlCreateElement
115+
return exports
116+
}

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"files": [
88
"index.js",
99
"raw.js",
10+
"dom.js",
1011
"lib",
1112
"types",
1213
"dist"
@@ -16,7 +17,7 @@
1617
"bench": "node bench/server.js && browserify bench/client.js | tape-run",
1718
"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",
1819
"prepublishOnly": "npm run build",
19-
"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",
20+
"test": "npm run test:standard && npm run test:node && npm run test:browser && npm run test:transform-browser && npm run test:babel-browser",
2021
"test:standard": "standard",
2122
"test:node": "node tests",
2223
"test:browser": "browserify tests/browser | tape-run",
@@ -46,6 +47,7 @@
4647
"bubleify": "^1.2.0",
4748
"bundle-collapser": "^1.3.0",
4849
"choo": "^6.9.0",
50+
"jsdom": "^15.2.0",
4951
"pify": "^3.0.0",
5052
"standard": "^10.0.3",
5153
"tape": "^4.8.0",

tests/babel/build.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ const nanohtml = require('../../')
33

44
browserify(require.resolve('../browser'))
55
.transform('aliasify', {
6-
aliases: { '../../': 'nanohtml' }
6+
aliases: {
7+
'../../': 'nanohtml',
8+
'./html': 'nanohtml'
9+
}
710
})
811
.transform('babelify', {
912
plugins: [

tests/browser/api.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
var test = require('tape')
2-
var html = require('../../')
2+
if (typeof window !== 'undefined') {
3+
var html = require('../../')
4+
} else {
5+
html = require('./html').html
6+
}
37

48
test('creates an element', function (t) {
59
t.plan(3)

tests/browser/elements.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
var test = require('tape')
2-
var html = require('../../')
2+
if (typeof window !== 'undefined') {
3+
var document = window.document
4+
var html = require('../../')
5+
} else {
6+
var nano = require('./html')
7+
document = nano.document
8+
html = nano.html
9+
}
310

411
test('create inputs', function (t) {
512
t.plan(7)

tests/browser/events.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
let test = require('tape')
2-
var html = require('../../')
2+
if (typeof window !== 'undefined') {
3+
var document = window.document
4+
var html = require('../../')
5+
} else {
6+
var nano = require('./html')
7+
document = nano.document
8+
html = nano.html
9+
}
310

411
/* Note:
512
Failing tests have been commented. They include the following:

tests/browser/html.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var doc = new (require('js' + 'dom').JSDOM)().window.document
2+
3+
module.exports.document = doc
4+
module.exports.html = require('../../dom')(doc)

0 commit comments

Comments
 (0)