avalon-rails 1.4.7 → 1.4.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a883dc9ef6ec4c81e8664df873eab7a0844ef1d5
4
- data.tar.gz: 68269cfe5619ebfb73db88d4aa1658b19c59561f
3
+ metadata.gz: 4ec2949685acaec3839465e5ad405fe828708df4
4
+ data.tar.gz: 38bd673512f4460facd8d075fbf14a771ceee5c7
5
5
  SHA512:
6
- metadata.gz: e006b0b1cbfe3d4e01c4f2fd30ec7bd9e7aa8800a79f13b963879a5065806b80f6fab44ed12b26f1acef7f7ff8f3b42d923123ff896558d0cca84b3cbc85118d
7
- data.tar.gz: 65948021fa19d4140b5e65a7519109f39da8d54977535e669603cd1184a954ac9a2b91fb4122d4f3b8a2b946eb81e0f294acb2efb0d4c7b415c11a939898ea86
6
+ metadata.gz: 6f784654b88fde2321ca8a42495665b23e4b815a36175922bec68fe5b2739f8901ea3e1f0519b0a31357551c67901e985637dc526b6309cbd21fb61457801d59
7
+ data.tar.gz: 784a749e1339cc88f0545aa54d5dd9fa03e15bac08a4d235811b9f3b6abb5ad9e0b42417b9f01041d2fa7614ab09363b8e38bed4f144e59bf7f7ca6f0f790c20
@@ -1,5 +1,5 @@
1
1
  module Avalon
2
2
  module Rails
3
- VERSION = "1.4.7"
3
+ VERSION = "1.4.7.1"
4
4
  end
5
5
  end
@@ -5,7 +5,7 @@
5
5
  http://weibo.com/jslouvre/
6
6
 
7
7
  Released under the MIT license
8
- avalon.js 1.4.7 built in 2015.10.13
8
+ avalon.js 1.4.7.1 built in 2015.11.19
9
9
  support IE6+ and other browsers
10
10
  ==================================================*/
