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