diff --git a/docs/vnodes.md b/docs/vnodes.md index a07683f9..97b8d364 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -72,7 +72,7 @@ Property | Type | Description `text` | `(String|Number|Boolean)?` | This is used instead of `children` if a vnode contains a text node as its only child. This is done for performance reasons. Component vnodes never use the `text` property even if they have a text node as its only child. `dom` | `Element?` | Points to the element that corresponds to the vnode. This property is `undefined` in the `oninit` lifecycle method. In fragment and trusted HTML vnodes, `dom` points to the first element in the range. `domSize` | `Number?` | This is only set in fragment and trusted HTML vnodes, and it's `undefined` in all other vnode types. It defines the number of DOM elements that the vnode represents (starting from the element referenced by the `dom` property). -`state` | `Object` | An object that is persisted between redraws. In component vnodes, `state` is a deep clone of the component object. +`state` | `Object` | An object that is persisted between redraws. In component vnodes, `state` is a shallow clone of the component object. `events` | `Object?` | An object that is persisted between redraws and that stores event handlers so that they can be removed using the DOM API. The `events` property is `undefined` if there are no event handlers defined. This property is only used internally by Mithril, do not use it. --- diff --git a/render/hyperscript.js b/render/hyperscript.js index c19926bf..12fcf0be 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -9,43 +9,41 @@ function hyperscript(selector) { throw Error("The selector must be either a string or a component."); } - if (typeof selector === "string") { - if (selectorCache[selector] === undefined) { - var match, tag, classes = [], attributes = {} - while (match = selectorParser.exec(selector)) { - var type = match[1], value = match[2] - if (type === "" && value !== "") tag = value - else if (type === "#") attributes.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, "\\") - attributes[match[4]] = attrValue || true + if (typeof selector === "string" && selectorCache[selector] === undefined) { + var match, tag, classes = [], attributes = {} + while (match = selectorParser.exec(selector)) { + var type = match[1], value = match[2] + if (type === "" && value !== "") tag = value + else if (type === "#") attributes.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, "\\") + attributes[match[4]] = attrValue || true + } + } + if (classes.length > 0) attributes.className = classes.join(" ") + selectorCache[selector] = function(attrs, children) { + var hasAttrs = false, childList, text + var className = attrs.className || attrs.class + for (var key in attributes) attrs[key] = attributes[key] + if (className !== undefined) { + if (attrs.class !== undefined) { + attrs.class = undefined + attrs.className = className + } + if (attributes.className !== undefined) attrs.className = attributes.className + " " + className + } + for (var key in attrs) { + if (key !== "key") { + hasAttrs = true + break } } - if (classes.length > 0) attributes.className = classes.join(" ") - selectorCache[selector] = function(attrs, children) { - var hasAttrs = false, childList, text - var className = attrs.className || attrs.class - for (var key in attributes) attrs[key] = attributes[key] - if (className !== undefined) { - if (attrs.class !== undefined) { - attrs.class = undefined - attrs.className = className - } - if (attributes.className !== undefined) attrs.className = attributes.className + " " + className - } - for (var key in attrs) { - if (key !== "key") { - hasAttrs = true - break - } - } - if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children - else childList = children + if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children + else childList = children - return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined) - } + return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined) } } var attrs, children, childrenIndex diff --git a/render/render.js b/render/render.js index e71ca0fe..13bb402b 100644 --- a/render/render.js +++ b/render/render.js @@ -91,7 +91,9 @@ module.exports = function($window) { return element } function createComponent(vnode, hooks, ns) { - vnode.state = copy(vnode.tag) + // For object literals since `Vnode()` always sets the `state` field. + if (!vnode.state) vnode.state = {} + assign(vnode.state, vnode.tag) initLifecycle(vnode.tag, vnode, hooks) vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode)) @@ -500,18 +502,8 @@ module.exports = function($window) { return false } - function copy(data) { - if (data instanceof Array) { - var output = [] - for (var i = 0; i < data.length; i++) output[i] = data[i] - return output - } - else if (typeof data === "object") { - var output = {} - for (var i in data) output[i] = data[i] - return output - } - return data + function assign(target, source) { + Object.keys(source).forEach(function(k){target[k] = source[k]}) } function render(dom, vnodes) {