11
11
  (function(global, factory) {
@@ -61,7 +61,6 @@ var ohasOwn = oproto.hasOwnProperty
61
61
  var serialize = oproto.toString
62
62
  var ap = Array.prototype
63
63
  var aslice = ap.slice
64
- var Registry = {} //将函数曝光到此对象上,方便访问器收集依赖
65
64
  var W3C = window.dispatchEvent
66
65
  var root = DOC.documentElement
67
66
  var avalonFragment = DOC.createDocumentFragment()
@@ -302,7 +301,7 @@ function _number(a, len) { //用于模拟slice, splice的效果
302
301
  avalon.mix({
303
302
  rword: rword,
304
303
  subscribers: subscribers,
305
- version: 1.47,
304
+ version: 1.471,
306
305
  ui: {},
307
306
  log: log,
308
307
  slice: W3C ? function (nodes, start, end) {
@@ -1128,7 +1127,7 @@ function modelFactory(source, $special, $model) {
1128
1127
  return collection
1129
1128
  }
1130
1129
  //0 null undefined || Node || VModel(fix IE6-8 createWithProxy $val: val引发的BUG)
1131
- if (!source || source.nodeType > 0 || (source.$id && source.$events)) {
1130
+ if (!source || (source.$id && source.$events) || (source.nodeType > 0 && source.nodeName) ) {
1132
1131
  return source
1133
1132
  }
1134
1133
  var $skipArray = Array.isArray(source.$skipArray) ? source.$skipArray : []
@@ -1321,6 +1320,7 @@ function makeComplexAccessor(name, initValue, valueType, list, parentModel) {
1321
1320
  delete a.$lock
1322
1321
  a._fire("set")
1323
1322
  } else if (valueType === "object") {
1323
+ value = value.$model ? value.$model : value
1324
1324
  var observes = this.$events[name] || []
1325
1325
  var newObject = avalon.mix(true, {}, value)
1326
1326
  for(i in son ){
@@ -1393,7 +1393,7 @@ var isEqual = Object.is || function (v1, v2) {
1393
1393
  }
1394
1394
 
1395
1395
  function isObservable(name, value, $skipArray) {
1396
- if (isFunction(value) || value && value.nodeType) {
1396
+ if (isFunction(value) || value && value.nodeName && (value.nodeType > 0) ) {
1397
1397
  return false
1398
1398
  }
1399
1399
  if ($skipArray.indexOf(name) !== -1) {
@@ -1822,12 +1822,14 @@ avalon.injectBinding = function (data) {
1822
1822
  if(value === void 0){
1823
1823
  delete data.evaluator
1824
1824
  }
1825
- data.handler(value, data.element, data)
1825
+ if (data.handler) {
1826
+ data.handler(value, data.element, data)
1827
+ }
1826
1828
  } catch (e) {
1827
1829
  log("warning:exception throwed in [avalon.injectBinding] " , e)
1828
1830
  delete data.evaluator
1829
1831
  var node = data.element
1830
- if (node.nodeType === 3) {
1832
+ if (node && node.nodeType === 3) {
1831
1833
  var parent = node.parentNode
1832
1834
  if (kernel.commentInterpolate) {
1833
1835
  parent.replaceChild(DOC.createComment(data.value), node)
@@ -2135,30 +2137,30 @@ function camelize(target) {
2135
2137
  return target
2136
2138
  }
2137
2139
  //转换为驼峰风格
2138
- return target.replace(/[-_][^-_]/g, function(match) {
2140
+ return target.replace(/[-_][^-_]/g, function (match) {
2139
2141
  return match.charAt(1).toUpperCase()
2140
2142
  })
2141
2143
  }
2142
2144
 
2143
2145
  var fakeClassListMethods = {
2144
- _toString: function() {
2146
+ _toString: function () {
2145
2147
  var node = this.node
2146
2148
  var cls = node.className
2147
2149
  var str = typeof cls === "string" ? cls : cls.baseVal
2148
2150
  return str.split(/\s+/).join(" ")
2149
2151
  },
2150
- _contains: function(cls) {
2152
+ _contains: function (cls) {
2151
2153
  return (" " + this + " ").indexOf(" " + cls + " ") > -1
2152
2154
  },
2153
- _add: function(cls) {
2155
+ _add: function (cls) {
2154
2156
  if (!this.contains(cls)) {
2155
2157
  this._set(this + " " + cls)
2156
2158
  }
2157
2159
  },
2158
- _remove: function(cls) {
2160
+ _remove: function (cls) {
2159
2161
  this._set((" " + this + " ").replace(" " + cls + " ", " "))
2160
2162
  },
2161
- __set: function(cls) {
2163
+ __set: function (cls) {
2162
2164
  cls = cls.trim()
2163
2165
  var node = this.node
2164
2166
  if (rsvg.test(node)) {
@@ -2170,180 +2172,181 @@ var fakeClassListMethods = {
2170
2172
  } //toggle存在版本差异,因此不使用它
2171
2173
  }
2172
2174
 
2173
- function fakeClassList(node) {
2174
- if (!("classList" in node)) {
2175
- node.classList = {
2176
- node: node
2177
- }
2178
- for (var k in fakeClassListMethods) {
2179
- node.classList[k.slice(1)] = fakeClassListMethods[k]
2180
- }
2175
+ function fakeClassList(node) {
2176
+ if (!("classList" in node)) {
2177
+ node.classList = {
2178
+ node: node
2179
+ }
2180
+ for (var k in fakeClassListMethods) {
2181
+ node.classList[k.slice(1)] = fakeClassListMethods[k]
2181
2182
  }
2182
- return node.classList
2183
2183
  }
2184
+ return node.classList
2185
+ }
2184
2186
 
2185
2187
 
2186
- "add,remove".replace(rword, function(method) {
2187
- avalon.fn[method + "Class"] = function(cls) {
2188
- var el = this[0]
2189
- //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
2190
- if (cls && typeof cls === "string" && el && el.nodeType === 1) {
2191
- cls.replace(/\S+/g, function(c) {
2192
- fakeClassList(el)[method](c)
2193
- })
2194
- }
2195
- return this
2188
+ "add,remove".replace(rword, function (method) {
2189
+ avalon.fn[method + "Class"] = function (cls) {
2190
+ var el = this[0]
2191
+ //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
2192
+ if (cls && typeof cls === "string" && el && el.nodeType === 1) {
2193
+ cls.replace(/\S+/g, function (c) {
2194
+ fakeClassList(el)[method](c)
2195
+ })
2196
2196
  }
2197
- })
2198
- avalon.fn.mix({
2199
- hasClass: function(cls) {
2200
- var el = this[0] || {}
2201
- return el.nodeType === 1 && fakeClassList(el).contains(cls)
2202
- },
2203
- toggleClass: function(value, stateVal) {
2204
- var className, i = 0
2205
- var classNames = String(value).split(/\s+/)
2206
- var isBool = typeof stateVal === "boolean"
2207
- while ((className = classNames[i++])) {
2208
- var state = isBool ? stateVal : !this.hasClass(className)
2209
- this[state ? "addClass" : "removeClass"](className)
2210
- }
2197
+ return this
2198
+ }
2199
+ })
2200
+ avalon.fn.mix({
2201
+ hasClass: function (cls) {
2202
+ var el = this[0] || {}
2203
+ return el.nodeType === 1 && fakeClassList(el).contains(cls)
2204
+ },
2205
+ toggleClass: function (value, stateVal) {
2206
+ var className, i = 0
2207
+ var classNames = String(value).split(/\s+/)
2208
+ var isBool = typeof stateVal === "boolean"
2209
+ while ((className = classNames[i++])) {
2210
+ var state = isBool ? stateVal : !this.hasClass(className)
2211
+ this[state ? "addClass" : "removeClass"](className)
2212
+ }
2213
+ return this
2214
+ },
2215
+ attr: function (name, value) {
2216
+ if (arguments.length === 2) {
2217
+ this[0].setAttribute(name, value)
2211
2218
  return this
2212
- },
2213
- attr: function(name, value) {
2214
- if (arguments.length === 2) {
2215
- this[0].setAttribute(name, value)
2219
+ } else {
2220
+ return this[0].getAttribute(name)
2221
+ }
2222
+ },
2223
+ data: function (name, value) {
2224
+ name = "data-" + hyphen(name || "")
2225
+ switch (arguments.length) {
2226
+ case 2:
2227
+ this.attr(name, value)
2216
2228
  return this
2217
- } else {
2218
- return this[0].getAttribute(name)
2219
- }
2220
- },
2221
- data: function(name, value) {
2222
- name = "data-" + hyphen(name || "")
2223
- switch (arguments.length) {
2224
- case 2:
2225
- this.attr(name, value)
2226
- return this
2227
- case 1:
2228
- var val = this.attr(name)
2229
- return parseData(val)
2230
- case 0:
2231
- var ret = {}
2232
- ap.forEach.call(this[0].attributes, function(attr) {
2233
- if (attr) {
2234
- name = attr.name
2235
- if (!name.indexOf("data-")) {
2236
- name = camelize(name.slice(5))
2237
- ret[name] = parseData(attr.value)
2238
- }
2229
+ case 1:
2230
+ var val = this.attr(name)
2231
+ return parseData(val)
2232
+ case 0:
2233
+ var ret = {}
2234
+ ap.forEach.call(this[0].attributes, function (attr) {
2235
+ if (attr) {
2236
+ name = attr.name
2237
+ if (!name.indexOf("data-")) {
2238
+ name = camelize(name.slice(5))
2239
+ ret[name] = parseData(attr.value)
2239
2240
  }
2240
- })
2241
- return ret
2242
- }
2243
- },
2244
- removeData: function(name) {
2245
- name = "data-" + hyphen(name)
2246
- this[0].removeAttribute(name)
2247
- return this
2248
- },
2249
- css: function(name, value) {
2250
- if (avalon.isPlainObject(name)) {
2251
- for (var i in name) {
2252
- avalon.css(this, i, name[i])
2253
- }
2254
- } else {
2255
- var ret = avalon.css(this, name, value)
2241
+ }
2242
+ })
2243
+ return ret
2244
+ }
2245
+ },
2246
+ removeData: function (name) {
2247
+ name = "data-" + hyphen(name)
2248
+ this[0].removeAttribute(name)
2249
+ return this
2250
+ },
2251
+ css: function (name, value) {
2252
+ if (avalon.isPlainObject(name)) {
2253
+ for (var i in name) {
2254
+ avalon.css(this, i, name[i])
2256
2255
  }
2257
- return ret !== void 0 ? ret : this
2258
- },
2259
- position: function() {
2260
- var offsetParent, offset,
2256
+ } else {
2257
+ var ret = avalon.css(this, name, value)
2258
+ }
2259
+ return ret !== void 0 ? ret : this
2260
+ },
2261
+ position: function () {
2262
+ var offsetParent, offset,
2261
2263
  elem = this[0],
2262
2264
  parentOffset = {
2263
2265
  top: 0,
2264
2266
  left: 0
2265
2267
  }
2266
- if (!elem) {
2267
- return
2268
+ if (!elem) {
2269
+ return
2270
+ }
2271
+ if (this.css("position") === "fixed") {
2272
+ offset = elem.getBoundingClientRect()
2273
+ } else {
2274
+ offsetParent = this.offsetParent() //得到真正的offsetParent
2275
+ offset = this.offset() // 得到正确的offsetParent
2276
+ if (offsetParent[0].tagName !== "HTML") {
2277
+ parentOffset = offsetParent.offset()
2268
2278
  }
2269
- if (this.css("position") === "fixed") {
2270
- offset = elem.getBoundingClientRect()
2271
- } else {
2272
- offsetParent = this.offsetParent() //得到真正的offsetParent
2273
- offset = this.offset() // 得到正确的offsetParent
2274
- if (offsetParent[0].tagName !== "HTML") {
2275
- parentOffset = offsetParent.offset()
2276
- }
2277
- parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true)
2278
- parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true)
2279
+ parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true)
2280
+ parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true)
2279
2281
 
2280
- // Subtract offsetParent scroll positions
2281
- parentOffset.top -= offsetParent.scrollTop()
2282
- parentOffset.left -= offsetParent.scrollLeft()
2283
- }
2284
- return {
2285
- top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true),
2286
- left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true)
2287
- }
2288
- },
2289
- offsetParent: function() {
2290
- var offsetParent = this[0].offsetParent
2291
- while (offsetParent && avalon.css(offsetParent, "position") === "static") {
2292
- offsetParent = offsetParent.offsetParent;
2293
- }
2294
- return avalon(offsetParent || root)
2295
- },
2296
- bind: function(type, fn, phase) {
2297
- if (this[0]) { //此方法不会链
2298
- return avalon.bind(this[0], type, fn, phase)
2299
- }
2300
- },
2301
- unbind: function(type, fn, phase) {
2302
- if (this[0]) {
2303
- avalon.unbind(this[0], type, fn, phase)
2304
- }
2305
- return this
2306
- },
2307
- val: function(value) {
2308
- var node = this[0]
2309
- if (node && node.nodeType === 1) {
2310
- var get = arguments.length === 0
2311
- var access = get ? ":get" : ":set"
2312
- var fn = valHooks[getValType(node) + access]
2313
- if (fn) {
2314
- var val = fn(node, value)
2315
- } else if (get) {
2316
- return (node.value || "").replace(/\r/g, "")
2317
- } else {
2318
- node.value = value
2319
- }
2282
+ // Subtract offsetParent scroll positions
2283
+ parentOffset.top -= offsetParent.scrollTop()
2284
+ parentOffset.left -= offsetParent.scrollLeft()
2285
+ }
2286
+ return {
2287
+ top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true),
2288
+ left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true)
2289
+ }
2290
+ },
2291
+ offsetParent: function () {
2292
+ var offsetParent = this[0].offsetParent
2293
+ while (offsetParent && avalon.css(offsetParent, "position") === "static") {
2294
+ offsetParent = offsetParent.offsetParent;
2295
+ }
2296
+ return avalon(offsetParent || root)
2297
+ },
2298
+ bind: function (type, fn, phase) {
2299
+ if (this[0]) { //此方法不会链
2300
+ return avalon.bind(this[0], type, fn, phase)
2301
+ }
2302
+ },
2303
+ unbind: function (type, fn, phase) {
2304
+ if (this[0]) {
2305
+ avalon.unbind(this[0], type, fn, phase)
2306
+ }
2307
+ return this
2308
+ },
2309
+ val: function (value) {
2310
+ var node = this[0]
2311
+ if (node && node.nodeType === 1) {
2312
+ var get = arguments.length === 0
2313
+ var access = get ? ":get" : ":set"
2314
+ var fn = valHooks[getValType(node) + access]
2315
+ if (fn) {
2316
+ var val = fn(node, value)
2317
+ } else if (get) {
2318
+ return (node.value || "").replace(/\r/g, "")
2319
+ } else {
2320
+ node.value = value
2320
2321
  }
2321
- return get ? val : this
2322
2322
  }
2323
- })
2323
+ return get ? val : this
2324
+ }
2325
+ })
2324
2326
 
2325
- function parseData(data) {
2326
- try {
2327
- if (typeof data === "object")
2328
- return data
2329
- data = data === "true" ? true :
2327
+ function parseData(data) {
2328
+ try {
2329
+ if (typeof data === "object")
2330
+ return data
2331
+ data = data === "true" ? true :
2330
2332
  data === "false" ? false :
2331
2333
  data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? avalon.parseJSON(data) : data
2332
- } catch (e) {}
2333
- return data
2334
+ } catch (e) {
2334
2335
  }
2336
+ return data
2337
+ }
2335
2338
  var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
2336
- rvalidchars = /^[\],:{}\s]*$/,
2337
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
2338
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
2339
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g
2340
- avalon.parseJSON = window.JSON ? JSON.parse : function(data) {
2339
+ rvalidchars = /^[\],:{}\s]*$/,
2340
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
2341
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
2342
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g
2343
+ avalon.parseJSON = window.JSON ? JSON.parse : function (data) {
2341
2344
  if (typeof data === "string") {
2342
2345
  data = data.trim();
2343
2346
  if (data) {
2344
2347
  if (rvalidchars.test(data.replace(rvalidescape, "@")
2345
- .replace(rvalidtokens, "]")
2346
- .replace(rvalidbraces, ""))) {
2348
+ .replace(rvalidtokens, "]")
2349
+ .replace(rvalidbraces, ""))) {
2347
2350
  return (new Function("return " + data))() // jshint ignore:line
2348
2351
  }
2349
2352
  }
@@ -2351,15 +2354,30 @@ avalon.parseJSON = window.JSON ? JSON.parse : function(data) {
2351
2354
  }
2352
2355
  return data
2353
2356
  }
2357
+ avalon.fireDom = function (elem, type, opts) {
2358
+ if (DOC.createEvent) {
2359
+ var hackEvent = DOC.createEvent("Events");
2360
+ hackEvent.initEvent(type, true, true)
2361
+ avalon.mix(hackEvent, opts)
2362
+ elem.dispatchEvent(hackEvent)
2363
+ } else {
2364
+ try {
2365
+ hackEvent = DOC.createEventObject()
2366
+ avalon.mix(hackEvent, opts)
2367
+ elem.fireEvent("on" + type, hackEvent)
2368
+ } catch (e) {//IE6-8触发事件必须保证在DOM树中,否则报"SCRIPT16389: 未指明的错误"
2369
+ }
2370
+ }
2371
+ }
2354
2372
 
2355
2373
  //生成avalon.fn.scrollLeft, avalon.fn.scrollTop方法
2356
2374
  avalon.each({
2357
2375
  scrollLeft: "pageXOffset",
2358
2376
  scrollTop: "pageYOffset"
2359
- }, function(method, prop) {
2360
- avalon.fn[method] = function(val) {
2377
+ }, function (method, prop) {
2378
+ avalon.fn[method] = function (val) {
2361
2379
  var node = this[0] || {}, win = getWindow(node),
2362
- top = method === "scrollTop"
2380
+ top = method === "scrollTop"
2363
2381
  if (!arguments.length) {
2364
2382
  return win ? (prop in win) ? win[prop] : root[method] : node[method]
2365
2383
  } else {
@@ -2383,7 +2401,7 @@ var cssMap = {
2383
2401
  }
2384
2402
  avalon.cssNumber = oneObject("animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
2385
2403
 
2386
- avalon.cssName = function(name, host, camelCase) {
2404
+ avalon.cssName = function (name, host, camelCase) {
2387
2405
  if (cssMap[name]) {
2388
2406
  return cssMap[name]
2389
2407
  }
@@ -2396,26 +2414,27 @@ avalon.cssName = function(name, host, camelCase) {
2396
2414
  }
2397
2415
  return null
2398
2416
  }
2399
- cssHooks["@:set"] = function(node, name, value) {
2417
+ cssHooks["@:set"] = function (node, name, value) {
2400
2418
  try { //node.style.width = NaN;node.style.width = "xxxxxxx";node.style.width = undefine 在旧式IE下会抛异常
2401
2419
  node.style[name] = value
2402
- } catch (e) {}
2420
+ } catch (e) {
2421
+ }
2403
2422
  }
2404
2423
  if (window.getComputedStyle) {
2405
- cssHooks["@:get"] = function(node, name) {
2424
+ cssHooks["@:get"] = function (node, name) {
2406
2425
  if (!node || !node.style) {
2407
2426
  throw new Error("getComputedStyle要求传入一个节点 " + node)
2408
2427
  }
2409
2428
  var ret, styles = getComputedStyle(node, null)
2410
- if (styles) {
2411
- ret = name === "filter" ? styles.getPropertyValue(name) : styles[name]
2412
- if (ret === "") {
2413
- ret = node.style[name] //其他浏览器需要我们手动取内联样式
2414
- }
2429
+ if (styles) {
2430
+ ret = name === "filter" ? styles.getPropertyValue(name) : styles[name]
2431
+ if (ret === "") {
2432
+ ret = node.style[name] //其他浏览器需要我们手动取内联样式
2415
2433
  }
2434
+ }
2416
2435
  return ret
2417
2436
  }
2418
- cssHooks["opacity:get"] = function(node) {
2437
+ cssHooks["opacity:get"] = function (node) {
2419
2438
  var ret = cssHooks["@:get"](node, "opacity")
2420
2439
  return ret === "" ? "1" : ret
2421
2440
  }
@@ -2423,31 +2442,31 @@ if (window.getComputedStyle) {
2423
2442
  var rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i
2424
2443
  var rposition = /^(top|right|bottom|left)$/
2425
2444
  var ralpha = /alpha\([^)]*\)/i
2426
- var ie8 = !! window.XDomainRequest
2445
+ var ie8 = !!window.XDomainRequest
2427
2446
  var salpha = "DXImageTransform.Microsoft.Alpha"
2428
2447
  var border = {
2429
2448
  thin: ie8 ? '1px' : '2px',
2430
2449
  medium: ie8 ? '3px' : '4px',
2431
2450
  thick: ie8 ? '5px' : '6px'
2432
2451
  }
2433
- cssHooks["@:get"] = function(node, name) {
2452
+ cssHooks["@:get"] = function (node, name) {
2434
2453
  //取得精确值,不过它有可能是带em,pc,mm,pt,%等单位
2435
2454
  var currentStyle = node.currentStyle
2436
2455
  var ret = currentStyle[name]
2437
2456
  if ((rnumnonpx.test(ret) && !rposition.test(ret))) {
2438
2457
  //①,保存原有的style.left, runtimeStyle.left,
2439
2458
  var style = node.style,
2440
- left = style.left,
2441
- rsLeft = node.runtimeStyle.left
2442
- //②由于③处的style.left = xxx会影响到currentStyle.left,
2443
- //因此把它currentStyle.left放到runtimeStyle.left,
2444
- //runtimeStyle.left拥有最高优先级,不会style.left影响
2445
- node.runtimeStyle.left = currentStyle.left
2446
- //③将精确值赋给到style.left,然后通过IE的另一个私有属性 style.pixelLeft
2447
- //得到单位为px的结果;fontSize的分支见http://bugs.jquery.com/ticket/760
2448
- style.left = name === 'fontSize' ? '1em' : (ret || 0)
2449
- ret = style.pixelLeft + "px"
2450
- //④还原 style.left,runtimeStyle.left
2459
+ left = style.left,
2460
+ rsLeft = node.runtimeStyle.left
2461
+ //②由于③处的style.left = xxx会影响到currentStyle.left,
2462
+ //因此把它currentStyle.left放到runtimeStyle.left,
2463
+ //runtimeStyle.left拥有最高优先级,不会style.left影响
2464
+ node.runtimeStyle.left = currentStyle.left
2465
+ //③将精确值赋给到style.left,然后通过IE的另一个私有属性 style.pixelLeft
2466
+ //得到单位为px的结果;fontSize的分支见http://bugs.jquery.com/ticket/760
2467
+ style.left = name === 'fontSize' ? '1em' : (ret || 0)
2468
+ ret = style.pixelLeft + "px"
2469
+ //④还原 style.left,runtimeStyle.left
2451
2470
  style.left = left
2452
2471
  node.runtimeStyle.left = rsLeft
2453
2472
  }
@@ -2460,7 +2479,7 @@ if (window.getComputedStyle) {
2460
2479
  }
2461
2480
  return ret === "" ? "auto" : border[ret] || ret
2462
2481
  }
2463
- cssHooks["opacity:set"] = function(node, name, value) {
2482
+ cssHooks["opacity:set"] = function (node, name, value) {
2464
2483
  var style = node.style
2465
2484
  var opacity = isFinite(value) && value <= 1 ? "alpha(opacity=" + value * 100 + ")" : ""
2466
2485
  var filter = style.filter || "";
@@ -2468,25 +2487,25 @@ if (window.getComputedStyle) {
2468
2487
  //不能使用以下方式设置透明度
2469
2488
  //node.filters.alpha.opacity = value * 100
2470
2489
  style.filter = (ralpha.test(filter) ?
2471
- filter.replace(ralpha, opacity) :
2472
- filter + " " + opacity).trim()
2490
+ filter.replace(ralpha, opacity) :
2491
+ filter + " " + opacity).trim()
2473
2492
  if (!style.filter) {
2474
2493
  style.removeAttribute("filter")
2475
2494
  }
2476
2495
  }
2477
- cssHooks["opacity:get"] = function(node) {
2496
+ cssHooks["opacity:get"] = function (node) {
2478
2497
  //这是最快的获取IE透明值的方式,不需要动用正则了!
2479
2498
  var alpha = node.filters.alpha || node.filters[salpha],
2480
- op = alpha && alpha.enabled ? alpha.opacity : 100
2499
+ op = alpha && alpha.enabled ? alpha.opacity : 100
2481
2500
  return (op / 100) + "" //确保返回的是字符串
2482
2501
  }
2483
2502
  }
2484
2503
 
2485
- "top,left".replace(rword, function(name) {
2486
- cssHooks[name + ":get"] = function(node) {
2504
+ "top,left".replace(rword, function (name) {
2505
+ cssHooks[name + ":get"] = function (node) {
2487
2506
  var computed = cssHooks["@:get"](node, name)
2488
2507
  return /px$/.test(computed) ? computed :
2489
- avalon(node).position()[name] + "px"
2508
+ avalon(node).position()[name] + "px"
2490
2509
  }
2491
2510
  })
2492
2511
 
@@ -2498,147 +2517,147 @@ var cssShow = {
2498
2517
 
2499
2518
  var rdisplayswap = /^(none|table(?!-c[ea]).+)/
2500
2519
 
2501
- function showHidden(node, array) {
2502
- //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
2503
- if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
2504
- if (rdisplayswap.test(cssHooks["@:get"](node, "display"))) {
2505
- var obj = {
2506
- node: node
2507
- }
2508
- for (var name in cssShow) {
2509
- obj[name] = node.style[name]
2510
- node.style[name] = cssShow[name]
2511
- }
2512
- array.push(obj)
2520
+ function showHidden(node, array) {
2521
+ //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
2522
+ if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
2523
+ if (rdisplayswap.test(cssHooks["@:get"](node, "display"))) {
2524
+ var obj = {
2525
+ node: node
2513
2526
  }
2514
- var parent = node.parentNode
2515
- if (parent && parent.nodeType === 1) {
2516
- showHidden(parent, array)
2527
+ for (var name in cssShow) {
2528
+ obj[name] = node.style[name]
2529
+ node.style[name] = cssShow[name]
2517
2530
  }
2531
+ array.push(obj)
2532
+ }
2533
+ var parent = node.parentNode
2534
+ if (parent && parent.nodeType === 1) {
2535
+ showHidden(parent, array)
2518
2536
  }
2519
2537
  }
2520
- "Width,Height".replace(rword, function(name) { //fix 481
2521
- var method = name.toLowerCase(),
2538
+ }
2539
+ "Width,Height".replace(rword, function (name) { //fix 481
2540
+ var method = name.toLowerCase(),
2522
2541
  clientProp = "client" + name,
2523
2542
  scrollProp = "scroll" + name,
2524
2543
  offsetProp = "offset" + name
2525
- cssHooks[method + ":get"] = function(node, which, override) {
2526
- var boxSizing = -4
2527
- if (typeof override === "number") {
2528
- boxSizing = override
2529
- }
2530
- which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
2531
- var ret = node[offsetProp] // border-box 0
2532
- if (boxSizing === 2) { // margin-box 2
2533
- return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true)
2534
- }
2535
- if (boxSizing < 0) { // padding-box -2
2536
- ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true)
2537
- }
2538
- if (boxSizing === -4) { // content-box -4
2539
- ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true)
2540
- }
2541
- return ret
2542
- }
2543
- cssHooks[method + "&get"] = function(node) {
2544
- var hidden = [];
2545
- showHidden(node, hidden);
2546
- var val = cssHooks[method + ":get"](node)
2547
- for (var i = 0, obj; obj = hidden[i++];) {
2548
- node = obj.node
2549
- for (var n in obj) {
2550
- if (typeof obj[n] === "string") {
2551
- node.style[n] = obj[n]
2552
- }
2553
- }
2554
- }
2555
- return val;
2544
+ cssHooks[method + ":get"] = function (node, which, override) {
2545
+ var boxSizing = -4
2546
+ if (typeof override === "number") {
2547
+ boxSizing = override
2556
2548
  }
2557
- avalon.fn[method] = function(value) { //会忽视其display
2558
- var node = this[0]
2559
- if (arguments.length === 0) {
2560
- if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
2561
- return node["inner" + name] || node.document.documentElement[clientProp] ||
2562
- node.document.body[clientProp]//IE6下前两个分别为undefine,0
2563
- }
2564
- if (node.nodeType === 9) { //取得页面尺寸
2565
- var doc = node.documentElement
2566
- //FF chrome html.scrollHeight< body.scrollHeight
2567
- //IE 标准模式 : html.scrollHeight> body.scrollHeight
2568
- //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
2569
- return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
2549
+ which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
2550
+ var ret = node[offsetProp] // border-box 0
2551
+ if (boxSizing === 2) { // margin-box 2
2552
+ return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true)
2553
+ }
2554
+ if (boxSizing < 0) { // padding-box -2
2555
+ ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true)
2556
+ }
2557
+ if (boxSizing === -4) { // content-box -4
2558
+ ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true)
2559
+ }
2560
+ return ret
2561
+ }
2562
+ cssHooks[method + "&get"] = function (node) {
2563
+ var hidden = [];
2564
+ showHidden(node, hidden);
2565
+ var val = cssHooks[method + ":get"](node)
2566
+ for (var i = 0, obj; obj = hidden[i++]; ) {
2567
+ node = obj.node
2568
+ for (var n in obj) {
2569
+ if (typeof obj[n] === "string") {
2570
+ node.style[n] = obj[n]
2570
2571
  }
2571
- return cssHooks[method + "&get"](node)
2572
- } else {
2573
- return this.css(method, value)
2574
2572
  }
2575
2573
  }
2576
- avalon.fn["inner" + name] = function() {
2577
- return cssHooks[method + ":get"](this[0], void 0, -2)
2578
- }
2579
- avalon.fn["outer" + name] = function(includeMargin) {
2580
- return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
2574
+ return val;
2575
+ }
2576
+ avalon.fn[method] = function (value) { //会忽视其display
2577
+ var node = this[0]
2578
+ if (arguments.length === 0) {
2579
+ if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
2580
+ return node["inner" + name] || node.document.documentElement[clientProp] ||
2581
+ node.document.body[clientProp]//IE6下前两个分别为undefine,0
2582
+ }
2583
+ if (node.nodeType === 9) { //取得页面尺寸
2584
+ var doc = node.documentElement
2585
+ //FF chrome html.scrollHeight< body.scrollHeight
2586
+ //IE 标准模式 : html.scrollHeight> body.scrollHeight
2587
+ //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
2588
+ return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
2589
+ }
2590
+ return cssHooks[method + "&get"](node)
2591
+ } else {
2592
+ return this.css(method, value)
2581
2593
  }
2582
- })
2583
- avalon.fn.offset = function() { //取得距离页面左右角的坐标
2584
- var node = this[0],
2594
+ }
2595
+ avalon.fn["inner" + name] = function () {
2596
+ return cssHooks[method + ":get"](this[0], void 0, -2)
2597
+ }
2598
+ avalon.fn["outer" + name] = function (includeMargin) {
2599
+ return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
2600
+ }
2601
+ })
2602
+ avalon.fn.offset = function () { //取得距离页面左右角的坐标
2603
+ var node = this[0],
2585
2604
  box = {
2586
2605
  left: 0,
2587
2606
  top: 0
2588
2607
  }
2589
- if (!node || !node.tagName || !node.ownerDocument) {
2590
- return box
2591
- }
2592
- var doc = node.ownerDocument,
2608
+ if (!node || !node.tagName || !node.ownerDocument) {
2609
+ return box
2610
+ }
2611
+ var doc = node.ownerDocument,
2593
2612
  body = doc.body,
2594
2613
  root = doc.documentElement,
2595
2614
  win = doc.defaultView || doc.parentWindow
2596
- if (!avalon.contains(root, node)) {
2597
- return box
2598
- }
2599
- //http://hkom.blog1.fc2.com/?mode=m&no=750 body的偏移量是不包含margin的
2600
- //我们可以通过getBoundingClientRect来获得元素相对于client的rect.
2601
- //http://msdn.microsoft.com/en-us/library/ms536433.aspx
2602
- if (node.getBoundingClientRect) {
2603
- box = node.getBoundingClientRect() // BlackBerry 5, iOS 3 (original iPhone)
2604
- }
2605
- //chrome/IE6: body.scrollTop, firefox/other: root.scrollTop
2606
- var clientTop = root.clientTop || body.clientTop,
2615
+ if (!avalon.contains(root, node)) {
2616
+ return box
2617
+ }
2618
+ //http://hkom.blog1.fc2.com/?mode=m&no=750 body的偏移量是不包含margin的
2619
+ //我们可以通过getBoundingClientRect来获得元素相对于client的rect.
2620
+ //http://msdn.microsoft.com/en-us/library/ms536433.aspx
2621
+ if (node.getBoundingClientRect) {
2622
+ box = node.getBoundingClientRect() // BlackBerry 5, iOS 3 (original iPhone)
2623
+ }
2624
+ //chrome/IE6: body.scrollTop, firefox/other: root.scrollTop
2625
+ var clientTop = root.clientTop || body.clientTop,
2607
2626
  clientLeft = root.clientLeft || body.clientLeft,
2608
2627
  scrollTop = Math.max(win.pageYOffset || 0, root.scrollTop, body.scrollTop),
2609
2628
  scrollLeft = Math.max(win.pageXOffset || 0, root.scrollLeft, body.scrollLeft)
2610
- // 把滚动距离加到left,top中去。
2611
- // IE一些版本中会自动为HTML元素加上2px的border,我们需要去掉它
2612
- // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx
2613
- return {
2614
- top: box.top + scrollTop - clientTop,
2615
- left: box.left + scrollLeft - clientLeft
2616
- }
2629
+ // 把滚动距离加到left,top中去。
2630
+ // IE一些版本中会自动为HTML元素加上2px的border,我们需要去掉它
2631
+ // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx
2632
+ return {
2633
+ top: box.top + scrollTop - clientTop,
2634
+ left: box.left + scrollLeft - clientLeft
2617
2635
  }
2636
+ }
2618
2637
 
2619
- //==================================val相关============================
2638
+ //==================================val相关============================
2620
2639
 
2621
- function getValType(elem) {
2622
- var ret = elem.tagName.toLowerCase()
2623
- return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret
2624
- }
2640
+ function getValType(elem) {
2641
+ var ret = elem.tagName.toLowerCase()
2642
+ return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret
2643
+ }
2625
2644
  var roption = /^<option(?:\s+\w+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?)*\s+value[\s=]/i
2626
2645
  var valHooks = {
2627
- "option:get": IEVersion ? function(node) {
2646
+ "option:get": IEVersion ? function (node) {
2628
2647
  //在IE11及W3C,如果没有指定value,那么node.value默认为node.text(存在trim作),但IE9-10则是取innerHTML(没trim操作)
2629
2648
  //specified并不可靠,因此通过分析outerHTML判定用户有没有显示定义value
2630
2649
  return roption.test(node.outerHTML) ? node.value : node.text.trim()
2631
- } : function(node) {
2650
+ } : function (node) {
2632
2651
  return node.value
2633
2652
  },
2634
- "select:get": function(node, value) {
2653
+ "select:get": function (node, value) {
2635
2654
  var option, options = node.options,
2636
- index = node.selectedIndex,
2637
- getter = valHooks["option:get"],
2638
- one = node.type === "select-one" || index < 0,
2639
- values = one ? null : [],
2640
- max = one ? index + 1 : options.length,
2641
- i = index < 0 ? max : one ? index : 0
2655
+ index = node.selectedIndex,
2656
+ getter = valHooks["option:get"],
2657
+ one = node.type === "select-one" || index < 0,
2658
+ values = one ? null : [],
2659
+ max = one ? index + 1 : options.length,
2660
+ i = index < 0 ? max : one ? index : 0
2642
2661
  for (; i < max; i++) {
2643
2662
  option = options[i]
2644
2663
  //旧式IE在reset后不会改变selected,需要改用i === index判定
@@ -2655,10 +2674,10 @@ var valHooks = {
2655
2674
  }
2656
2675
  return values
2657
2676
  },
2658
- "select:set": function(node, values, optionSet) {
2677
+ "select:set": function (node, values, optionSet) {
2659
2678
  values = [].concat(values) //强制转换为数组
2660
2679
  var getter = valHooks["option:get"]
2661
- for (var i = 0, el; el = node.options[i++];) {
2680
+ for (var i = 0, el; el = node.options[i++]; ) {
2662
2681
  if ((el.selected = values.indexOf(getter(el)) > -1)) {
2663
2682
  optionSet = true
2664
2683
  }
@@ -3410,6 +3429,10 @@ bindingExecutors.attr = function (val, elem, data) {
3410
3429
  var replace = data.includeReplace
3411
3430
  var target = replace ? elem.parentNode : elem
3412
3431
  var scanTemplate = function (text) {
3432
+ if (data.vmodels === null) {
3433
+ return
3434
+ }
3435
+
3413
3436
  if (loaded) {
3414
3437
  var newText = loaded.apply(target, [text].concat(vmodels))
3415
3438
  if (typeof newText === "string")
@@ -3429,7 +3452,7 @@ bindingExecutors.attr = function (val, elem, data) {
3429
3452
  }
3430
3453
  }
3431
3454
  data.includeLastID = val
3432
- while (true) {
3455
+ while (data.startInclude) {
3433
3456
  var node = data.startInclude.nextSibling
3434
3457
  if (node && node !== data.endInclude) {
3435
3458
  target.removeChild(node)
@@ -3770,7 +3793,7 @@ new function() { // jshint ignore:line
3770
3793
  var bproto = HTMLTextAreaElement.prototype
3771
3794
  function newSetter(value) { // jshint ignore:line
3772
3795
  setters[this.tagName].call(this, value)
3773
- if (!this.msFocus && this.avalonSetter && this.oldValue !== value) {
3796
+ if (!this.msFocus && this.avalonSetter) {
3774
3797
  this.avalonSetter()
3775
3798
  }
3776
3799
  }
@@ -3794,18 +3817,18 @@ new function() { // jshint ignore:line
3794
3817
  } // jshint ignore:line
3795
3818
  if (IEVersion) {
3796
3819
  avalon.bind(DOC, "selectionchange", function (e) {
3797
- var el = DOC.activeElement
3798
- if (el && typeof el.avalonSetter === "function") {
3820
+ var el = DOC.activeElement || {}
3821
+ if (!el.msFocus && el.avalonSetter) {
3799
3822
  el.avalonSetter()
3800
3823
  }
3801
3824
  })
3802
3825
  }
3803
-
3826
+ var rnoduplex = /^(file|button|reset|submit|checkbox|radio|range)$/
3804
3827
  //处理radio, checkbox, text, textarea, password
3805
- duplexBinding.INPUT = function (element, evaluator, data) {
3806
- var $type = element.type,
3828
+ duplexBinding.INPUT = function (elem, evaluator, data) {
3829
+ var $type = elem.type,
3807
3830
  bound = data.bound,
3808
- $elem = avalon(element),
3831
+ $elem = avalon(elem),
3809
3832
  composing = false
3810
3833
 
3811
3834
  function callback(value) {
@@ -3819,74 +3842,90 @@ duplexBinding.INPUT = function (element, evaluator, data) {
3819
3842
  function compositionEnd() {
3820
3843
  composing = false
3821
3844
  }
3845
+ var IE9Value
3822
3846
  //当value变化时改变model的值
3823
3847
  var updateVModel = function () {
3824
- var val = element.value //防止递归调用形成死循环
3825
- if (composing || val === element.oldValue) //处理中文输入法在minlengh下引发的BUG
3848
+ var val = elem.value //防止递归调用形成死循环
3849
+ if (composing || val === IE9Value) //处理中文输入法在minlengh下引发的BUG
3826
3850
  return
3827
3851
  var lastValue = data.pipe(val, data, "get")
3828
3852
  if ($elem.data("duplexObserve") !== false) {
3853
+ IE9Value = val
3829
3854
  evaluator(lastValue)
3830
- callback.call(element, lastValue)
3855
+ callback.call(elem, lastValue)
3831
3856
  }
3832
3857
  }
3833
3858
  //当model变化时,它就会改变value的值
3834
3859
  data.handler = function () {
3835
- var val = data.pipe(evaluator(), data, "set") //fix #673
3836
- if (val !== element.oldValue) {
3837
- element.value = element.oldValue = val
3860
+ var val = data.pipe(evaluator(), data, "set") //fix #673 #1106
3861
+ if (val !== IE9Value) {
3862
+ var fixCaret = false
3863
+ if (elem.msFocus) {
3864
+ try {
3865
+ var pos = getCaret(elem)
3866
+ if (pos.start === pos.end) {
3867
+ pos = pos.start
3868
+ fixCaret = true
3869
+ }
3870
+ } catch (e) {
3871
+ }
3872
+ }
3873
+ elem.value = IE9Value = val
3874
+ if (fixCaret && !elem.readyOnly) {
3875
+ setCaret(elem, pos, pos)
3876
+ }
3838
3877
  }
3839
3878
  }
3840
3879
  if (data.isChecked || $type === "radio") {
3841
3880
  var IE6 = IEVersion === 6
3842
3881
  updateVModel = function () {
3843
3882
  if ($elem.data("duplexObserve") !== false) {
3844
- var lastValue = data.pipe(element.value, data, "get")
3883
+ var lastValue = data.pipe(elem.value, data, "get")
3845
3884
  evaluator(lastValue)
3846
- callback.call(element, lastValue)
3885
+ callback.call(elem, lastValue)
3847
3886
  }
3848
3887
  }
3849
3888
  data.handler = function () {
3850
3889
  var val = evaluator()
3851
- var checked = data.isChecked ? !!val : val + "" === element.value
3852
- element.oldValue = checked
3890
+ var checked = data.isChecked ? !!val : val + "" === elem.value
3891
+ elem.oldValue = checked
3853
3892
  if (IE6) {
3854
3893
  setTimeout(function () {
3855
3894
  //IE8 checkbox, radio是使用defaultChecked控制选中状态,
3856
3895
  //并且要先设置defaultChecked后设置checked
3857
3896
  //并且必须设置延迟
3858
- element.defaultChecked = checked
3859
- element.checked = checked
3897
+ elem.defaultChecked = checked
3898
+ elem.checked = checked
3860
3899
  }, 31)
3861
3900
  } else {
3862
- element.checked = checked
3901
+ elem.checked = checked
3863
3902
  }
3864
3903
  }
3865
3904
  bound("click", updateVModel)
3866
3905
  } else if ($type === "checkbox") {
3867
3906
  updateVModel = function () {
3868
3907
  if ($elem.data("duplexObserve") !== false) {
3869
- var method = element.checked ? "ensure" : "remove"
3908
+ var method = elem.checked ? "ensure" : "remove"
3870
3909
  var array = evaluator()
3871
3910
  if (!Array.isArray(array)) {
3872
3911
  log("ms-duplex应用于checkbox上要对应一个数组")
3873
3912
  array = [array]
3874
3913
  }
3875
- var val = data.pipe(element.value, data, "get")
3914
+ var val = data.pipe(elem.value, data, "get")
3876
3915
  avalon.Array[method](array, val)
3877
- callback.call(element, array)
3916
+ callback.call(elem, array)
3878
3917
  }
3879
3918
  }
3880
3919
 
3881
3920
  data.handler = function () {
3882
3921
  var array = [].concat(evaluator()) //强制转换为数组
3883
- var val = data.pipe(element.value, data, "get")
3884
- element.checked = array.indexOf(val) > -1
3922
+ var val = data.pipe(elem.value, data, "get")
3923
+ elem.checked = array.indexOf(val) > -1
3885
3924
  }
3886
3925
  bound(W3C ? "change" : "click", updateVModel)
3887
3926
  } else {
3888
- var events = element.getAttribute("data-duplex-event") || "input"
3889
- if (element.attributes["data-event"]) {
3927
+ var events = elem.getAttribute("data-duplex-event") || "input"
3928
+ if (elem.attributes["data-event"]) {
3890
3929
  log("data-event指令已经废弃,请改用data-duplex-event")
3891
3930
  }
3892
3931
 
@@ -3904,12 +3943,19 @@ duplexBinding.INPUT = function (element, evaluator, data) {
3904
3943
  bound("compositionstart", compositionStart)
3905
3944
  bound("compositionend", compositionEnd)
3906
3945
  bound("DOMAutoComplete", updateVModel)
3907
- } else { //onpropertychange事件无法区分是程序触发还是用户触发
3946
+ } else {
3908
3947
  // IE下通过selectionchange事件监听IE9+点击input右边的X的清空行为,及粘贴,剪切,删除行为
3909
3948
  if (IEVersion > 8) {
3910
- bound("input", updateVModel) //IE9使用propertychange无法监听中文输入改动
3949
+ if(IEVersion === 9){
3950
+ //IE9删除字符后再失去焦点不会同步 #1167
3951
+ bound("keyup", updateVModel)
3952
+ }
3953
+ //IE9使用propertychange无法监听中文输入改动
3954
+ bound("input", updateVModel)
3911
3955
  } else {
3912
- bound("propertychange", function (e) { //IE6-8下第一次修改时不会触发,需要使用keydown或selectionchange修正
3956
+ //onpropertychange事件无法区分是程序触发还是用户触发
3957
+ //IE6-8下第一次修改时不会触发,需要使用keydown或selectionchange修正
3958
+ bound("propertychange", function (e) {
3913
3959
  if (e.propertyName === "value") {
3914
3960
  updateVModel()
3915
3961
  }
@@ -3925,32 +3971,65 @@ duplexBinding.INPUT = function (element, evaluator, data) {
3925
3971
  break
3926
3972
  }
3927
3973
  })
3928
- bound("focus", function () {
3929
- element.msFocus = true
3930
- })
3931
- bound("blur", function () {
3932
- element.msFocus = false
3933
- })
3934
3974
 
3935
- if (!/^(file|button|reset|submit|checkbox|radio)$/.test(element.type)) {
3936
- element.avalonSetter = updateVModel //#765
3975
+
3976
+ if (!rnoduplex.test(elem.type)) {
3977
+ if (elem.type !== "hidden") {
3978
+ bound("focus", function () {
3979
+ elem.msFocus = true
3980
+ })
3981
+ bound("blur", function () {
3982
+ elem.msFocus = false
3983
+ })
3984
+ }
3985
+
3986
+ elem.avalonSetter = updateVModel //#765
3937
3987
  watchValueInTimer(function () {
3938
- if (root.contains(element)) {
3939
- if (!element.msFocus && element.oldValue !== element.value) {
3988
+ if (root.contains(elem)) {
3989
+ if (!elem.msFocus ) {
3940
3990
  updateVModel()
3941
3991
  }
3942
- } else if (!element.msRetain) {
3992
+ } else if (!elem.msRetain) {
3943
3993
  return false
3944
3994
  }
3945
3995
  })
3946
3996
  }
3947
-
3997
+
3948
3998
  }
3949
3999
 
3950
4000
  avalon.injectBinding(data)
3951
- callback.call(element, element.value)
4001
+ callback.call(elem, elem.value)
3952
4002
  }
3953
4003
  duplexBinding.TEXTAREA = duplexBinding.INPUT
4004
+ function getCaret(ctrl) {
4005
+ var start = NaN, end = NaN
4006
+ //https://github.com/RobinHerbots/jquery.inputmask/blob/3.x/js/inputmask.js#L1736
4007
+ if (ctrl.setSelectionRange) {
4008
+ start = ctrl.selectionStart
4009
+ end = ctrl.selectionEnd
4010
+ } else {
4011
+ var range = document.selection.createRange()
4012
+ start = 0 - range.duplicate().moveStart('character', -100000)
4013
+ end = start + range.text.length
4014
+ }
4015
+ return {
4016
+ start: start,
4017
+ end: end
4018
+ }
4019
+ }
4020
+ function setCaret(ctrl, begin, end) {
4021
+ if (!ctrl.value || ctrl.readOnly)
4022
+ return
4023
+ if (ctrl.createTextRange) {//IE6-8
4024
+ var range = ctrl.createTextRange()
4025
+ range.collapse(true)
4026
+ range.moveStart("character", begin)
4027
+ range.select()
4028
+ } else {
4029
+ ctrl.selectionStart = begin
4030
+ ctrl.selectionEnd = end
4031
+ }
4032
+ }
3954
4033
  duplexBinding.SELECT = function(element, evaluator, data) {
3955
4034
  var $elem = avalon(element)
3956
4035
 
@@ -4158,8 +4237,10 @@ bindingHandlers.repeat = function (data, vmodels) {
4158
4237
  }
4159
4238
  }
4160
4239
 
4240
+ var oldHandler = data.handler
4161
4241
  data.handler = noop
4162
4242
  avalon.injectBinding(data)
4243
+ data.handler = oldHandler
4163
4244
 
4164
4245
  var elem = data.element
4165
4246
  if (elem.nodeType === 1) {
@@ -4658,7 +4739,7 @@ bindingHandlers.widget = function(data, vmodels) {
4658
4739
  options.onInit.call(elem, vmodel, options, vmodels)
4659
4740
  }
4660
4741
  })
4661
- } catch (e) {}
4742
+ } catch (e) {log(e)}
4662
4743
  data.rollback = function() {
4663
4744
  try {
4664
4745
  vmodel.$remove()