-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
105 lines (86 loc) · 2.4 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
const htmlTags = require('html-tag-names')
const document = require('global-undom')
const svgTags = require('svg-tag-names')
const namespaces = {
ev: 'http://www.w3.org/2001/xml-events',
xlink: 'http://www.w3.org/1999/xlink',
xml: 'http://www.w3.org/XML/1998/namespace',
xmlns: 'http://www.w3.org/2000/xmlns/'
}
const booleanAttrs = [
'defaultchecked',
'formnovalidate',
'indeterminate',
'willvalidate',
'autofocus',
'checked',
'disabled',
'readonly',
'required',
'selected'
]
const isEventHandler = (key) => key.slice(0, 2) === 'on'
const normalizeEventName = (event) =>
'on' + event.slice(2, event.length).toLowerCase()
const isPlainObject = (obj) =>
typeof obj === 'object' && obj.constructor === Object
const contains = (val, obj) => obj.indexOf(val) !== -1
const getSvgAttributeNamespace = (attr) => {
const prefix = attr.split(':', 1)[0]
return namespaces.hasOwnProperty(prefix)
? namespaces[prefix]
: null
}
const createElementTag = (tagName) => {
return contains(tagName, htmlTags)
? document.createElement(tagName)
: document.createElementNS('http://www.w3.org/2000/svg', tagName)
}
const setAttribute = (element, key, value) => {
return contains(':', key)
? element.setAttributeNS(getSvgAttributeNamespace(key), key, value)
: element.setAttribute(key, value)
}
const createElement = (tagName, ...args) => {
let attrs
const children = []
args.forEach((arg) => {
if (!arg) {
return
} else if (!attrs && isPlainObject(arg)) {
attrs = arg
} else if (Array.isArray(arg)) {
children.push(...arg)
} else {
children.push(arg)
}
})
const element = createElementTag(tagName)
for (const key in attrs) {
const value = attrs[key]
if (isEventHandler(key)) {
element[normalizeEventName(key)] = value
} else if (contains(key, booleanAttrs)) {
value !== false && element.setAttribute(key, key)
} else {
setAttribute(element, key, value)
}
}
if (children && children.length > 0) {
children.forEach((child) => {
element.appendChild(
typeof child === 'string'
? document.createTextNode(child)
: child
)
})
}
return element
}
const createTagFactory = (tag) => {
return (...args) => createElement(tag, ...args)
}
module.exports = createElement
svgTags.concat(htmlTags).forEach((tag) => {
module.exports[tag] = createTagFactory(tag)
})