nodes-parser.js 3.9 KB
Newer Older
1
import { hasOwn, isPlainObject } from '@vue/shared'
D
DCloud_LXH 已提交
2
import { getRealPath } from '@dcloudio/uni-platform'
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

const TAGS = {
  a: '',
  abbr: '',
  address: '',
  article: '',
  aside: '',
  b: '',
  bdi: '',
  bdo: ['dir'],
  big: '',
  blockquote: '',
  br: '',
  caption: '',
  center: '',
  cite: '',
  code: '',
  col: ['span', 'width'],
  colgroup: ['span', 'width'],
  dd: '',
  del: '',
  div: '',
  dl: '',
  dt: '',
  em: '',
  fieldset: '',
  font: '',
  footer: '',
  h1: '',
  h2: '',
  h3: '',
  h4: '',
  h5: '',
  h6: '',
  header: '',
  hr: '',
  i: '',
  img: ['alt', 'src', 'height', 'width'],
  ins: '',
  label: '',
  legend: '',
  li: '',
  mark: '',
  nav: '',
  ol: ['start', 'type'],
  p: '',
  pre: '',
  q: '',
  rt: '',
  ruby: '',
  s: '',
  section: '',
  small: '',
  span: '',
  strong: '',
  sub: '',
  sup: '',
  table: ['width'],
  tbody: '',
  td: ['colspan', 'height', 'rowspan', 'width'],
  tfoot: '',
  th: ['colspan', 'height', 'rowspan', 'width'],
  thead: '',
  tr: ['colspan', 'height', 'rowspan', 'width'],
  tt: '',
  u: '',
  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
    }
  )
}

D
DCloud_LXH 已提交
100 101 102 103 104
function normlizeValue(tagName, name, value) {
  if (tagName === 'img' && name === 'src') return getRealPath(value)
  return value
}

105 106 107 108 109 110
export default function parseNodes(
  nodes,
  parentNode,
  scopeId,
  triggerItemClick
) {
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
  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
      }
127
      scopeId && elem.setAttribute(scopeId, '')
128 129 130 131 132 133 134 135 136 137 138 139 140 141
      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) {
D
DCloud_LXH 已提交
142
                elem.setAttribute(name, normlizeValue(tagName, name, value))
143 144 145 146 147
              }
          }
        })
      }

148 149
      processClickEvent(node, elem, triggerItemClick)

150 151
      const children = node.children
      if (Array.isArray(children) && children.length) {
152
        parseNodes(node.children, elem, scopeId, triggerItemClick)
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
      }

      parentNode.appendChild(elem)
    } else {
      if (
        node.type === 'text' &&
        typeof node.text === 'string' &&
        node.text !== ''
      ) {
        parentNode.appendChild(
          document.createTextNode(decodeEntities(node.text))
        )
      }
    }
  })
  return parentNode
}
170 171 172 173 174 175 176 177 178 179 180 181 182 183

function processClickEvent(node, elem, triggerItemClick) {
  if (['a', 'img'].includes(node.name) && triggerItemClick) {
    elem.setAttribute('onClick', 'return false;')
    elem.addEventListener(
      'click',
      (e) => {
        triggerItemClick(e, { node })
        e.stopPropagation()
      },
      true
    )
  }
}