+113
-46
lines changedFilter options
+113
-46
lines changed Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
1
1
/* @flow */
2
-
/* globals MutationObserver */
2
+
/* globals MessageChannel */
3
3
4
-
import { noop } from 'shared/util'
5
4
import { handleError } from './error'
6
5
7
6
// can we use __proto__?
@@ -80,41 +79,29 @@ export const nextTick = (function () {
80
79
}
81
80
}
82
81
83
-
// the nextTick behavior leverages the microtask queue, which can be accessed
84
-
// via either native Promise.then or MutationObserver.
85
-
// MutationObserver has wider support, however it is seriously bugged in
86
-
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
87
-
// completely stops working after triggering a few times... so, if native
88
-
// Promise is available, we will use it:
89
-
/* istanbul ignore if */ // $flow-disable-line
90
-
if (typeof Promise !== 'undefined' && isNative(Promise)) {
91
-
var p = Promise.resolve()
92
-
var logError = err => { handleError(err, null, 'nextTick') }
82
+
// An asynchronous deferring mechanism.
83
+
// In pre 2.4, we used to use microtasks (Promise/MutationObserver)
84
+
// but microtasks actually has too high a priority and fires in between
85
+
// supposedly sequential events (e.g. #4521, #6690) or even between
86
+
// bubbling of the same event (#6566). Technically setImmediate should be
87
+
// the ideal choice, but it's not available everywhere; and the only polyfill
88
+
// that consistently queues the callback after all DOM events triggered in the
89
+
// same loop is by using MessageChannel.
90
+
/* istanbul ignore if */
91
+
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
93
92
timerFunc = () => {
94
-
p.then(nextTickHandler).catch(logError)
95
-
// in problematic UIWebViews, Promise.then doesn't completely break, but
96
-
// it can get stuck in a weird state where callbacks are pushed into the
97
-
// microtask queue but the queue isn't being flushed, until the browser
98
-
// needs to do some other work, e.g. handle a timer. Therefore we can
99
-
// "force" the microtask queue to be flushed by adding an empty timer.
100
-
if (isIOS) setTimeout(noop)
93
+
setImmediate(nextTickHandler)
101
94
}
102
-
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
103
-
isNative(MutationObserver) ||
104
-
// PhantomJS and iOS 7.x
105
-
MutationObserver.toString() === '[object MutationObserverConstructor]'
95
+
} else if (typeof MessageChannel !== 'undefined' && (
96
+
isNative(MessageChannel) ||
97
+
// PhantomJS
98
+
MessageChannel.toString() === '[object MessageChannelConstructor]'
106
99
)) {
107
-
// use MutationObserver where native Promise is not available,
108
-
// e.g. PhantomJS, iOS7, Android 4.4
109
-
var counter = 1
110
-
var observer = new MutationObserver(nextTickHandler)
111
-
var textNode = document.createTextNode(String(counter))
112
-
observer.observe(textNode, {
113
-
characterData: true
114
-
})
100
+
const channel = new MessageChannel()
101
+
const port = channel.port2
102
+
channel.port1.onmessage = nextTickHandler
115
103
timerFunc = () => {
116
-
counter = (counter + 1) % 2
117
-
textNode.data = String(counter)
104
+
port.postMessage(1)
118
105
}
119
106
} else {
120
107
// fallback to setTimeout
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ let warn
9
9
// in some cases, the event used has to be determined at runtime
10
10
// so we used some reserved tokens during compile.
11
11
export const RANGE_TOKEN = '__r'
12
-
export const CHECKBOX_RADIO_TOKEN = '__c'
13
12
14
13
export default function model (
15
14
el: ASTElement,
@@ -86,7 +85,7 @@ function genCheckboxModel (
86
85
: `:_q(${value},${trueValueBinding})`
87
86
)
88
87
)
89
-
addHandler(el, CHECKBOX_RADIO_TOKEN,
88
+
addHandler(el, 'change',
90
89
`var $$a=${value},` +
91
90
'$$el=$event.target,' +
92
91
`$$c=$$el.checked?(${trueValueBinding}):(${falseValueBinding});` +
@@ -109,7 +108,7 @@ function genRadioModel (
109
108
let valueBinding = getBindingAttr(el, 'value') || 'null'
110
109
valueBinding = number ? `_n(${valueBinding})` : valueBinding
111
110
addProp(el, 'checked', `_q(${value},${valueBinding})`)
112
-
addHandler(el, CHECKBOX_RADIO_TOKEN, genAssignmentCode(value, valueBinding), null, true)
111
+
addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true)
113
112
}
114
113
115
114
function genSelect (
Original file line number Diff line number Diff line change
@@ -2,28 +2,21 @@
2
2
3
3
import { isDef, isUndef } from 'shared/util'
4
4
import { updateListeners } from 'core/vdom/helpers/index'
5
-
import { isChrome, isIE, supportsPassive } from 'core/util/env'
6
-
import { RANGE_TOKEN, CHECKBOX_RADIO_TOKEN } from 'web/compiler/directives/model'
5
+
import { isIE, supportsPassive } from 'core/util/env'
6
+
import { RANGE_TOKEN } from 'web/compiler/directives/model'
7
7
8
8
// normalize v-model event tokens that can only be determined at runtime.
9
9
// it's important to place the event as the first in the array because
10
10
// the whole point is ensuring the v-model callback gets called before
11
11
// user-attached handlers.
12
12
function normalizeEvents (on) {
13
-
let event
14
13
/* istanbul ignore if */
15
14
if (isDef(on[RANGE_TOKEN])) {
16
15
// IE input[type=range] only supports `change` event
17
-
event = isIE ? 'change' : 'input'
16
+
const event = isIE ? 'change' : 'input'
18
17
on[event] = [].concat(on[RANGE_TOKEN], on[event] || [])
19
18
delete on[RANGE_TOKEN]
20
19
}
21
-
if (isDef(on[CHECKBOX_RADIO_TOKEN])) {
22
-
// Chrome fires microtasks in between click/change, leads to #4521
23
-
event = isChrome ? 'click' : 'change'
24
-
on[event] = [].concat(on[CHECKBOX_RADIO_TOKEN], on[event] || [])
25
-
delete on[CHECKBOX_RADIO_TOKEN]
26
-
}
27
20
}
28
21
29
22
let target: HTMLElement
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="utf-8">
5
+
<title></title>
6
+
<script src="../../../dist/vue.min.js"></script>
7
+
</head>
8
+
<body>
9
+
10
+
<!-- #4510 click and change event on checkbox -->
11
+
<div id="case-1">
12
+
<div @click="num++">
13
+
{{ num }}
14
+
<input type="checkbox" v-model="checked">
15
+
</div>
16
+
</div>
17
+
<script>
18
+
var vm1 = new Vue({
19
+
el: '#case-1',
20
+
data: {
21
+
num: 1,
22
+
checked: false
23
+
}
24
+
})
25
+
</script>
26
+
27
+
<!-- #6566 click event bubbling -->
28
+
<div id="case-2">
29
+
<div v-if="expand">
30
+
<button @click="expand = false, countA++">Expand is True</button>
31
+
</div>
32
+
<div class="header" v-if="!expand" @click="expand = true, countB++">
33
+
<button>Expand is False</button>
34
+
</div>
35
+
<div class="count-a">
36
+
countA: {{countA}}
37
+
</div>
38
+
<div class="count-b">
39
+
countB: {{countB}}
40
+
</div>
41
+
</div>
42
+
<script>
43
+
var vm2 = new Vue({
44
+
el: '#case-2',
45
+
data: {
46
+
expand: true,
47
+
countA: 0,
48
+
countB: 0,
49
+
}
50
+
})
51
+
</script>
52
+
53
+
</body>
54
+
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
1
+
module.exports = {
2
+
'async edge cases': function (browser) {
3
+
browser
4
+
.url('http://localhost:8080/test/e2e/specs/async-edge-cases.html')
5
+
// #4510
6
+
.assert.containsText('#case-1', '1')
7
+
.assert.checked('#case-1 input', false)
8
+
9
+
.click('#case-1 input')
10
+
.assert.containsText('#case-1', '2')
11
+
.assert.checked('#case-1 input', true)
12
+
13
+
.click('#case-1 input')
14
+
.assert.containsText('#case-1', '3')
15
+
.assert.checked('#case-1 input', false)
16
+
17
+
// #6566
18
+
.assert.containsText('#case-2 button', 'Expand is True')
19
+
.assert.containsText('.count-a', 'countA: 0')
20
+
.assert.containsText('.count-b', 'countB: 0')
21
+
22
+
.click('#case-2 button')
23
+
.assert.containsText('#case-2 button', 'Expand is False')
24
+
.assert.containsText('.count-a', 'countA: 1')
25
+
.assert.containsText('.count-b', 'countB: 0')
26
+
27
+
.click('#case-2 button')
28
+
.assert.containsText('#case-2 button', 'Expand is True')
29
+
.assert.containsText('.count-a', 'countA: 1')
30
+
.assert.containsText('.count-b', 'countB: 1')
31
+
32
+
.end()
33
+
}
34
+
}
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4