forked from RubyLouvre/avalon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
avalon.live.js
156 lines (148 loc) · 5.92 KB
/
avalon.live.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
define(["avalon"], function(avalon) {
var DOC = document
var root = DOC.documentElement
var IEEventMap = {
"change": "click",
"focus": "focusin",
"blur": "focusout"
}
function getVal(elem) {
var type = elem.type
if (type === "select-multiple") {
if (elem.selectedIndex > -1) {
var ret = []
for (var i = 0, el; el = elem.options[i++]; ) {
ret.push(el.selected)
}
return ret.join("-")
} else {
return ""
}
} else if (elem.nodeName.toLowerCase() === "select") {
return elem.selectedIndex;
}
return elem.value
}
function testChange(e) {
var callbacks = liveMap["fixChangechange"]
var target = e.target
for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
var elem = obj.elem
if (root.contains(elem)) {
if (elem === target) {
var curVal = getVal(elem)
if (obj.__change__ !== curVal) {
e.type = "change"
obj.fn.call(elem, e)
obj.__change__ = curVal
}
}
} else {
dequeue(callbacks, obj, i)
}
}
}
function dequeue(callbacks, obj, i) {
var parent = obj.elem.parentNode
if (!parent || parent.nodeType == 11) {
callbacks.splice(i, 1)
}
}
var liveMap = avalon.bindingHandlers.live = function(data, vmodels) {
var type = data.param
var elem = data.element
var live = "noFix"
if (!DOC.createEvent) {
if (/focus|blur/.test(type)) {
live = "fixFocus"//旧式IE下使用focusin与focusout来模拟focus、blur,使用click来模拟复选框,单选框的change事件
} else if (type == "change") {
var elemType = elem.type
if (elemType == "radio" || elemType === "checkbox") {
live = "fixFocus"
if (!("_just_changed" in elem)) {//确保只绑定一次
elem._just_changed = false
elem.attachEvent("onpropertychange", function(e) {
if (e.propertyName == "checked") {
elem._just_changed = true
}
})
}
} else {
live = "fixChange"
}
} else if (/submit|reset|select/.test(type)) {
live = false//对于一些模拟成本太大的事件直接使用普通的事件绑定
}
}
if (live) {
if (!liveMap[live + type]) {
liveMap[live + type] = []
if (live === "noFix") {
avalon.bind(DOC, type, function(e) {//W3C
var callbacks = liveMap[live + type]
var target = e.target
for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
if (root.contains(obj.elem)) {
if (obj.elem === target || obj.elem.contains(target)) {
obj.fn.call(obj.elem, e)
}
} else {
dequeue(callbacks, obj, i)
}
}
}, true)
}
if (live === "fixFocus") {//旧式浏览器的focus,blur,单选框与复选枉的change
avalon.bind(DOC, IEEventMap[type], function(e) {
var callbacks = liveMap[live + type]
var target = e.target
for (var i = callbacks.length, obj; obj = callbacks[--i]; ) {
var elem = obj.elem
if (root.contains(elem)) {
if (elem === target || elem.contains(target)) {
if (type === "change") {
if (elem._just_changed === true) {
e.type = "change"
obj.fn.call(elem, e)
elem._just_changed = false
}
} else {
e.type = type
obj.fn.call(elem, e)
}
}
} else {
dequeue(callbacks, obj, i)
}
}
})
}
if (live === "fixChange") {
avalon.bind(DOC, "beforeactivate", testChange)
avalon.bind(DOC, "beforedeactivate", testChange)
}
}
data.specialBind = function(elem, fn) {
var obj = {
elem: elem,
fn: fn
}
if (/focus|blur/.test(type)) {
elem.tabIndex = elem.tabIndex || -1
}
if (live === "fixChange") {
obj.__change__ = getVal(elem)
}
var callbacks = liveMap[live + type]
callbacks.unshift(obj)
data.specialUnbind = function() {
avalon.Array.remove(callbacks, obj)
delete data.specialBind
delete data.specialUnbind
}
}
}
avalon.bindingHandlers.on(data, vmodels)
}
})
//avalon的事件代理模块