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.
@@ -5,7 +5,7 @@
5
5
  http://weibo.com/jslouvre/
6
6
 
7
7
  Released under the MIT license
8
- avalon.modern.js 1.4.7 built in 2015.10.13
8
+ avalon.modern.js 1.4.7.1 built in 2015.11.19
9
9
  support IE10+ and other browsers
10
10
  ==================================================*/
11
11
  (function(global, factory) {
@@ -70,7 +70,6 @@ var ohasOwn = oproto.hasOwnProperty
70
70
  var serialize = oproto.toString
71
71
  var ap = Array.prototype
72
72
  var aslice = ap.slice
73
- var Registry = {} //将函数曝光到此对象上,方便访问器收集依赖
74
73
  var W3C = window.dispatchEvent
75
74
  var root = DOC.documentElement
76
75
  var avalonFragment = DOC.createDocumentFragment()
@@ -265,7 +264,7 @@ function _number(a, len) { //用于模拟slice, splice的效果
265
264
  avalon.mix({
266
265
  rword: rword,
267
266
  subscribers: subscribers,
268
- version: 1.47,
267
+ version: 1.471,
269
268
  ui: {},
270
269
  log: log,
271
270
  slice: function (nodes, start, end) {
@@ -856,7 +855,7 @@ function modelFactory(source, $special, $model) {
856
855
  return collection
857
856
  }
858
857
  //0 null undefined || Node || VModel(fix IE6-8 createWithProxy $val: val引发的BUG)
859
- if (!source || source.nodeType > 0 || (source.$id && source.$events)) {
858
+ if (!source || (source.$id && source.$events) || (source.nodeName && source.nodeType > 0) ) {
860
859
  return source
861
860
  }
862
861
  var $skipArray = Array.isArray(source.$skipArray) ? source.$skipArray : []
@@ -1049,6 +1048,7 @@ function makeComplexAccessor(name, initValue, valueType, list, parentModel) {
1049
1048
  delete a.$lock
1050
1049
  a._fire("set")
1051
1050
  } else if (valueType === "object") {
1051
+ value = value.$model ? value.$model : value
1052
1052
  var observes = this.$events[name] || []
1053
1053
  var newObject = avalon.mix(true, {}, value)
1054
1054
  for (i in son) {
@@ -1122,7 +1122,7 @@ var isEqual = Object.is || function (v1, v2) {
1122
1122
  }
1123
1123
 
1124
1124
  function isObservable(name, value, $skipArray) {
1125
- if (isFunction(value) || value && value.nodeType) {
1125
+ if (isFunction(value) || value && value.nodeName && (value.nodeType > 0)) {
1126
1126
  return false
1127
1127
  }
1128
1128
  if ($skipArray.indexOf(name) !== -1) {
@@ -1439,12 +1439,14 @@ avalon.injectBinding = function (data) {
1439
1439
  if(value === void 0){
1440
1440
  delete data.evaluator
1441
1441
  }
1442
- data.handler(value, data.element, data)
1442
+ if (data.handler) {
1443
+ data.handler(value, data.element, data)
1444
+ }
1443
1445
  } catch (e) {
1444
1446
  log("warning:exception throwed in [avalon.injectBinding] " , e)
1445
1447
  delete data.evaluator
1446
1448
  var node = data.element
1447
- if (node.nodeType === 3) {
1449
+ if (node && node.nodeType === 3) {
1448
1450
  var parent = node.parentNode
1449
1451
  if (kernel.commentInterpolate) {
1450
1452
  parent.replaceChild(DOC.createComment(data.value), node)
@@ -1696,17 +1698,17 @@ function camelize(target) {
1696
1698
  if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
1697
1699
  return target //提前判断,提高getStyle等的效率
1698
1700
  }
1699
- return target.replace(/[-_][^-_]/g, function(match) {
1701
+ return target.replace(/[-_][^-_]/g, function (match) {
1700
1702
  return match.charAt(1).toUpperCase()
1701
1703
  })
1702
1704
  }
1703
1705
 
1704
- "add,remove".replace(rword, function(method) {
1705
- avalon.fn[method + "Class"] = function(cls) {
1706
+ "add,remove".replace(rword, function (method) {
1707
+ avalon.fn[method + "Class"] = function (cls) {
1706
1708
  var el = this[0]
1707
1709
  //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
1708
1710
  if (cls && typeof cls === "string" && el && el.nodeType === 1) {
1709
- cls.replace(/\S+/g, function(c) {
1711
+ cls.replace(/\S+/g, function (c) {
1710
1712
  el.classList[method](c)
1711
1713
  })
1712
1714
  }
@@ -1715,11 +1717,11 @@ function camelize(target) {
1715
1717
  })
1716
1718
 
1717
1719
  avalon.fn.mix({
1718
- hasClass: function(cls) {
1720
+ hasClass: function (cls) {
1719
1721
  var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0
1720
1722
  return el.nodeType === 1 && el.classList.contains(cls)
1721
1723
  },
1722
- toggleClass: function(value, stateVal) {
1724
+ toggleClass: function (value, stateVal) {
1723
1725
  var className, i = 0
1724
1726
  var classNames = String(value).split(/\s+/)
1725
1727
  var isBool = typeof stateVal === "boolean"
@@ -1729,7 +1731,7 @@ avalon.fn.mix({
1729
1731
  }
1730
1732
  return this
1731
1733
  },
1732
- attr: function(name, value) {
1734
+ attr: function (name, value) {
1733
1735
  if (arguments.length === 2) {
1734
1736
  this[0].setAttribute(name, value)
1735
1737
  return this
@@ -1737,7 +1739,7 @@ avalon.fn.mix({
1737
1739
  return this[0].getAttribute(name)
1738
1740
  }
1739
1741
  },
1740
- data: function(name, value) {
1742
+ data: function (name, value) {
1741
1743
  name = "data-" + hyphen(name || "")
1742
1744
  switch (arguments.length) {
1743
1745
  case 2:
@@ -1748,7 +1750,7 @@ avalon.fn.mix({
1748
1750
  return parseData(val)
1749
1751
  case 0:
1750
1752
  var ret = {}
1751
- ap.forEach.call(this[0].attributes, function(attr) {
1753
+ ap.forEach.call(this[0].attributes, function (attr) {
1752
1754
  if (attr) {
1753
1755
  name = attr.name
1754
1756
  if (!name.indexOf("data-")) {
@@ -1760,12 +1762,12 @@ avalon.fn.mix({
1760
1762
  return ret
1761
1763
  }
1762
1764
  },
1763
- removeData: function(name) {
1765
+ removeData: function (name) {
1764
1766
  name = "data-" + hyphen(name)
1765
1767
  this[0].removeAttribute(name)
1766
1768
  return this
1767
1769
  },
1768
- css: function(name, value) {
1770
+ css: function (name, value) {
1769
1771
  if (avalon.isPlainObject(name)) {
1770
1772
  for (var i in name) {
1771
1773
  avalon.css(this, i, name[i])
@@ -1775,13 +1777,13 @@ avalon.fn.mix({
1775
1777
  }
1776
1778
  return ret !== void 0 ? ret : this
1777
1779
  },
1778
- position: function() {
1780
+ position: function () {
1779
1781
  var offsetParent, offset,
1780
- elem = this[0],
1781
- parentOffset = {
1782
- top: 0,
1783
- left: 0
1784
- };
1782
+ elem = this[0],
1783
+ parentOffset = {
1784
+ top: 0,
1785
+ left: 0
1786
+ };
1785
1787
  if (!elem) {
1786
1788
  return
1787
1789
  }
@@ -1804,25 +1806,25 @@ avalon.fn.mix({
1804
1806
  left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true)
1805
1807
  }
1806
1808
  },
1807
- offsetParent: function() {
1809
+ offsetParent: function () {
1808
1810
  var offsetParent = this[0].offsetParent
1809
1811
  while (offsetParent && avalon.css(offsetParent, "position") === "static") {
1810
1812
  offsetParent = offsetParent.offsetParent;
1811
1813
  }
1812
1814
  return avalon(offsetParent || root)
1813
1815
  },
1814
- bind: function(type, fn, phase) {
1816
+ bind: function (type, fn, phase) {
1815
1817
  if (this[0]) { //此方法不会链
1816
1818
  return avalon.bind(this[0], type, fn, phase)
1817
1819
  }
1818
1820
  },
1819
- unbind: function(type, fn, phase) {
1821
+ unbind: function (type, fn, phase) {
1820
1822
  if (this[0]) {
1821
1823
  avalon.unbind(this[0], type, fn, phase)
1822
1824
  }
1823
1825
  return this
1824
1826
  },
1825
- val: function(value) {
1827
+ val: function (value) {
1826
1828
  var node = this[0]
1827
1829
  if (node && node.nodeType === 1) {
1828
1830
  var get = arguments.length === 0
@@ -1841,7 +1843,7 @@ avalon.fn.mix({
1841
1843
  })
1842
1844
 
1843
1845
  if (root.dataset) {
1844
- avalon.fn.data = function(name, val) {
1846
+ avalon.fn.data = function (name, val) {
1845
1847
  name = name && camelize(name)
1846
1848
  var dataset = this[0].dataset
1847
1849
  switch (arguments.length) {
@@ -1868,18 +1870,26 @@ function parseData(data) {
1868
1870
  if (typeof data === "object")
1869
1871
  return data
1870
1872
  data = data === "true" ? true :
1871
- data === "false" ? false :
1872
- data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data
1873
- } catch (e) {}
1873
+ data === "false" ? false :
1874
+ data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data
1875
+ } catch (e) {
1876
+ }
1874
1877
  return data
1875
1878
  }
1879
+
1880
+ avalon.fireDom = function (elem, type, opts) {
1881
+ var hackEvent = DOC.createEvent("Events");
1882
+ hackEvent.initEvent(type, true, true)
1883
+ avalon.mix(hackEvent, opts)
1884
+ elem.dispatchEvent(hackEvent)
1885
+ }
1876
1886
  avalon.each({
1877
1887
  scrollLeft: "pageXOffset",
1878
1888
  scrollTop: "pageYOffset"
1879
- }, function(method, prop) {
1880
- avalon.fn[method] = function(val) {
1889
+ }, function (method, prop) {
1890
+ avalon.fn[method] = function (val) {
1881
1891
  var node = this[0] || {}, win = getWindow(node),
1882
- top = method === "scrollTop"
1892
+ top = method === "scrollTop"
1883
1893
  if (!arguments.length) {
1884
1894
  return win ? win[prop] : node[method]
1885
1895
  } else {
@@ -1904,7 +1914,7 @@ var cssMap = {
1904
1914
  }
1905
1915
  avalon.cssNumber = oneObject("animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
1906
1916
 
1907
- avalon.cssName = function(name, host, camelCase) {
1917
+ avalon.cssName = function (name, host, camelCase) {
1908
1918
  if (cssMap[name]) {
1909
1919
  return cssMap[name]
1910
1920
  }
@@ -1917,33 +1927,33 @@ avalon.cssName = function(name, host, camelCase) {
1917
1927
  }
1918
1928
  return null
1919
1929
  }
1920
- cssHooks["@:set"] = function(node, name, value) {
1930
+ cssHooks["@:set"] = function (node, name, value) {
1921
1931
  node.style[name] = value
1922
1932
  }
1923
1933
 
1924
- cssHooks["@:get"] = function(node, name) {
1934
+ cssHooks["@:get"] = function (node, name) {
1925
1935
  if (!node || !node.style) {
1926
1936
  throw new Error("getComputedStyle要求传入一个节点 " + node)
1927
1937
  }
1928
1938
  var ret, computed = getComputedStyle(node)
1929
- if (computed) {
1930
- ret = name === "filter" ? computed.getPropertyValue(name) : computed[name]
1931
- if (ret === "") {
1932
- ret = node.style[name] //其他浏览器需要我们手动取内联样式
1933
- }
1939
+ if (computed) {
1940
+ ret = name === "filter" ? computed.getPropertyValue(name) : computed[name]
1941
+ if (ret === "") {
1942
+ ret = node.style[name] //其他浏览器需要我们手动取内联样式
1934
1943
  }
1944
+ }
1935
1945
  return ret
1936
1946
  }
1937
- cssHooks["opacity:get"] = function(node) {
1947
+ cssHooks["opacity:get"] = function (node) {
1938
1948
  var ret = cssHooks["@:get"](node, "opacity")
1939
1949
  return ret === "" ? "1" : ret
1940
1950
  }
1941
1951
 
1942
- "top,left".replace(rword, function(name) {
1943
- cssHooks[name + ":get"] = function(node) {
1952
+ "top,left".replace(rword, function (name) {
1953
+ cssHooks[name + ":get"] = function (node) {
1944
1954
  var computed = cssHooks["@:get"](node, name)
1945
1955
  return /px$/.test(computed) ? computed :
1946
- avalon(node).position()[name] + "px"
1956
+ avalon(node).position()[name] + "px"
1947
1957
  }
1948
1958
  })
1949
1959
  var cssShow = {
@@ -1953,125 +1963,125 @@ var cssShow = {
1953
1963
  }
1954
1964
  var rdisplayswap = /^(none|table(?!-c[ea]).+)/
1955
1965
 
1956
- function showHidden(node, array) {
1957
- //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
1958
- if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
1959
- var styles = getComputedStyle(node, null)
1960
- if (rdisplayswap.test(styles["display"])) {
1961
- var obj = {
1962
- node: node
1963
- }
1964
- for (var name in cssShow) {
1965
- obj[name] = styles[name]
1966
- node.style[name] = cssShow[name]
1967
- }
1968
- array.push(obj)
1966
+ function showHidden(node, array) {
1967
+ //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
1968
+ if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
1969
+ var styles = getComputedStyle(node, null)
1970
+ if (rdisplayswap.test(styles["display"])) {
1971
+ var obj = {
1972
+ node: node
1969
1973
  }
1970
- var parent = node.parentNode
1971
- if (parent && parent.nodeType === 1) {
1972
- showHidden(parent, array)
1974
+ for (var name in cssShow) {
1975
+ obj[name] = styles[name]
1976
+ node.style[name] = cssShow[name]
1973
1977
  }
1978
+ array.push(obj)
1979
+ }
1980
+ var parent = node.parentNode
1981
+ if (parent && parent.nodeType === 1) {
1982
+ showHidden(parent, array)
1974
1983
  }
1975
1984
  }
1985
+ }
1976
1986
 
1977
- "Width,Height".replace(rword, function(name) { //fix 481
1978
- var method = name.toLowerCase(),
1987
+ "Width,Height".replace(rword, function (name) { //fix 481
1988
+ var method = name.toLowerCase(),
1979
1989
  clientProp = "client" + name,
1980
1990
  scrollProp = "scroll" + name,
1981
1991
  offsetProp = "offset" + name
1982
- cssHooks[method + ":get"] = function(node, which, override) {
1983
- var boxSizing = -4
1984
- if (typeof override === "number") {
1985
- boxSizing = override
1986
- }
1987
- which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
1988
- var ret = node[offsetProp] // border-box 0
1989
- if (boxSizing === 2) { // margin-box 2
1990
- return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true)
1991
- }
1992
- if (boxSizing < 0) { // padding-box -2
1993
- ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true)
1994
- }
1995
- if (boxSizing === -4) { // content-box -4
1996
- ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true)
1997
- }
1998
- return ret
1999
- }
2000
- cssHooks[method + "&get"] = function(node) {
2001
- var hidden = [];
2002
- showHidden(node, hidden);
2003
- var val = cssHooks[method + ":get"](node)
2004
- for (var i = 0, obj; obj = hidden[i++];) {
2005
- node = obj.node
2006
- for (var n in obj) {
2007
- if (typeof obj[n] === "string") {
2008
- node.style[n] = obj[n]
2009
- }
2010
- }
2011
- }
2012
- return val;
1992
+ cssHooks[method + ":get"] = function (node, which, override) {
1993
+ var boxSizing = -4
1994
+ if (typeof override === "number") {
1995
+ boxSizing = override
2013
1996
  }
2014
- avalon.fn[method] = function(value) { //会忽视其display
2015
- var node = this[0]
2016
- if (arguments.length === 0) {
2017
- if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
2018
- return node["inner" + name]
2019
- }
2020
- if (node.nodeType === 9) { //取得页面尺寸
2021
- var doc = node.documentElement
2022
- //FF chrome html.scrollHeight< body.scrollHeight
2023
- //IE 标准模式 : html.scrollHeight> body.scrollHeight
2024
- //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
2025
- return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
2026
- }
2027
- return cssHooks[method + "&get"](node)
2028
- } else {
2029
- return this.css(method, value)
2030
- }
1997
+ which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
1998
+ var ret = node[offsetProp] // border-box 0
1999
+ if (boxSizing === 2) { // margin-box 2
2000
+ return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true)
2031
2001
  }
2032
- avalon.fn["inner" + name] = function() {
2033
- return cssHooks[method + ":get"](this[0], void 0, -2)
2002
+ if (boxSizing < 0) { // padding-box -2
2003
+ ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true)
2034
2004
  }
2035
- avalon.fn["outer" + name] = function(includeMargin) {
2036
- return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
2005
+ if (boxSizing === -4) { // content-box -4
2006
+ ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true)
2037
2007
  }
2038
- })
2039
- avalon.fn.offset = function() { //取得距离页面左右角的坐标
2040
- var node = this[0]
2041
- try {
2042
- var rect = node.getBoundingClientRect()
2043
- // Make sure element is not hidden (display: none) or disconnected
2044
- // https://github.com/jquery/jquery/pull/2043/files#r23981494
2045
- if (rect.width || rect.height || node.getClientRects().length) {
2046
- var doc = node.ownerDocument
2047
- var root = doc.documentElement
2048
- var win = doc.defaultView
2049
- return {
2050
- top: rect.top + win.pageYOffset - root.clientTop,
2051
- left: rect.left + win.pageXOffset - root.clientLeft
2008
+ return ret
2009
+ }
2010
+ cssHooks[method + "&get"] = function (node) {
2011
+ var hidden = [];
2012
+ showHidden(node, hidden);
2013
+ var val = cssHooks[method + ":get"](node)
2014
+ for (var i = 0, obj; obj = hidden[i++]; ) {
2015
+ node = obj.node
2016
+ for (var n in obj) {
2017
+ if (typeof obj[n] === "string") {
2018
+ node.style[n] = obj[n]
2052
2019
  }
2053
2020
  }
2054
- } catch (e) {
2021
+ }
2022
+ return val;
2023
+ }
2024
+ avalon.fn[method] = function (value) { //会忽视其display
2025
+ var node = this[0]
2026
+ if (arguments.length === 0) {
2027
+ if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
2028
+ return node["inner" + name]
2029
+ }
2030
+ if (node.nodeType === 9) { //取得页面尺寸
2031
+ var doc = node.documentElement
2032
+ //FF chrome html.scrollHeight< body.scrollHeight
2033
+ //IE 标准模式 : html.scrollHeight> body.scrollHeight
2034
+ //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
2035
+ return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
2036
+ }
2037
+ return cssHooks[method + "&get"](node)
2038
+ } else {
2039
+ return this.css(method, value)
2040
+ }
2041
+ }
2042
+ avalon.fn["inner" + name] = function () {
2043
+ return cssHooks[method + ":get"](this[0], void 0, -2)
2044
+ }
2045
+ avalon.fn["outer" + name] = function (includeMargin) {
2046
+ return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
2047
+ }
2048
+ })
2049
+ avalon.fn.offset = function () { //取得距离页面左右角的坐标
2050
+ var node = this[0]
2051
+ try {
2052
+ var rect = node.getBoundingClientRect()
2053
+ // Make sure element is not hidden (display: none) or disconnected
2054
+ // https://github.com/jquery/jquery/pull/2043/files#r23981494
2055
+ if (rect.width || rect.height || node.getClientRects().length) {
2056
+ var doc = node.ownerDocument
2057
+ var root = doc.documentElement
2058
+ var win = doc.defaultView
2055
2059
  return {
2056
- left: 0,
2057
- top: 0
2060
+ top: rect.top + win.pageYOffset - root.clientTop,
2061
+ left: rect.left + win.pageXOffset - root.clientLeft
2058
2062
  }
2059
2063
  }
2064
+ } catch (e) {
2065
+ return {
2066
+ left: 0,
2067
+ top: 0
2068
+ }
2060
2069
  }
2061
- //=============================val相关=======================
2070
+ }
2071
+ //=============================val相关=======================
2062
2072
 
2063
- function getValType(elem) {
2064
- var ret = elem.tagName.toLowerCase()
2065
- return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret
2066
- }
2073
+ function getValType(elem) {
2074
+ var ret = elem.tagName.toLowerCase()
2075
+ return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret
2076
+ }
2067
2077
  var valHooks = {
2068
- "select:get": function(node, value) {
2078
+ "select:get": function (node, value) {
2069
2079
  var option, options = node.options,
2070
- index = node.selectedIndex,
2071
- one = node.type === "select-one" || index < 0,
2072
- values = one ? null : [],
2073
- max = one ? index + 1 : options.length,
2074
- i = index < 0 ? max : one ? index : 0
2080
+ index = node.selectedIndex,
2081
+ one = node.type === "select-one" || index < 0,
2082
+ values = one ? null : [],
2083
+ max = one ? index + 1 : options.length,
2084
+ i = index < 0 ? max : one ? index : 0
2075
2085
  for (; i < max; i++) {
2076
2086
  option = options[i]
2077
2087
  //旧式IE在reset后不会改变selected,需要改用i === index判定
@@ -2088,9 +2098,9 @@ var valHooks = {
2088
2098
  }
2089
2099
  return values
2090
2100
  },
2091
- "select:set": function(node, values, optionSet) {
2101
+ "select:set": function (node, values, optionSet) {
2092
2102
  values = [].concat(values) //强制转换为数组
2093
- for (var i = 0, el; el = node.options[i++];) {
2103
+ for (var i = 0, el; el = node.options[i++]; ) {
2094
2104
  if ((el.selected = values.indexOf(el.value) > -1)) {
2095
2105
  optionSet = true
2096
2106
  }
@@ -2773,6 +2783,10 @@ bindingExecutors.attr = function (val, elem, data) {
2773
2783
  var replace = data.includeReplace
2774
2784
  var target = replace ? elem.parentNode : elem
2775
2785
  var scanTemplate = function (text) {
2786
+ if (data.vmodels === null) {
2787
+ return
2788
+ }
2789
+
2776
2790
  if (loaded) {
2777
2791
  var newText = loaded.apply(target, [text].concat(vmodels))
2778
2792
  if (typeof newText === "string")
@@ -2792,7 +2806,7 @@ bindingExecutors.attr = function (val, elem, data) {
2792
2806
  }
2793
2807
  }
2794
2808
  data.includeLastID = val
2795
- while (true) {
2809
+ while (data.startInclude) {
2796
2810
  var node = data.startInclude.nextSibling
2797
2811
  if (node && node !== data.endInclude) {
2798
2812
  target.removeChild(node)
@@ -3133,7 +3147,7 @@ new function() { // jshint ignore:line
3133
3147
  var bproto = HTMLTextAreaElement.prototype
3134
3148
  function newSetter(value) { // jshint ignore:line
3135
3149
  setters[this.tagName].call(this, value)
3136
- if (!this.msFocus && this.avalonSetter && this.oldValue !== value) {
3150
+ if (!this.msFocus && this.avalonSetter) {
3137
3151
  this.avalonSetter()
3138
3152
  }
3139
3153
  }
@@ -3155,88 +3169,106 @@ new function() { // jshint ignore:line
3155
3169
  watchValueInTimer = avalon.tick
3156
3170
  }
3157
3171
  } // jshint ignore:line
3172
+ var rnoduplex = /^(file|button|reset|submit|checkbox|radio|range)$/
3158
3173
  //处理radio, checkbox, text, textarea, password
3159
- duplexBinding.INPUT = function(element, evaluator, data) {
3160
- var $type = element.type,
3161
- bound = data.bound,
3162
- $elem = avalon(element),
3163
- composing = false
3164
-
3165
- function callback(value) {
3166
- data.changed.call(this, value, data)
3167
- }
3174
+ duplexBinding.INPUT = function (elem, evaluator, data) {
3175
+ var $type = elem.type,
3176
+ bound = data.bound,
3177
+ $elem = avalon(elem),
3178
+ composing = false
3168
3179
 
3169
- function compositionStart() {
3170
- composing = true
3171
- }
3180
+ function callback(value) {
3181
+ data.changed.call(this, value, data)
3182
+ }
3172
3183
 
3173
- function compositionEnd() {
3174
- composing = false
3175
- }
3176
- //当value变化时改变model的值
3184
+ function compositionStart() {
3185
+ composing = true
3186
+ }
3177
3187
 
3178
- var updateVModel = function() {
3179
- var val = element.value //防止递归调用形成死循环
3180
- if (composing || val === element.oldValue) //处理中文输入法在minlengh下引发的BUG
3188
+ function compositionEnd() {
3189
+ composing = false
3190
+ }
3191
+ //当value变化时改变model的值
3192
+ var IE9Value
3193
+ var updateVModel = function () {
3194
+ var val = elem.value //防止递归调用形成死循环
3195
+ if (composing || val === IE9Value) //处理中文输入法在minlengh下引发的BUG
3181
3196
  return
3182
3197
  var lastValue = data.pipe(val, data, "get")
3183
3198
  if ($elem.data("duplexObserve") !== false) {
3199
+ IE9Value = val
3184
3200
  evaluator(lastValue)
3185
- callback.call(element, lastValue)
3201
+ callback.call(elem, lastValue)
3186
3202
  }
3187
3203
  }
3188
3204
  //当model变化时,它就会改变value的值
3189
- data.handler = function() {
3190
- var val = data.pipe(evaluator(), data, "set")
3191
- if (val !== element.oldValue) {
3192
- element.value = element.oldValue = val
3205
+ data.handler = function () {
3206
+ var val = data.pipe(evaluator(), data, "set")
3207
+ if (val !== IE9Value) {
3208
+ var fixCaret = false
3209
+ if (elem.msFocus) {
3210
+ try {
3211
+ var start = elem.selectionStart
3212
+ var end = elem.selectionEnd
3213
+ if (start === end) {
3214
+ var pos = start
3215
+ fixCaret = true
3216
+ }
3217
+ } catch (e) {
3218
+ }
3219
+ }
3220
+ elem.value = IE9Value = val
3221
+ if (fixCaret && !elem.readyOnly) {
3222
+ elem.selectionStart = elem.selectionEnd = pos
3223
+ }
3193
3224
  }
3194
3225
  }
3195
3226
  if (data.isChecked || $type === "radio") {
3196
- updateVModel = function() {
3227
+ updateVModel = function () {
3197
3228
  if ($elem.data("duplexObserve") !== false) {
3198
- var lastValue = data.pipe(element.value, data, "get")
3229
+ var lastValue = data.pipe(elem.value, data, "get")
3199
3230
  evaluator(lastValue)
3200
- callback.call(element, lastValue)
3231
+ callback.call(elem, lastValue)
3201
3232
  }
3202
3233
  }
3203
- data.handler = function() {
3234
+ data.handler = function () {
3204
3235
  var val = evaluator()
3205
- var checked = data.isChecked ? !! val : val + "" === element.value
3206
- element.checked = element.oldValue = checked
3236
+ var checked = data.isChecked ? !!val : val + "" === elem.value
3237
+ elem.checked = elem.oldValue = checked
3207
3238
  }
3208
3239
  bound("click", updateVModel)
3209
3240
  } else if ($type === "checkbox") {
3210
- updateVModel = function() {
3241
+ updateVModel = function () {
3211
3242
  if ($elem.data("duplexObserve") !== false) {
3212
- var method = element.checked ? "ensure" : "remove"
3243
+ var method = elem.checked ? "ensure" : "remove"
3213
3244
  var array = evaluator()
3214
3245
  if (!Array.isArray(array)) {
3215
3246
  log("ms-duplex应用于checkbox上要对应一个数组")
3216
3247
  array = [array]
3217
3248
  }
3218
- avalon.Array[method](array, data.pipe(element.value, data, "get"))
3219
- callback.call(element, array)
3249
+ avalon.Array[method](array, data.pipe(elem.value, data, "get"))
3250
+ callback.call(elem, array)
3220
3251
  }
3221
3252
  }
3222
- data.handler = function() {
3253
+ data.handler = function () {
3223
3254
  var array = [].concat(evaluator()) //强制转换为数组
3224
- element.checked = array.indexOf(data.pipe(element.value, data, "get")) > -1
3255
+ elem.checked = array.indexOf(data.pipe(elem.value, data, "get")) > -1
3225
3256
  }
3226
3257
  bound("change", updateVModel)
3227
3258
  } else {
3228
- var events = element.getAttribute("data-duplex-event") || "input"
3229
- if (element.attributes["data-event"]) {
3259
+ var events = elem.getAttribute("data-duplex-event") || "input"
3260
+ if (elem.attributes["data-event"]) {
3230
3261
  log("data-event指令已经废弃,请改用data-duplex-event")
3231
3262
  }
3232
- events.replace(rword, function(name) {
3263
+ events.replace(rword, function (name) {
3233
3264
  switch (name) {
3234
3265
  case "input":
3235
3266
  bound("input", updateVModel)
3236
- bound("DOMAutoComplete", updateVModel)
3267
+ bound("keyup", updateVModel)
3237
3268
  if (!IEVersion) {
3238
3269
  bound("compositionstart", compositionStart)
3239
3270
  bound("compositionend", compositionEnd)
3271
+ bound("DOMAutoComplete", updateVModel)
3240
3272
  }
3241
3273
  break
3242
3274
  default:
@@ -3244,29 +3276,30 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3244
3276
  break
3245
3277
  }
3246
3278
  })
3247
- bound("focus", function() {
3248
- element.msFocus = true
3249
- })
3250
- bound("blur", function() {
3251
- element.msFocus = false
3252
- })
3253
- if (!/^(file|button|reset|submit|checkbox|radio)$/.test(element.type)) {
3254
- element.avalonSetter = updateVModel //#765
3279
+
3280
+ if (!rnoduplex.test($type)) {
3281
+ if ($type !== "hidden") {
3282
+ bound("focus", function () {
3283
+ elem.msFocus = true
3284
+ })
3285
+ bound("blur", function () {
3286
+ elem.msFocus = false
3287
+ })
3288
+ }
3289
+ elem.avalonSetter = updateVModel //#765
3255
3290
  watchValueInTimer(function () {
3256
- if (root.contains(element)) {
3257
- if (!element.msFocus && data.oldValue !== element.value) {
3291
+ if (root.contains(elem)) {
3292
+ if (!elem.msFocus) {
3258
3293
  updateVModel()
3259
3294
  }
3260
- } else if (!element.msRetain) {
3295
+ } else if (!elem.msRetain) {
3261
3296
  return false
3262
3297
  }
3263
3298
  })
3264
3299
  }
3265
3300
  }
3266
-
3267
-
3268
3301
  avalon.injectBinding(data)
3269
- callback.call(element, element.value)
3302
+ callback.call(elem, elem.value)
3270
3303
  }
3271
3304
  duplexBinding.TEXTAREA = duplexBinding.INPUT
3272
3305
  duplexBinding.SELECT = function(element, evaluator, data) {
@@ -3476,8 +3509,10 @@ bindingHandlers.repeat = function (data, vmodels) {
3476
3509
  }
3477
3510
  }
3478
3511
 
3512
+ var oldHandler = data.handler
3479
3513
  data.handler = noop
3480
3514
  avalon.injectBinding(data)
3515
+ data.handler = oldHandler
3481
3516
 
3482
3517
  var elem = data.element
3483
3518
  if (elem.nodeType === 1) {
@@ -3972,7 +4007,7 @@ bindingHandlers.widget = function(data, vmodels) {
3972
4007
  options.onInit.call(elem, vmodel, options, vmodels)
3973
4008
  }
3974
4009
  })
3975
- } catch (e) {}
4010
+ } catch (e) {log(e)}
3976
4011
  data.rollback = function() {
3977
4012
  try {
3978
4013
  vmodel.$remove()