/** Minimal CSS: tag / .class / #id / * plus a few properties. */ var BARE_SUMMON_UA_CSS = [ { sel: 'a', decl: { color: 'blue', 'text-decoration': 'underline' } }, { sel: 'b', decl: { 'font-weight': 'bold' } }, { sel: 'strong', decl: { 'font-weight': 'bold' } }, { sel: 'em', decl: { 'font-style': 'italic' } }, { sel: 'i', decl: { 'font-style': 'italic' } }, { sel: 'h1', decl: { 'font-weight': 'bold', 'margin-top': '1em', 'margin-bottom': '0.5em' } }, { sel: 'h2', decl: { 'font-weight': 'bold', 'margin-top': '1em' } }, { sel: 'h3', decl: { 'font-weight': 'bold' } }, { sel: 'pre', decl: { 'white-space': 'pre', 'font-family': 'monospace' } }, { sel: 'code', decl: { 'font-family': 'monospace' } }, { sel: 'script', decl: { display: 'none' } }, { sel: 'style', decl: { display: 'none' } }, { sel: 'head', decl: { display: 'none' } }, { sel: 'title', decl: { display: 'none' } }, { sel: 'meta', decl: { display: 'none' } }, { sel: 'link', decl: { display: 'none' } }, { sel: 'noscript', decl: { display: 'none' } } ] function bareSummonParseDeclarations(block) { var decl = {} var parts = String(block || '').split(';') for (var i = 0; i < parts.length; i++) { var p = parts[i] var c = p.indexOf(':') if (c < 0) continue var k = p.slice(0, c).trim().toLowerCase() var v = p.slice(c + 1).trim() if (k) decl[k] = v } return decl } function bareSummonStripAtRules(css) { var s = String(css || '') var out = '' var i = 0 while (i < s.length) { if (s.charAt(i) === '@') { var brace = s.indexOf('{', i) if (brace < 0) break var depth = 0 var j = brace for (; j < s.length; j++) { if (s.charAt(j) === '{') depth++ else if (s.charAt(j) === '}') { depth-- if (depth === 0) { j++ break } } } i = j continue } out += s.charAt(i) i++ } return out } function bareSummonParseStylesheet(css, maxRules) { var s = bareSummonStripAtRules( String(css || '').replace(/\/\*[\s\S]*?\*\//g, '') ) var rules = [] var cap = maxRules > 0 ? maxRules : 800 var re = /([^{}]+)\{([^{}]*)\}/g var m while ((m = re.exec(s)) && rules.length < cap) { var sels = m[1].split(',') var decl = bareSummonParseDeclarations(m[2]) for (var i = 0; i < sels.length; i++) { var sel = sels[i].trim() if (sel) rules.push({ sel: sel, decl: decl }) } } return rules } function bareSummonHasClass(node, name) { var cls = (node.attrs && node.attrs.class ? node.attrs.class : '').split( /\s+/ ) return cls.indexOf(name) >= 0 } function bareSummonMatchCompound(sel, node) { if (!node || node.type !== 'element') return false sel = String(sel || '').trim() if (!sel || sel === '*') return true if (sel.charAt(0) === ':') return false var i = 0 var tag = '' if (/^[a-zA-Z]/.test(sel)) { while (i < sel.length && /[a-zA-Z0-9_-]/.test(sel.charAt(i))) i++ tag = sel.slice(0, i).toLowerCase() if (node.name !== tag) return false } while (i < sel.length) { var ch = sel.charAt(i) if (ch === '.') { i++ var c0 = i while (i < sel.length && /[a-zA-Z0-9_-]/.test(sel.charAt(i))) i++ if (!bareSummonHasClass(node, sel.slice(c0, i))) return false } else if (ch === '#') { i++ var i0 = i while (i < sel.length && /[a-zA-Z0-9_-]/.test(sel.charAt(i))) i++ if ((node.attrs.id || '') !== sel.slice(i0, i)) return false } else if (ch === '[') { var end = sel.indexOf(']', i) if (end < 0) return false var inside = sel.slice(i + 1, end) var eq = inside.indexOf('=') var an = (eq < 0 ? inside : inside.slice(0, eq)).trim().toLowerCase() var av = eq < 0 ? null : inside .slice(eq + 1) .trim() .replace(/^["']|["']$/g, '') var have = node.attrs ? node.attrs[an] : undefined if (eq < 0) { if (have == null) return false } else if (String(have) !== av) return false i = end + 1 } else if (ch === ':') { i++ while (i < sel.length && /[a-zA-Z0-9_-]/.test(sel.charAt(i))) i++ if (sel.charAt(i) === '(') { var depth = 1 i++ while (i < sel.length && depth) { if (sel.charAt(i) === '(') depth++ else if (sel.charAt(i) === ')') depth-- i++ } } } else return false } return true } function bareSummonSplitCombinators(sel) { var parts = [] var cur = '' var comb = ' ' var i var s = String(sel || '') .replace(/\s+/g, ' ') .trim() for (i = 0; i < s.length; i++) { var ch = s.charAt(i) if (ch === '>' || ch === '+' || ch === '~') { if (cur.trim()) parts.push({ sel: cur.trim(), comb: comb }) cur = '' comb = ch if (s.charAt(i + 1) === ' ') i++ } else if (ch === ' ') { if (cur.trim()) { parts.push({ sel: cur.trim(), comb: comb }) cur = '' comb = ' ' } } else cur += ch } if (cur.trim()) parts.push({ sel: cur.trim(), comb: comb }) return parts } function bareSummonPrevElement(node) { if (!node || !node.parent) return null var kids = node.parent.children || [] var i var prev = null for (i = 0; i < kids.length; i++) { if (kids[i] === node) return prev if (kids[i] && kids[i].type === 'element') prev = kids[i] } return prev } function bareSummonMatches(sel, node) { if (!node || node.type !== 'element') return false sel = String(sel || '').trim() if (!sel) return false var groups = sel.split(',') var g for (g = 0; g < groups.length; g++) { if (bareSummonMatchesOne(groups[g].trim(), node)) return true } return false } function bareSummonMatchesOne(sel, node) { var parts = bareSummonSplitCombinators(sel) if (!parts.length) return false var cur = node var p = parts.length - 1 if (!bareSummonMatchCompound(parts[p].sel, cur)) return false p-- while (p >= 0 && cur) { var comb = parts[p + 1] ? parts[p + 1].comb : ' ' if (comb === '>') { cur = cur.parent if (!cur || !bareSummonMatchCompound(parts[p].sel, cur)) return false p-- } else if (comb === '+') { cur = bareSummonPrevElement(cur) if (!cur || !bareSummonMatchCompound(parts[p].sel, cur)) return false p-- } else if (comb === '~') { var ok = false var sib = bareSummonPrevElement(cur) while (sib) { if (bareSummonMatchCompound(parts[p].sel, sib)) { ok = true cur = sib break } sib = bareSummonPrevElement(sib) } if (!ok) return false p-- } else { var hit = false var anc = cur.parent while (anc) { if (bareSummonMatchCompound(parts[p].sel, anc)) { hit = true cur = anc break } anc = anc.parent } if (!hit) return false p-- } } return p < 0 } function bareSummonMatchSimple(sel, node) { return bareSummonMatches(sel, node) } function bareSummonQueryAll(root, sel, cap) { var out = [] var max = cap > 0 ? cap : 2000 function walk(n) { if (!n || out.length >= max) return if (n.type === 'element' && bareSummonMatches(sel, n)) out.push(n) var ch = n.children || [] var i for (i = 0; i < ch.length; i++) walk(ch[i]) } walk(root) return out } function bareSummonComputedStyle(node, sheets) { var out = {} function apply(decl) { var k for (k in decl) { if (Object.prototype.hasOwnProperty.call(decl, k)) out[k] = decl[k] } } var i for (i = 0; i < BARE_SUMMON_UA_CSS.length; i++) { if (bareSummonMatches(BARE_SUMMON_UA_CSS[i].sel, node)) apply(BARE_SUMMON_UA_CSS[i].decl) } if (sheets) { for (i = 0; i < sheets.length; i++) { var rules = sheets[i] for (var r = 0; r < rules.length; r++) { if (bareSummonMatches(rules[r].sel, node)) apply(rules[r].decl) } } } if (node && node.attrs && node.attrs.style) { apply(bareSummonParseDeclarations(node.attrs.style)) } return out } function bareSummonDisplay(style) { var d = style && style.display ? String(style.display).toLowerCase() : '' if (d === 'none') return 'none' if (style && String(style.visibility || '').toLowerCase() === 'hidden') return 'none' if (d === 'inline' || d === 'inline-block' || d === 'inline-flex') return 'inline' if (d === 'flex' || d === 'grid' || d === 'table' || d === 'list-item') return 'block' return '' }