Browse Source

fix attribute decode reggression (fix #3327)

dev
Evan You 8 years ago
parent
commit
e84a1a43be
  1. 3
      flow/compiler.js
  2. 7
      src/compiler/parser/entity-decoder.js
  3. 17
      src/compiler/parser/html-parser.js
  4. 3
      src/compiler/parser/index.js
  5. 9
      src/entries/web-runtime-with-compiler.js
  6. 5
      src/platforms/web/util/index.js
  7. 8
      test/unit/features/options/el.spec.js

3
flow/compiler.js

@ -11,7 +11,8 @@ declare type CompilerOptions = {
getTagNamespace?: (tag: string) => ?string; // check the namespace for a tag
transforms?: Array<Function>; // a list of transforms on parsed AST before codegen
preserveWhitespace?: boolean;
shouldDecodeAttr?: boolean;
isFromDOM?: boolean;
shouldDecodeTags?: boolean;
// runtime user-configurable
delimiters?: [string, string]; // template delimiters

7
src/compiler/parser/entity-decoder.js

@ -2,12 +2,7 @@
const decoder = document.createElement('div')
export function decodeHTML (html: string, asAttribute?: boolean): string {
if (asAttribute) {
html = html
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
}
export function decodeHTML (html: string): string {
decoder.innerHTML = html
return decoder.textContent
}

17
src/compiler/parser/html-parser.js

@ -9,7 +9,6 @@
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
*/
import { decodeHTML } from 'entities'
import { makeMap, no } from 'shared/util'
import { isNonPhrasingTag, canBeLeftOpenTag } from 'web/util/index'
@ -49,11 +48,23 @@ const isSpecialTag = makeMap('script,style', true)
const reCache = {}
const ampRE = /&amp;/g
const ltRE = /&lt;/g
const gtRE = /&gt;/g
function decodeAttr (value, shouldDecodeTags) {
if (shouldDecodeTags) {
value = value.replace(ltRE, '<').replace(gtRE, '>')
}
return value.replace(ampRE, '&')
}
export function parseHTML (html, options) {
const stack = []
const expectHTML = options.expectHTML
const isUnaryTag = options.isUnaryTag || no
const shouldDecodeAttr = options.shouldDecodeAttr
const isFromDOM = options.isFromDOM
const shouldDecodeTags = options.shouldDecodeTags
let index = 0
let last, lastTag
while (html) {
@ -203,7 +214,7 @@ export function parseHTML (html, options) {
const value = args[3] || args[4] || args[5] || ''
attrs[i] = {
name: args[1],
value: shouldDecodeAttr ? decodeHTML(value, true) : value
value: isFromDOM ? decodeAttr(value, shouldDecodeTags) : value
}
}

3
src/compiler/parser/index.js

@ -54,7 +54,8 @@ export function parse (
parseHTML(template, {
expectHTML: options.expectHTML,
isUnaryTag: options.isUnaryTag,
shouldDecodeAttr: options.shouldDecodeAttr,
isFromDOM: options.isFromDOM,
shouldDecodeTags: options.shouldDecodeTags,
start (tag, attrs, unary) {
// check namespace.
// inherit parent ns if there is one

9
src/entries/web-runtime-with-compiler.js

@ -2,7 +2,7 @@
import Vue from './web-runtime'
import { warn, cached } from 'core/util/index'
import { query, shouldDecodeAttr } from 'web/util/index'
import { query, shouldDecodeTags } from 'web/util/index'
import { compileToFunctions } from 'web/compiler/index'
const idToTemplate = cached(id => {
@ -42,9 +42,10 @@ Vue.prototype.$mount = function (
}
if (template) {
const { render, staticRenderFns } = compileToFunctions(template, {
shouldDecodeAttr: isFromDOM && shouldDecodeAttr,
delimiters: options.delimiters,
warn
warn,
isFromDOM,
shouldDecodeTags,
delimiters: options.delimiters
}, this)
options.render = render
options.staticRenderFns = staticRenderFns

5
src/platforms/web/util/index.js

@ -11,9 +11,10 @@ export const isIE = UA && /msie|trident/.test(UA)
export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
export const isAndroid = UA && UA.indexOf('android') > 0
// some browsers, e.g. PhantomJS, encodes attribute values for innerHTML
// some browsers, e.g. PhantomJS, encodes angular brackets
// inside attribute values when retrieving innerHTML.
// this causes problems with the in-browser parser.
export const shouldDecodeAttr = inBrowser ? (function () {
export const shouldDecodeTags = inBrowser ? (function () {
const div = document.createElement('div')
div.innerHTML = '<div a=">">'
return div.innerHTML.indexOf('&gt;') > 0

8
test/unit/features/options/el.spec.js

@ -66,6 +66,14 @@ describe('Options el', () => {
expect(vm.$el.childNodes[1].childNodes[0].childNodes[0].namespaceURI).toContain('svg')
})
it('properly encode attribute values', function () {
const el = document.createElement('div')
el.innerHTML = '<a href="/a?foo=bar&baz=qux" name="<abc>"></a>'
const vm = new Vue({ el })
expect(vm.$el.children[0].getAttribute('href')).toBe('/a?foo=bar&baz=qux')
expect(vm.$el.children[0].getAttribute('name')).toBe('<abc>')
})
it('warn cannot find element', () => {
new Vue({ el: '#non-existent' })
expect('Cannot find element: #non-existent').toHaveBeenWarned()

Loading…
Cancel
Save