diff --git a/.npmignore b/.npmignore index 48873c87..bf023d92 100644 --- a/.npmignore +++ b/.npmignore @@ -1,20 +1,8 @@ -# Configuration files +# Development-specific files .deploy.env .editorconfig .eslintrc.js .gitattributes .gitignore .travis.yml - -# Tests -test-utils/ -tests/ - -# Documentation -docs/ -examples/ CONTRIBUTING.md - -# Browser stub (use index.js w/ a bundler or mithril.js w/o one instead) -module/ -browser.js diff --git a/README.md b/README.md index ac65b7f1..9664d8f4 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult ## Modularity -Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.53 KB min+gzip +Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.54 KB min+gzip In addition, Mithril is now completely modular: you can import only the modules that you need and easily integrate 3rd party modules if you wish to use a different library for routing, ajax, and even rendering diff --git a/mithril.js b/mithril.js index 43523644..715ecc63 100644 --- a/mithril.js +++ b/mithril.js @@ -759,14 +759,14 @@ var coreRenderer = function($window) { } function setAttr(vnode, key2, old, value, ns) { var element = vnode.dom - if (key2 === "key" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return + if (key2 === "key" || key2 === "is" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return var nsLastIndex = key2.indexOf(":") if (nsLastIndex > -1 && key2.substr(0, nsLastIndex) === "xlink") { element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(nsLastIndex + 1), value) } else if (key2[0] === "o" && key2[1] === "n" && typeof value === "function") updateEvent(vnode, key2, value) else if (key2 === "style") updateStyle(element, old, value) - else if (key2 in element && !isAttribute(key2) && ns === undefined) { + else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) { //setting input[value] to same value by typing on focused element moves cursor to end in Chrome if (vnode.tag === "input" && key2 === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return //setting select[value] to same value while having select open blinks select dropdown in Chrome @@ -815,6 +815,9 @@ var coreRenderer = function($window) { function isAttribute(attr) { return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type" } + function isCustomElement(vnode){ + return vnode.attrs.is || vnode.tag.indexOf("-") > -1 + } function hasIntegrationMethods(source) { return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove) } diff --git a/mithril.min.js b/mithril.min.js index 5242bdcd..811aaac4 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -26,16 +26,16 @@ null!=b.text&&(b.children=[u("#",void 0,void 0,b.text,void 0,void 0)]),g(q,f.chi b.dom){var e=y.createDocumentFragment();if(0 -1 && key.substr(0, nsLastIndex) === "xlink") { element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1), value) } else if (key[0] === "o" && key[1] === "n" && typeof value === "function") updateEvent(vnode, key, value) else if (key === "style") updateStyle(element, old, value) - else if (key in element && !isAttribute(key) && ns === undefined) { + else if (key in element && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) { //setting input[value] to same value by typing on focused element moves cursor to end in Chrome if (vnode.tag === "input" && key === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return //setting select[value] to same value while having select open blinks select dropdown in Chrome @@ -491,6 +491,9 @@ module.exports = function($window) { function isAttribute(attr) { return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type" } + function isCustomElement(vnode){ + return vnode.attrs.is || vnode.tag.indexOf("-") > -1 + } function hasIntegrationMethods(source) { return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove) } diff --git a/render/tests/test-attributes.js b/render/tests/test-attributes.js index 73cbd685..2d08007b 100644 --- a/render/tests/test-attributes.js +++ b/render/tests/test-attributes.js @@ -11,7 +11,43 @@ o.spec("attributes", function() { root = $window.document.body render = vdom($window).render }) + o.spec("customElements", function(){ + + o("when vnode is customElement, custom setAttribute called", function(){ + var normal = [ + { tag: "input", attrs: { value: 'hello' } }, + { tag: "input", attrs: { value: 'hello' } }, + { tag: "input", attrs: { value: 'hello' } } + ] + + var custom = [ + { tag: "custom-element", attrs: { custom: 'x' } }, + { tag: "input", attrs: { is: 'something-special', custom: 'x' } }, + { tag: "custom-element", attrs: { is: 'something-special', custom: 'x' } } + ] + + var view = normal.concat(custom) + + var f = $window.document.createElement + var spy + + $window.document.createElement = function(tag, is){ + var el = f(tag, is) + if(!spy){ + spy = o.spy(el.setAttribute) + } + el.setAttribute = spy + + return el + } + + render(root, view) + + o(spy.callCount).equals( custom.length ) + }) + + }) o.spec("input readonly", function() { o("when input readonly is true, attribute is present", function() { var a = {tag: "input", attrs: {readonly: true}}