mithril
Version:
A framework for building brilliant applications
87 lines (69 loc) • 2.73 kB
JavaScript
var Vnode = require("../render/vnode")
var hyperscriptVnode = require("./hyperscriptVnode")
var hasOwn = require("../util/hasOwn")
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
var selectorCache = Object.create(null)
function isEmpty(object) {
for (var key in object) if (hasOwn.call(object, key)) return false
return true
}
function compileSelector(selector) {
var match, tag = "div", classes = [], attrs = {}
while (match = selectorParser.exec(selector)) {
var type = match[1], value = match[2]
if (type === "" && value !== "") tag = value
else if (type === "#") attrs.id = value
else if (type === ".") classes.push(value)
else if (match[3][0] === "[") {
var attrValue = match[6]
if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
if (match[4] === "class") classes.push(attrValue)
else attrs[match[4]] = attrValue === "" ? attrValue : attrValue || true
}
}
if (classes.length > 0) attrs.className = classes.join(" ")
if (isEmpty(attrs)) attrs = null
return selectorCache[selector] = {tag: tag, attrs: attrs}
}
function execSelector(state, vnode) {
var attrs = vnode.attrs
var hasClass = hasOwn.call(attrs, "class")
var className = hasClass ? attrs.class : attrs.className
vnode.tag = state.tag
if (state.attrs != null) {
attrs = Object.assign({}, state.attrs, attrs)
if (className != null || state.attrs.className != null) attrs.className =
className != null
? state.attrs.className != null
? String(state.attrs.className) + " " + String(className)
: className
: state.attrs.className != null
? state.attrs.className
: null
} else {
if (className != null) attrs.className = className
}
if (hasClass) attrs.class = null
// workaround for #2622 (reorder keys in attrs to set "type" first)
// The DOM does things to inputs based on the "type", so it needs set first.
// See: https://github.com/MithrilJS/mithril.js/issues/2622
if (state.tag === "input" && hasOwn.call(attrs, "type")) {
attrs = Object.assign({type: attrs.type}, attrs)
}
vnode.attrs = attrs
return vnode
}
function hyperscript(selector) {
if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") {
throw Error("The selector must be either a string or a component.");
}
var vnode = hyperscriptVnode.apply(1, arguments)
if (typeof selector === "string") {
vnode.children = Vnode.normalizeChildren(vnode.children)
if (selector !== "[") return execSelector(selectorCache[selector] || compileSelector(selector), vnode)
}
vnode.tag = selector
return vnode
}
module.exports = hyperscript