Skip to content

Commit 45ff621

Browse files
committedSep 13, 2016
handle multiline atribute value parsing in IE (fix #3663)
1 parent d0c13c7 commit 45ff621

File tree

7 files changed

+45
-17
lines changed

7 files changed

+45
-17
lines changed
 

‎flow/compiler.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ declare type CompilerOptions = {
1414
preserveWhitespace?: boolean;
1515
isFromDOM?: boolean;
1616
shouldDecodeTags?: boolean;
17+
shouldDecodeNewlines?: boolean;
1718

1819
// runtime user-configurable
1920
delimiters?: [string, string]; // template delimiters

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,19 @@ const isSpecialTag = makeMap('script,style', true)
4848

4949
const reCache = {}
5050

51-
const ampRE = /&/g
5251
const ltRE = /</g
5352
const gtRE = />/g
53+
const nlRE = /
/g
54+
const ampRE = /&/g
5455
const quoteRE = /"/g
5556

56-
function decodeAttr (value, shouldDecodeTags) {
57+
function decodeAttr (value, shouldDecodeTags, shouldDecodeNewlines) {
5758
if (shouldDecodeTags) {
5859
value = value.replace(ltRE, '<').replace(gtRE, '>')
5960
}
61+
if (shouldDecodeNewlines) {
62+
value = value.replace(nlRE, '\n')
63+
}
6064
return value.replace(ampRE, '&').replace(quoteRE, '"')
6165
}
6266

@@ -65,7 +69,6 @@ export function parseHTML (html, options) {
6569
const expectHTML = options.expectHTML
6670
const isUnaryTag = options.isUnaryTag || no
6771
const isFromDOM = options.isFromDOM
68-
const shouldDecodeTags = options.shouldDecodeTags
6972
let index = 0
7073
let last, lastTag
7174
while (html) {
@@ -215,7 +218,11 @@ export function parseHTML (html, options) {
215218
const value = args[3] || args[4] || args[5] || ''
216219
attrs[i] = {
217220
name: args[1],
218-
value: isFromDOM ? decodeAttr(value, shouldDecodeTags) : value
221+
value: isFromDOM ? decodeAttr(
222+
value,
223+
options.shouldDecodeTags,
224+
options.shouldDecodeNewlines
225+
) : value
219226
}
220227
}
221228

‎src/compiler/parser/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export function parse (
6262
isUnaryTag: options.isUnaryTag,
6363
isFromDOM: options.isFromDOM,
6464
shouldDecodeTags: options.shouldDecodeTags,
65+
shouldDecodeNewlines: options.shouldDecodeNewlines,
6566
start (tag, attrs, unary) {
6667
// check namespace.
6768
// inherit parent ns if there is one

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import Vue from './web-runtime'
44
import { warn, cached } from 'core/util/index'
5-
import { query, shouldDecodeTags } from 'web/util/index'
5+
import { query } from 'web/util/index'
6+
import { shouldDecodeTags, shouldDecodeNewlines } from 'web/util/compat'
67
import { compileToFunctions } from 'web/compiler/index'
78

89
const idToTemplate = cached(id => {
@@ -54,6 +55,7 @@ Vue.prototype.$mount = function (
5455
warn,
5556
isFromDOM,
5657
shouldDecodeTags,
58+
shouldDecodeNewlines,
5759
delimiters: options.delimiters
5860
}, this)
5961
options.render = render

‎src/platforms/web/util/compat.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* @flow */
2+
3+
import { inBrowser } from 'core/util/index'
4+
5+
// check whether current browser encodes a char inside attribute values
6+
function shouldDecode (content: string, encoded: string): boolean {
7+
const div = document.createElement('div')
8+
div.innerHTML = `<div a="${content}">`
9+
return div.innerHTML.indexOf(encoded) > 0
10+
}
11+
12+
// According to
13+
// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value
14+
// when serializing innerHTML, <, >, ", & should be encoded as entities.
15+
// However, only some browsers, e.g. PhantomJS, encodes < and >.
16+
// this causes problems with the in-browser parser.
17+
export const shouldDecodeTags = inBrowser ? shouldDecode('>', '&gt;') : false
18+
19+
// #3663
20+
// IE encodes newlines inside attribute values while other browsers don't
21+
export const shouldDecodeNewlines = inBrowser ? shouldDecode('\n', '&#10;') : false

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

-11
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,6 @@ 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-
// According to
15-
// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value
16-
// when serializing innerHTML, <, >, ", & should be encoded as entities.
17-
// However, only some browsers, e.g. PhantomJS, encodes < and >.
18-
// this causes problems with the in-browser parser.
19-
export const shouldDecodeTags = inBrowser ? (function () {
20-
const div = document.createElement('div')
21-
div.innerHTML = '<div a=">">'
22-
return div.innerHTML.indexOf('&gt;') > 0
23-
})() : false
24-
2514
/**
2615
* Query an element selector if it's not an element already.
2716
*/

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe('Options el', () => {
6767
})
6868

6969
// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value
70-
it('properly decode attribute values when parsing templates from DOM', function () {
70+
it('properly decode attribute values when parsing templates from DOM', () => {
7171
const el = document.createElement('div')
7272
el.innerHTML = '<a href="/a?foo=bar&baz=qux" name="<abc>" single=\'"hi"\'></a>'
7373
const vm = new Vue({ el })
@@ -76,6 +76,13 @@ describe('Options el', () => {
7676
expect(vm.$el.children[0].getAttribute('single')).toBe('"hi"')
7777
})
7878

79+
it('decode attribute value newlines when parsing templates from DOM in IE', () => {
80+
const el = document.createElement('div')
81+
el.innerHTML = `<a :style="{\ncolor:'red'\n}"></a>`
82+
const vm = new Vue({ el })
83+
expect(vm.$el.children[0].style.color).toBe('red')
84+
})
85+
7986
it('warn cannot find element', () => {
8087
new Vue({ el: '#non-existent' })
8188
expect('Cannot find element: #non-existent').toHaveBeenWarned()

0 commit comments

Comments
 (0)
Please sign in to comment.