Skip to content

Commit e84a1a4

Browse files
committed
fix attribute decode reggression (fix #3327)
1 parent 0009105 commit e84a1a4

File tree

7 files changed

+35
-17
lines changed

7 files changed

+35
-17
lines changed

Diff for: flow/compiler.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ declare type CompilerOptions = {
1111
getTagNamespace?: (tag: string) => ?string; // check the namespace for a tag
1212
transforms?: Array<Function>; // a list of transforms on parsed AST before codegen
1313
preserveWhitespace?: boolean;
14-
shouldDecodeAttr?: boolean;
14+
isFromDOM?: boolean;
15+
shouldDecodeTags?: boolean;
1516

1617
// runtime user-configurable
1718
delimiters?: [string, string]; // template delimiters

Diff for: src/compiler/parser/entity-decoder.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22

33
const decoder = document.createElement('div')
44

5-
export function decodeHTML (html: string, asAttribute?: boolean): string {
6-
if (asAttribute) {
7-
html = html
8-
.replace(/</g, '&lt;')
9-
.replace(/>/g, '&gt;')
10-
}
5+
export function decodeHTML (html: string): string {
116
decoder.innerHTML = html
127
return decoder.textContent
138
}

Diff for: src/compiler/parser/html-parser.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
1010
*/
1111

12-
import { decodeHTML } from 'entities'
1312
import { makeMap, no } from 'shared/util'
1413
import { isNonPhrasingTag, canBeLeftOpenTag } from 'web/util/index'
1514

@@ -49,11 +48,23 @@ const isSpecialTag = makeMap('script,style', true)
4948

5049
const reCache = {}
5150

51+
const ampRE = /&amp;/g
52+
const ltRE = /&lt;/g
53+
const gtRE = /&gt;/g
54+
55+
function decodeAttr (value, shouldDecodeTags) {
56+
if (shouldDecodeTags) {
57+
value = value.replace(ltRE, '<').replace(gtRE, '>')
58+
}
59+
return value.replace(ampRE, '&')
60+
}
61+
5262
export function parseHTML (html, options) {
5363
const stack = []
5464
const expectHTML = options.expectHTML
5565
const isUnaryTag = options.isUnaryTag || no
56-
const shouldDecodeAttr = options.shouldDecodeAttr
66+
const isFromDOM = options.isFromDOM
67+
const shouldDecodeTags = options.shouldDecodeTags
5768
let index = 0
5869
let last, lastTag
5970
while (html) {
@@ -203,7 +214,7 @@ export function parseHTML (html, options) {
203214
const value = args[3] || args[4] || args[5] || ''
204215
attrs[i] = {
205216
name: args[1],
206-
value: shouldDecodeAttr ? decodeHTML(value, true) : value
217+
value: isFromDOM ? decodeAttr(value, shouldDecodeTags) : value
207218
}
208219
}
209220

Diff for: src/compiler/parser/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ export function parse (
5454
parseHTML(template, {
5555
expectHTML: options.expectHTML,
5656
isUnaryTag: options.isUnaryTag,
57-
shouldDecodeAttr: options.shouldDecodeAttr,
57+
isFromDOM: options.isFromDOM,
58+
shouldDecodeTags: options.shouldDecodeTags,
5859
start (tag, attrs, unary) {
5960
// check namespace.
6061
// inherit parent ns if there is one

Diff for: src/entries/web-runtime-with-compiler.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import Vue from './web-runtime'
44
import { warn, cached } from 'core/util/index'
5-
import { query, shouldDecodeAttr } from 'web/util/index'
5+
import { query, shouldDecodeTags } from 'web/util/index'
66
import { compileToFunctions } from 'web/compiler/index'
77

88
const idToTemplate = cached(id => {
@@ -42,9 +42,10 @@ Vue.prototype.$mount = function (
4242
}
4343
if (template) {
4444
const { render, staticRenderFns } = compileToFunctions(template, {
45-
shouldDecodeAttr: isFromDOM && shouldDecodeAttr,
46-
delimiters: options.delimiters,
47-
warn
45+
warn,
46+
isFromDOM,
47+
shouldDecodeTags,
48+
delimiters: options.delimiters
4849
}, this)
4950
options.render = render
5051
options.staticRenderFns = staticRenderFns

Diff for: src/platforms/web/util/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ export const isIE = UA && /msie|trident/.test(UA)
1111
export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
1212
export const isAndroid = UA && UA.indexOf('android') > 0
1313

14-
// some browsers, e.g. PhantomJS, encodes attribute values for innerHTML
14+
// some browsers, e.g. PhantomJS, encodes angular brackets
15+
// inside attribute values when retrieving innerHTML.
1516
// this causes problems with the in-browser parser.
16-
export const shouldDecodeAttr = inBrowser ? (function () {
17+
export const shouldDecodeTags = inBrowser ? (function () {
1718
const div = document.createElement('div')
1819
div.innerHTML = '<div a=">">'
1920
return div.innerHTML.indexOf('&gt;') > 0

Diff for: test/unit/features/options/el.spec.js

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ describe('Options el', () => {
6666
expect(vm.$el.childNodes[1].childNodes[0].childNodes[0].namespaceURI).toContain('svg')
6767
})
6868

69+
it('properly encode attribute values', function () {
70+
const el = document.createElement('div')
71+
el.innerHTML = '<a href="/a?foo=bar&baz=qux" name="<abc>"></a>'
72+
const vm = new Vue({ el })
73+
expect(vm.$el.children[0].getAttribute('href')).toBe('/a?foo=bar&baz=qux')
74+
expect(vm.$el.children[0].getAttribute('name')).toBe('<abc>')
75+
})
76+
6977
it('warn cannot find element', () => {
7078
new Vue({ el: '#non-existent' })
7179
expect('Cannot find element: #non-existent').toHaveBeenWarned()

0 commit comments

Comments
 (0)