PageSourceSearch

https://www.glenengineering.com/src/prune-hidden-html.js

js glenengineering.com collected 2026-10-04 04:59:05 UTC 4,044 bytes, 129 lines download raw bytes

1const TAG_TYPES = {
2    self_close_tag: 'self_close_tag', //自闭合标签
3    open_tag: 'open_tag', // 起始标签
4    close_tag: 'close_tag' //闭合标签
5}
6
7const TAG_CLASS = {
8    tag: 'tag', //标签类型
9    text: 'text' //文本类型
10}
11
12/**
13 * 创建标签容器对象
14 * @param {string} str
15 * @returns {{key, content, tagClass, parentKey, tagType?, tagName?, pairKey?}}
16 */
17function createTag(str) {
18    const tag = {}
19    if (/^[<](meta|link|br|hr|img|input\b.*\/?)|([a-z0-9_-]+.*?\/)[>]$/is.test(str)) {
20        tag.tagClass = TAG_CLASS.tag
21        tag.tagType = TAG_TYPES.self_close_tag
22        tag.tagName = (/(?<=<)[a-z0-9_-]+\b/is.exec(str))?.[0].toUpperCase() || ''
23    } else if (/^<\/[a-z0-9_-]+[^>]*>$/is.test(str)) {
24        tag.tagClass = TAG_CLASS.tag
25        tag.tagType = TAG_TYPES.close_tag
26        tag.tagName = (/(?<=<\/)[a-z0-9_-]+\b/is.exec(str))?.[0].toUpperCase() || ''
27    } else if (/^<\w+.*>$/is.test(str)) {
28        tag.tagClass = TAG_CLASS.tag
29        tag.tagType = TAG_TYPES.open_tag
30        tag.tagName = (/(?<=<)[a-z0-9_-]+\b/is.exec(str))?.[0].toUpperCase() || ''
31    } else {
32        tag.tagClass = TAG_CLASS.text
33    }
34    tag.content = str
35    return tag
36}
37
38/**
39 * 标签配对
40 */
41function matchTagPairs(tags) {
42    const stack = []
43    for (let i = 0; i < tags.length; i++) {
44        let tag = tags[i]
45        const len = stack.length
46        let parent = null
47        if (tag.tagType === TAG_TYPES.close_tag) {
48            parent = stack[len - 2]
49        } else {
50            parent = stack[len - 1]
51        }
52        tag.parentKey = parent ? parent.key : ''
53        if (tag.tagClass !== TAG_CLASS.tag) {
54            continue
55        }
56        if (tag.tagType === TAG_TYPES.open_tag) {
57            stack.push(tag)
58        } else if (tag.tagType === TAG_TYPES.close_tag) {
59            const openTag = stack.pop()
60            if (openTag) {
61                // todo 标签数量不匹配 & 标签属性中嵌套标签 exp: <input alt="<p>something</p>">
62                openTag.pairKey = tag.key
63                tag.pairKey = openTag.key
64            }
65        } else if (tag.tagType === TAG_TYPES.self_close_tag) {
66            tag.pairKey = tag.key
67        }
68    }
69}
70
71/**
72 * 匹配三端隐藏的标签
73 */
74function matchHides(tag, hides = ['hide-pc', 'hide-pad', 'hide-phone']) {
75    // ^(?=.*hide-pc)(?=.*hide-pad)(?=.*hide-phone).*$
76    const reg = new RegExp('^' + hides.map(hide => `(?=.*${hide})`).join('') + '.*$', 'i')
77    return tag.tagClass === TAG_CLASS.tag
78        && (tag.tagType === TAG_TYPES.open_tag || tag.tagType === TAG_TYPES.self_close_tag)
79        && reg.test(tag.content)
80}
81
82/**
83 * 清理三端隐藏HTML
84 */
85function doPruneHiddenHtml(tpl, hides = ['hide-pc', 'hide-pad', 'hide-phone']) {
86    let arr = tpl.replace(/\s*\n\s*/gis, ' ')
87        .replace(/<\w+:\w+>[^<>]*?<\/w+:\w+>/gis, '') // 清理非html标签:word文档引入的异常标签<o:p></o:p>
88        .replace(/^\s*|\s*$/gis, '')
89        .split(/(?<=[<][a-z\/_-][^>]*[>])[\b]?|[\b]?(?=[<][a-z\/_-][^>]*[>])/gis)
90        .filter(s => !/^\s*$/gis.test(s))
91    let tags = arr.map((str, idx) => {
92        let tag = createTag(str)
93        tag.key = (`${tag.tagClass}:${idx}`).toLowerCase()
94        return tag
95    })
96
97    matchTagPairs(tags)
98
99    if (hides.length) {
100        let hideIndex = tags.findIndex(tag => matchHides(tag, hides))
101        while (hideIndex > -1) {
102            let hide = tags[hideIndex]
103            let closeIndex = tags.findIndex(tag => tag.key === hide.pairKey)
104            tags.splice(hideIndex, closeIndex - hideIndex + 1)
105            hideIndex = tags.findIndex(tag => matchHides(tag))
106        }
107    }
108
109    return tags.reduce((prev, node) => `${prev}${node.content}`, '')
110}
111
112/**
113 * wrap catch exception
114 * @param tpl
115 * @param hides
116 * @returns {*}
117 */
118function pruneHiddenHtml(tpl, hides = ['hide-pc', 'hide-pad', 'hide-phone']) {
119    try {
120        return doPruneHiddenHtml(tpl, hides)
121    } catch (e) {
122        console.error(e)
123        return tpl
124    }
125}
126
127export {
128    pruneHiddenHtml
129}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.