You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
2.8 KiB
127 lines
2.8 KiB
import {
|
|
hasOwn,
|
|
isPlainObject
|
|
} from 'uni-shared'
|
|
|
|
const TAGS = {
|
|
a: '',
|
|
abbr: '',
|
|
b: '',
|
|
blockquote: '',
|
|
br: '',
|
|
code: '',
|
|
col: ['span', 'width'],
|
|
colgroup: ['span', 'width'],
|
|
dd: '',
|
|
del: '',
|
|
div: '',
|
|
dl: '',
|
|
dt: '',
|
|
em: '',
|
|
fieldset: '',
|
|
h1: '',
|
|
h2: '',
|
|
h3: '',
|
|
h4: '',
|
|
h5: '',
|
|
h6: '',
|
|
hr: '',
|
|
i: '',
|
|
img: ['alt', 'src', 'height', 'width'],
|
|
ins: '',
|
|
label: '',
|
|
legend: '',
|
|
li: '',
|
|
ol: ['start', 'type'],
|
|
p: '',
|
|
q: '',
|
|
span: '',
|
|
strong: '',
|
|
sub: '',
|
|
sup: '',
|
|
table: ['width'],
|
|
tbody: '',
|
|
td: ['colspan', 'rowspan', 'height', 'width'],
|
|
tfoot: '',
|
|
th: ['colspan', 'rowspan', 'height', 'width'],
|
|
thead: '',
|
|
tr: '',
|
|
ul: ''
|
|
}
|
|
const CHARS = {
|
|
amp: '&',
|
|
gt: '>',
|
|
lt: '<',
|
|
nbsp: ' ',
|
|
quot: '"',
|
|
apos: "'"
|
|
}
|
|
|
|
function decodeEntities (htmlString) {
|
|
return htmlString.replace(/&(([a-zA-Z]+)|(#x{0,1}[\da-zA-Z]+));/gi, function (match, stage) {
|
|
if (hasOwn(CHARS, stage) && CHARS[stage]) {
|
|
return CHARS[stage]
|
|
}
|
|
if (/^#[0-9]{1,4}$/.test(stage)) {
|
|
return String.fromCharCode(stage.slice(1))
|
|
}
|
|
if (/^#x[0-9a-f]{1,4}$/i.test(stage)) {
|
|
return String.fromCharCode('0' + stage.slice(1))
|
|
}
|
|
const wrap = document.createElement('div')
|
|
wrap.innerHTML = match
|
|
return wrap.innerText || wrap.textContent
|
|
})
|
|
}
|
|
|
|
export default function parseNodes (nodes, parentNode) {
|
|
nodes.forEach(function (node) {
|
|
if (!isPlainObject(node)) {
|
|
return
|
|
}
|
|
if (!hasOwn(node, 'type') || node.type === 'node') {
|
|
if (!(typeof node.name === 'string' && node.name)) {
|
|
return
|
|
}
|
|
const tagName = node.name.toLowerCase()
|
|
if (!hasOwn(TAGS, tagName)) {
|
|
return
|
|
}
|
|
const elem = document.createElement(tagName)
|
|
if (!elem) {
|
|
return
|
|
}
|
|
const attrs = node.attrs
|
|
if (isPlainObject(attrs)) {
|
|
const tagAttrs = TAGS[tagName] || []
|
|
Object.keys(attrs).forEach(function (name) {
|
|
let value = attrs[name]
|
|
switch (name) {
|
|
case 'class':
|
|
/* eslint-disable no-fallthrough */
|
|
Array.isArray(value) && (value = value.join(' '))
|
|
case 'style':
|
|
elem.setAttribute(name, value)
|
|
break
|
|
default:
|
|
if (tagAttrs.indexOf(name) !== -1) {
|
|
elem.setAttribute(name, value)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const children = node.children
|
|
if (Array.isArray(children) && children.length) {
|
|
parseNodes(node.children, elem)
|
|
}
|
|
|
|
parentNode.appendChild(elem)
|
|
} else {
|
|
if (node.type === 'text' && typeof node.text === 'string' && node.text !== '') {
|
|
parentNode.appendChild(document.createTextNode(decodeEntities(node.text)))
|
|
}
|
|
}
|
|
})
|
|
return parentNode
|
|
}
|
|
|