diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index 859f4454..2c7aa7b3 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -3,7 +3,7 @@ import { decodeHTML } from 'entities' import { parseHTML } from './html-parser' import { parseText } from './text-parser' -import { hyphenate, cached, no } from 'shared/util' +import { cached, no } from 'shared/util' import { pluckModuleFunction, getAndRemoveAttr, @@ -59,9 +59,6 @@ export function parse ( expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, start (tag, attrs, unary) { - // normalize tag name - tag = hyphenate(tag) - // check namespace. // inherit parent ns if there is one const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag) diff --git a/src/core/vdom/create-element.js b/src/core/vdom/create-element.js index 778c5135..8ce307dc 100644 --- a/src/core/vdom/create-element.js +++ b/src/core/vdom/create-element.js @@ -41,38 +41,16 @@ function _createElement ( // in case of component :is set to falsy value return emptyVNode() } - if (typeof tag === 'string') { - const namespace = config.getTagNamespace(tag) - let Ctor - if (config.isReservedTag(tag)) { - return new VNode( - tag, data, normalizeChildren(children, namespace), - undefined, undefined, - namespace, context, host - ) - } else if ((Ctor = resolveAsset(context.$options, 'components', tag))) { - return createComponent(Ctor, data, parent, context, host, children, tag) - } else { - if (process.env.NODE_ENV !== 'production') { - if ( - !namespace && - !(config.ignoredElements && config.ignoredElements.indexOf(tag) > -1) && - config.isUnknownElement(tag) - ) { - warn( - 'Unknown custom element: <' + tag + '> - did you ' + - 'register the component correctly? For recursive components, ' + - 'make sure to provide the "name" option.' - ) - } - } - return new VNode( - tag, data, normalizeChildren(children, namespace), - undefined, undefined, - namespace, context, host - ) - } - } else { - return createComponent(tag, data, parent, context, host, children) + const Ctor = typeof tag === 'string' + ? resolveAsset(context.$options, 'components', tag) + : tag + if (Ctor) { + return createComponent(Ctor, data, parent, context, host, children) + } else if (typeof tag === 'string') { + const ns = config.getTagNamespace(tag) + return new VNode( + tag, data, normalizeChildren(children, ns), + undefined, undefined, ns, context, host + ) } } diff --git a/src/core/vdom/helpers.js b/src/core/vdom/helpers.js index c0c22b89..795e577a 100644 --- a/src/core/vdom/helpers.js +++ b/src/core/vdom/helpers.js @@ -36,7 +36,9 @@ export function normalizeChildren ( last.text += c.text } else { // inherit parent namespace - if (ns && c.tag) c.ns = ns + if (ns) { + applyNS(c, ns) + } res.push(c) } } @@ -49,6 +51,17 @@ function createTextVNode (val) { return new VNode(undefined, undefined, undefined, String(val)) } +function applyNS (vnode, ns) { + if (vnode.tag && !vnode.ns) { + vnode.ns = ns + if (vnode.children) { + for (let i = 0, l = vnode.children.length; i < l; i++) { + applyNS(vnode.children[i], ns) + } + } + } +} + export function updateListeners ( on: Object, oldOn: Object, diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index 775ea4df..3a8d5400 100644 --- a/src/core/vdom/patch.js +++ b/src/core/vdom/patch.js @@ -7,6 +7,7 @@ * of making flow understand it is not worth it. */ +import config from '../config' import VNode from './vnode' import { isPrimitive, _toString, warn } from '../util/index' @@ -90,6 +91,20 @@ export function createPatchFunction (backend) { const children = vnode.children const tag = vnode.tag if (isDef(tag)) { + if (process.env.NODE_ENV !== 'production') { + if ( + !vnode.ns && + !(config.ignoredElements && config.ignoredElements.indexOf(tag) > -1) && + config.isUnknownElement(tag) + ) { + warn( + 'Unknown custom element: <' + tag + '> - did you ' + + 'register the component correctly? For recursive components, ' + + 'make sure to provide the "name" option.', + vnode.context + ) + } + } elm = vnode.elm = vnode.ns ? nodeOps.createElementNS(vnode.ns, tag) : nodeOps.createElement(tag) diff --git a/test/unit/features/options/el.spec.js b/test/unit/features/options/el.spec.js index 6da792b5..9f7b5f6c 100644 --- a/test/unit/features/options/el.spec.js +++ b/test/unit/features/options/el.spec.js @@ -42,7 +42,11 @@ describe('Options el', () => { it('svg element', () => { const parent = document.createElement('div') - parent.innerHTML = '{{ text }}' + parent.innerHTML = + '' + + '{{ text }}' + + '' + + '' const vm = new Vue({ el: parent.childNodes[0], data: { @@ -57,6 +61,9 @@ describe('Options el', () => { expect(vm.$el.childNodes[0].getAttribute('y')).toBe(vm.y.toString()) expect(vm.$el.childNodes[0].getAttribute('fill')).toBe(vm.color) expect(vm.$el.childNodes[0].textContent).toBe(vm.text) + // nested, non-explicitly listed SVG elements + expect(vm.$el.childNodes[1].childNodes[0].namespaceURI).toContain('svg') + expect(vm.$el.childNodes[1].childNodes[0].childNodes[0].namespaceURI).toContain('svg') }) it('warn cannot find element', () => { diff --git a/test/unit/modules/compiler/parser.spec.js b/test/unit/modules/compiler/parser.spec.js index 8f260eca..9281f31e 100644 --- a/test/unit/modules/compiler/parser.spec.js +++ b/test/unit/modules/compiler/parser.spec.js @@ -46,7 +46,7 @@ describe('parser', () => { it('camelCase element', () => { const ast = parse('

hello world

', baseOptions) - expect(ast.tag).toBe('my-component') + expect(ast.tag).toBe('MyComponent') expect(ast.plain).toBe(true) expect(ast.children[0].tag).toBe('p') expect(ast.children[0].plain).toBe(true) diff --git a/test/unit/modules/vdom/create-element.spec.js b/test/unit/modules/vdom/create-element.spec.js index 96695f3b..c39350b2 100644 --- a/test/unit/modules/vdom/create-element.spec.js +++ b/test/unit/modules/vdom/create-element.spec.js @@ -62,7 +62,6 @@ describe('create-element', () => { expect(vnode.ns).toBeUndefined() expect(vnode.context).toEqual(vm) expect(vnode.componentOptions).toBeUndefined() - expect(`Unknown custom element: <${tag}> - did you`).toHaveBeenWarned() }) it('render empty vnode with falsy tag using createElement', () => { diff --git a/test/unit/modules/vdom/patch/element.spec.js b/test/unit/modules/vdom/patch/element.spec.js index 14b429f2..5872bdf8 100644 --- a/test/unit/modules/vdom/patch/element.spec.js +++ b/test/unit/modules/vdom/patch/element.spec.js @@ -16,6 +16,12 @@ describe('element', () => { expect(elm.namespaceURI).toBe('http://www.w3.org/2000/svg') }) + it('should warn unknown element', () => { + const vnode = new VNode('unknown') + patch(null, vnode) + expect(`Unknown custom element: `).toHaveBeenWarned() + }) + it('should create an elements which having text content', () => { const vnode = new VNode('div', {}, [createTextVNode('hello world')]) const elm = patch(null, vnode)