355 lines
9.6 KiB
JavaScript
355 lines
9.6 KiB
JavaScript
/** First-party DOM for summon page JS. Wraps the HTML tree; no host objects leak. */
|
|
|
|
function bareSummonClassList(node) {
|
|
return {
|
|
add: function () {
|
|
var set = (node.attrs.class || '').split(/\s+/).filter(Boolean)
|
|
var i
|
|
for (i = 0; i < arguments.length; i++) {
|
|
var n = String(arguments[i] || '')
|
|
if (n && set.indexOf(n) < 0) set.push(n)
|
|
}
|
|
node.attrs.class = set.join(' ')
|
|
},
|
|
remove: function () {
|
|
var set = (node.attrs.class || '').split(/\s+/).filter(Boolean)
|
|
var i
|
|
for (i = 0; i < arguments.length; i++) {
|
|
var n = String(arguments[i] || '')
|
|
var x = set.indexOf(n)
|
|
if (x >= 0) set.splice(x, 1)
|
|
}
|
|
node.attrs.class = set.join(' ')
|
|
},
|
|
contains: function (n) {
|
|
return (node.attrs.class || '').split(/\s+/).indexOf(String(n || '')) >= 0
|
|
},
|
|
toggle: function (n) {
|
|
n = String(n || '')
|
|
if (this.contains(n)) this.remove(n)
|
|
else this.add(n)
|
|
},
|
|
toString: function () {
|
|
return node.attrs.class || ''
|
|
}
|
|
}
|
|
}
|
|
|
|
function bareSummonWrapNode(node, env) {
|
|
if (!node) return null
|
|
if (node._el) return node._el
|
|
if (node.type === 'text') {
|
|
var tn = {
|
|
nodeType: 3,
|
|
nodeName: '#text',
|
|
get data() {
|
|
return node.text || ''
|
|
},
|
|
set data(v) {
|
|
node.text = String(v)
|
|
},
|
|
get textContent() {
|
|
return node.text || ''
|
|
},
|
|
set textContent(v) {
|
|
node.text = String(v)
|
|
}
|
|
}
|
|
node._el = tn
|
|
return tn
|
|
}
|
|
var el = {
|
|
nodeType: 1,
|
|
nodeName: String(node.name || '').toUpperCase(),
|
|
tagName: String(node.name || '').toUpperCase(),
|
|
_node: node,
|
|
get id() {
|
|
return node.attrs.id || ''
|
|
},
|
|
set id(v) {
|
|
node.attrs.id = String(v == null ? '' : v)
|
|
},
|
|
get className() {
|
|
return node.attrs.class || ''
|
|
},
|
|
set className(v) {
|
|
node.attrs.class = String(v == null ? '' : v)
|
|
},
|
|
get classList() {
|
|
return bareSummonClassList(node)
|
|
},
|
|
get href() {
|
|
return node.attrs.href || ''
|
|
},
|
|
set href(v) {
|
|
node.attrs.href = String(v == null ? '' : v)
|
|
},
|
|
get src() {
|
|
return node.attrs.src || ''
|
|
},
|
|
set src(v) {
|
|
node.attrs.src = String(v == null ? '' : v)
|
|
},
|
|
get value() {
|
|
return node.attrs.value != null ? String(node.attrs.value) : ''
|
|
},
|
|
set value(v) {
|
|
node.attrs.value = String(v == null ? '' : v)
|
|
},
|
|
get textContent() {
|
|
return bareSummonTextContent(node)
|
|
},
|
|
set textContent(v) {
|
|
node.children = [
|
|
{
|
|
type: 'text',
|
|
text: String(v == null ? '' : v),
|
|
parent: node,
|
|
children: []
|
|
}
|
|
]
|
|
},
|
|
get innerHTML() {
|
|
return bareSummonSerializeInner(node)
|
|
},
|
|
set innerHTML(v) {
|
|
var kids = bareSummonParseFragment(String(v == null ? '' : v))
|
|
var i
|
|
for (i = 0; i < kids.length; i++) kids[i].parent = node
|
|
node.children = kids
|
|
},
|
|
getAttribute: function (k) {
|
|
k = String(k || '').toLowerCase()
|
|
return node.attrs && node.attrs[k] != null ? String(node.attrs[k]) : null
|
|
},
|
|
setAttribute: function (k, v) {
|
|
node.attrs[String(k || '').toLowerCase()] = String(v == null ? '' : v)
|
|
},
|
|
removeAttribute: function (k) {
|
|
delete node.attrs[String(k || '').toLowerCase()]
|
|
},
|
|
hasAttribute: function (k) {
|
|
return (
|
|
node.attrs &&
|
|
Object.prototype.hasOwnProperty.call(
|
|
node.attrs,
|
|
String(k || '').toLowerCase()
|
|
)
|
|
)
|
|
},
|
|
appendChild: function (child) {
|
|
var cn = child && child._node ? child._node : child
|
|
if (!cn || !cn.type) return child
|
|
if (cn.parent && cn.parent.children) {
|
|
var ix = cn.parent.children.indexOf(cn)
|
|
if (ix >= 0) cn.parent.children.splice(ix, 1)
|
|
}
|
|
cn.parent = node
|
|
node.children.push(cn)
|
|
return bareSummonWrapNode(cn, env)
|
|
},
|
|
removeChild: function (child) {
|
|
var cn = child && child._node ? child._node : child
|
|
var ix = node.children.indexOf(cn)
|
|
if (ix >= 0) {
|
|
node.children.splice(ix, 1)
|
|
cn.parent = null
|
|
}
|
|
return child
|
|
},
|
|
insertBefore: function (child, ref) {
|
|
var cn = child && child._node ? child._node : child
|
|
var rn = ref && ref._node ? ref._node : ref
|
|
if (cn.parent && cn.parent.children) {
|
|
var px = cn.parent.children.indexOf(cn)
|
|
if (px >= 0) cn.parent.children.splice(px, 1)
|
|
}
|
|
cn.parent = node
|
|
var at = rn ? node.children.indexOf(rn) : -1
|
|
if (at < 0) node.children.push(cn)
|
|
else node.children.splice(at, 0, cn)
|
|
return bareSummonWrapNode(cn, env)
|
|
},
|
|
querySelector: function (sel) {
|
|
var hits = bareSummonQueryAll(node, sel, 1)
|
|
return hits[0] ? bareSummonWrapNode(hits[0], env) : null
|
|
},
|
|
querySelectorAll: function (sel) {
|
|
return bareSummonQueryAll(node, sel, 500).map(function (n) {
|
|
return bareSummonWrapNode(n, env)
|
|
})
|
|
},
|
|
getElementsByTagName: function (name) {
|
|
name = String(name || '').toLowerCase()
|
|
return bareSummonQueryAll(node, name === '*' ? '*' : name, 500).map(
|
|
function (n) {
|
|
return bareSummonWrapNode(n, env)
|
|
}
|
|
)
|
|
},
|
|
getElementsByClassName: function (name) {
|
|
return bareSummonQueryAll(node, '.' + String(name || ''), 500).map(
|
|
function (n) {
|
|
return bareSummonWrapNode(n, env)
|
|
}
|
|
)
|
|
},
|
|
addEventListener: function (type, fn) {
|
|
if (!node._listeners) node._listeners = {}
|
|
var t = String(type || '')
|
|
if (!node._listeners[t]) node._listeners[t] = []
|
|
node._listeners[t].push(fn)
|
|
},
|
|
removeEventListener: function (type, fn) {
|
|
var t = String(type || '')
|
|
var arr = node._listeners && node._listeners[t]
|
|
if (!arr) return
|
|
node._listeners[t] = arr.filter(function (x) {
|
|
return x !== fn
|
|
})
|
|
},
|
|
click: function () {
|
|
var arr = (node._listeners && node._listeners.click) || []
|
|
var i
|
|
for (i = 0; i < arr.length; i++) {
|
|
try {
|
|
arr[i].call(el)
|
|
} catch (e) {
|
|
if (env && env.console && env.console.error) env.console.error(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Object.defineProperty(el, 'style', {
|
|
get: function () {
|
|
if (!node._styleProxy) {
|
|
var decl = bareSummonParseDeclarations(node.attrs.style || '')
|
|
node._styleProxy = decl
|
|
}
|
|
return node._styleProxy
|
|
}
|
|
})
|
|
Object.defineProperty(el, 'children', {
|
|
get: function () {
|
|
return (node.children || [])
|
|
.filter(function (c) {
|
|
return c.type === 'element'
|
|
})
|
|
.map(function (c) {
|
|
return bareSummonWrapNode(c, env)
|
|
})
|
|
}
|
|
})
|
|
Object.defineProperty(el, 'childNodes', {
|
|
get: function () {
|
|
return (node.children || []).map(function (c) {
|
|
return bareSummonWrapNode(c, env)
|
|
})
|
|
}
|
|
})
|
|
Object.defineProperty(el, 'parentNode', {
|
|
get: function () {
|
|
return node.parent ? bareSummonWrapNode(node.parent, env) : null
|
|
}
|
|
})
|
|
Object.defineProperty(el, 'firstChild', {
|
|
get: function () {
|
|
var c = node.children && node.children[0]
|
|
return c ? bareSummonWrapNode(c, env) : null
|
|
}
|
|
})
|
|
node._el = el
|
|
return el
|
|
}
|
|
|
|
function bareSummonFlushInlineStyle(node) {
|
|
if (!node) return
|
|
if (node._styleProxy) {
|
|
var bits = []
|
|
var k
|
|
for (k in node._styleProxy) {
|
|
if (Object.prototype.hasOwnProperty.call(node._styleProxy, k)) {
|
|
bits.push(k + ':' + node._styleProxy[k])
|
|
}
|
|
}
|
|
node.attrs.style = bits.join(';')
|
|
}
|
|
var ch = node.children || []
|
|
var i
|
|
for (i = 0; i < ch.length; i++) bareSummonFlushInlineStyle(ch[i])
|
|
}
|
|
|
|
function bareSummonCreateDocumentApi(doc, env) {
|
|
env = env || {}
|
|
var api = {
|
|
nodeType: 9,
|
|
nodeName: '#document',
|
|
documentElement: bareSummonWrapNode(doc.html, env),
|
|
head: bareSummonWrapNode(doc.head, env),
|
|
body: bareSummonWrapNode(doc.body, env),
|
|
get title() {
|
|
return doc.title || ''
|
|
},
|
|
set title(v) {
|
|
doc.title = String(v == null ? '' : v)
|
|
},
|
|
getElementById: function (id) {
|
|
var hits = bareSummonQueryAll(doc.root, '#' + String(id || ''), 1)
|
|
return hits[0] ? bareSummonWrapNode(hits[0], env) : null
|
|
},
|
|
querySelector: function (sel) {
|
|
var hits = bareSummonQueryAll(doc.root, sel, 1)
|
|
return hits[0] ? bareSummonWrapNode(hits[0], env) : null
|
|
},
|
|
querySelectorAll: function (sel) {
|
|
return bareSummonQueryAll(doc.root, sel, 500).map(function (n) {
|
|
return bareSummonWrapNode(n, env)
|
|
})
|
|
},
|
|
getElementsByTagName: function (name) {
|
|
name = String(name || '').toLowerCase()
|
|
return bareSummonQueryAll(doc.root, name === '*' ? '*' : name, 500).map(
|
|
function (n) {
|
|
return bareSummonWrapNode(n, env)
|
|
}
|
|
)
|
|
},
|
|
getElementsByClassName: function (name) {
|
|
return bareSummonQueryAll(doc.root, '.' + String(name || ''), 500).map(
|
|
function (n) {
|
|
return bareSummonWrapNode(n, env)
|
|
}
|
|
)
|
|
},
|
|
createElement: function (name) {
|
|
return bareSummonWrapNode(
|
|
bareSummonCreateNode(
|
|
'element',
|
|
String(name || 'div').toLowerCase(),
|
|
{}
|
|
),
|
|
env
|
|
)
|
|
},
|
|
createTextNode: function (text) {
|
|
return bareSummonWrapNode(
|
|
{
|
|
type: 'text',
|
|
text: String(text == null ? '' : text),
|
|
parent: null,
|
|
children: []
|
|
},
|
|
env
|
|
)
|
|
},
|
|
createDocumentFragment: function () {
|
|
return bareSummonWrapNode(
|
|
bareSummonCreateNode('element', 'fragment', {}),
|
|
env
|
|
)
|
|
}
|
|
}
|
|
env.document = api
|
|
return api
|
|
}
|