avalon-rails 1.3.9.1 → 1.3.9.1.20150212184918

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: 0037e91deb9ccc8430cbe38729d2898cdec7b3b6
4
- data.tar.gz: 9c730ce5621b99d513d76a869b5ae8c170a77e3a
3
+ metadata.gz: ed801cfd8f10b5d5e8c22716fc0c7c31888d4ba9
4
+ data.tar.gz: ccfa1fb5357c02ea306286f143468f96a9f64421
5
5
  SHA512:
6
- metadata.gz: 0816bf3c1dd1fb7a7bba9908e772dd5b2232423dd32597183af5589ee628e6361a29431a933a0191c3a5c18dc84311422f59c470f39fbdbdaefd3ee4c25d9b9e
7
- data.tar.gz: 31e6f343d168a6090d584625e1aa41a7225b8d666abfe94b01f15c1787796cda756534881ed6fbce392c8551832bb00a74ab886aad984f586e2cf4417e5590da
6
+ metadata.gz: 9d0e70c173180ebadc019ff5dacd67e6fc04cef5c1f27b17c93b8b89898802ad4a273fc12f268e4505abd721edd1fbfc16195295241104497a6bc54ac349863f
7
+ data.tar.gz: a4bfabe15172bf4be49d772544fa53f952e0050f7f3fe6a809edc0667f64c7186d80daec5a985f33303fc98ccdf3754f3c26c06e9784f405748aa6d7c526371b
@@ -1,5 +1,5 @@
1
1
  module Avalon
2
2
  module Rails
3
- VERSION = "1.3.9.1"
3
+ VERSION = "1.3.9.1.20150212184918"
4
4
  end
5
5
  end
@@ -5,8 +5,7 @@
5
5
  http://weibo.com/jslouvre/
6
6
 
7
7
  Released under the MIT license
8
- avalon.js 1.391 build in 2015.1.31
9
- ____________________________________
8
+ avalon.js 1.391 built in 2015.2.12
10
9
  support IE6+ and other browsers
11
10
  ==================================================*/
12
11
  (function(global, factory) {
@@ -34,13 +33,14 @@ ____________________________________
34
33
  /*********************************************************************
35
34
  * 全局变量及方法 *
36
35
  **********************************************************************/
37
- var expose = new Date - 0
36
+ var expose = new Date() - 0
38
37
  //http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function
39
38
  var DOC = window.document
40
39
  var head = DOC.getElementsByTagName("head")[0] //HEAD元素
41
40
  var ifGroup = head.insertBefore(document.createElement("avalon"), head.firstChild) //避免IE6 base标签BUG
42
41
  ifGroup.innerHTML = "X<style id='avalonStyle'>.avalonHide{ display: none!important }</style>"
43
42
  ifGroup.setAttribute("ms-skip", "1")
43
+ ifGroup.className = "avalonHide"
44
44
  var rnative = /\[native code\]/ //判定是否原生函数
45
45
  function log() {
46
46
  if (window.console && avalon.config.debug) {
@@ -143,7 +143,7 @@ var isFunction = typeof alert === "object" ? function(fn) {
143
143
  return false
144
144
  }
145
145
  } : function(fn) {
146
- return serialize.call(fn) == "[object Function]"
146
+ return serialize.call(fn) === "[object Function]"
147
147
  }
148
148
  avalon.isFunction = isFunction
149
149
 
@@ -305,7 +305,7 @@ avalon.mix({
305
305
  }
306
306
  var index = -1,
307
307
  length = Math.max(0, Math.ceil((end - start) / step)),
308
- result = Array(length)
308
+ result = new Array(length)
309
309
  while (++index < length) {
310
310
  result[index] = start
311
311
  start += step
@@ -352,10 +352,10 @@ avalon.mix({
352
352
  if (node instanceof avalon) {
353
353
  node = node[0]
354
354
  }
355
- var prop = /[_-]/.test(name) ? camelize(name) : name
355
+ var prop = /[_-]/.test(name) ? camelize(name) : name, fn
356
356
  name = avalon.cssName(prop) || prop
357
357
  if (value === void 0 || typeof value === "boolean") { //获取样式
358
- var fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
358
+ fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
359
359
  if (name === "background") {
360
360
  name = "backgroundColor"
361
361
  }
@@ -446,7 +446,7 @@ function isArrayLike(obj) {
446
446
  }
447
447
  return true
448
448
  } catch (e) { //IE的NodeList直接抛错
449
- return !obj.eval //IE6-8 window
449
+ return !obj.window //IE6-8 window
450
450
  }
451
451
  }
452
452
  return false
@@ -691,7 +691,7 @@ function fixEvent(event) {
691
691
  ret.wheelDeltaY = ret.wheelDelta
692
692
  ret.wheelDeltaX = 0
693
693
  }
694
- ret.timeStamp = new Date - 0
694
+ ret.timeStamp = new Date() - 0
695
695
  ret.originalEvent = event
696
696
  ret.preventDefault = function() { //阻止默认行为
697
697
  event.returnValue = false
@@ -873,7 +873,7 @@ var EventBus = {
873
873
  return this
874
874
  },
875
875
  $fire: function(type) {
876
- var special
876
+ var special, i, v, callback
877
877
  if (/^(\w+)!(\S+)$/.test(type)) {
878
878
  special = RegExp.$1
879
879
  type = RegExp.$2
@@ -882,8 +882,8 @@ var EventBus = {
882
882
  var args = aslice.call(arguments, 1)
883
883
  var detail = [type].concat(args)
884
884
  if (special === "all") {
885
- for (var i in avalon.vmodels) {
886
- var v = avalon.vmodels[i]
885
+ for (i in avalon.vmodels) {
886
+ v = avalon.vmodels[i]
887
887
  if (v !== this) {
888
888
  v.$fire.apply(v, detail)
889
889
  }
@@ -892,8 +892,8 @@ var EventBus = {
892
892
  var elements = events.expr ? findNodes(events.expr) : []
893
893
  if (elements.length === 0)
894
894
  return
895
- for (var i in avalon.vmodels) {
896
- var v = avalon.vmodels[i]
895
+ for (i in avalon.vmodels) {
896
+ v = avalon.vmodels[i]
897
897
  if (v !== this) {
898
898
  if (v.$events.expr) {
899
899
  var eventNodes = findNodes(v.$events.expr)
@@ -926,19 +926,19 @@ var EventBus = {
926
926
  if (special === "up") {
927
927
  alls.reverse()
928
928
  }
929
- for (var i = 0, el; el = alls[i++]; ) {
930
- if (el.$fire.apply(el, detail) === false) {
929
+ for (i = 0; callback = alls[i++]; ) {
930
+ if (callback.$fire.apply(callback, detail) === false) {
931
931
  break
932
932
  }
933
933
  }
934
934
  } else {
935
935
  var callbacks = events[type] || []
936
936
  var all = events.$all || []
937
- for (var i = 0, callback; callback = callbacks[i++]; ) {
937
+ for (i = 0; callback = callbacks[i++]; ) {
938
938
  if (isFunction(callback))
939
939
  callback.apply(this, args)
940
940
  }
941
- for (var i = 0, callback; callback = all[i++]; ) {
941
+ for (i = 0; callback = all[i++]; ) {
942
942
  if (isFunction(callback))
943
943
  callback.apply(this, arguments)
944
944
  }
@@ -1116,7 +1116,7 @@ function modelFactory(source, $special, $model) {
1116
1116
  } else {
1117
1117
  if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性
1118
1118
  //计算属性不需要收集视图刷新函数,都是由其他监控属性代劳
1119
- var newValue = accessor.get.call($vmodel)
1119
+ newValue = accessor.get.call($vmodel)
1120
1120
  if (oldValue !== newValue) {
1121
1121
  $model[name] = newValue
1122
1122
  //这里不用同步视图
@@ -1148,12 +1148,12 @@ function modelFactory(source, $special, $model) {
1148
1148
  initCallbacks.push(function() {
1149
1149
  var data = {
1150
1150
  evaluator: function() {
1151
- data.type = new Date - 0
1151
+ data.type = Math.random(),
1152
1152
  data.element = null
1153
1153
  $model[name] = accessor.get.call($vmodel)
1154
1154
  },
1155
1155
  element: head,
1156
- type: new Date - 0,
1156
+ type: Math.random(),
1157
1157
  handler: noop,
1158
1158
  args: []
1159
1159
  }
@@ -1194,7 +1194,7 @@ function modelFactory(source, $special, $model) {
1194
1194
  $vmodel.$id = generateID()
1195
1195
  $vmodel.$model = $model
1196
1196
  $vmodel.$events = $events
1197
- for (var i in EventBus) {
1197
+ for ( i in EventBus) {
1198
1198
  var fn = EventBus[i]
1199
1199
  if (!W3C) { //在IE6-8下,VB对象的方法里的this并不指向自身,需要用bind处理一下
1200
1200
  fn = fn.bind($vmodel)
@@ -1754,7 +1754,7 @@ function removeSubscribers() {
1754
1754
  if (diff) {
1755
1755
  //avalon.log("有需要移除的元素")
1756
1756
  while (obj = $$subscribers[--i]) {
1757
- var data = obj.data
1757
+ data = obj.data
1758
1758
  if (data.element === void 0)
1759
1759
  continue
1760
1760
  if (needTest[data.type] && isRemove(data.element)) { //如果它没有在DOM树
@@ -1861,7 +1861,7 @@ avalon.parseHTML = function(html) {
1861
1861
  for (i = wrap[0]; i--; wrapper = wrapper.lastChild) {
1862
1862
  }
1863
1863
  if (!W3C) { //fix IE
1864
- var els = wrapper.getElementsByTagName("br"), n = els.length
1864
+ els = wrapper.getElementsByTagName("br"), n = els.length
1865
1865
  while (el = els[--n]) {
1866
1866
  if (el.className === "msNoScope") {
1867
1867
  el.parentNode.removeChild(el)
@@ -2003,55 +2003,6 @@ function bindingSorter(a, b) {
2003
2003
  return a.priority - b.priority
2004
2004
  }
2005
2005
 
2006
- function scanTag(elem, vmodels, node) {
2007
- //扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
2008
- //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
2009
- var a = elem.getAttribute("ms-skip")
2010
- //#360 在旧式IE中 Object标签在引入Flash等资源时,可能出现没有getAttributeNode,innerHTML的情形
2011
- if (!elem.getAttributeNode) {
2012
- return log("warning " + elem.tagName + " no getAttributeNode method")
2013
- }
2014
- var b = elem.getAttributeNode("ms-important")
2015
- var c = elem.getAttributeNode("ms-controller")
2016
- if (typeof a === "string") {
2017
- return
2018
- } else if (node = b || c) {
2019
- var newVmodel = avalon.vmodels[node.value]
2020
- if (!newVmodel) {
2021
- return
2022
- }
2023
- //ms-important不包含父VM,ms-controller相反
2024
- vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
2025
- var name = node.name
2026
- elem.removeAttribute(name) //removeAttributeNode不会刷新[ms-controller]样式规则
2027
- avalon(elem).removeClass(name)
2028
- createSignalTower(elem, newVmodel)
2029
- }
2030
- scanAttr(elem, vmodels) //扫描特性节点
2031
- }
2032
- function scanNodeList(parent, vmodels) {
2033
- var node = parent.firstChild
2034
- while (node) {
2035
- var nextNode = node.nextSibling
2036
- scanNode(node, node.nodeType, vmodels)
2037
- node = nextNode
2038
- }
2039
- }
2040
-
2041
- function scanNodeArray(nodes, vmodels) {
2042
- for (var i = 0, node; node = nodes[i++]; ) {
2043
- scanNode(node, node.nodeType, vmodels)
2044
- }
2045
- }
2046
- function scanNode(node, nodeType, vmodels) {
2047
- if (nodeType === 1) {
2048
- scanTag(node, vmodels) //扫描元素节点
2049
- } else if (nodeType === 3 && rexpr.test(node.data)){
2050
- scanText(node, vmodels) //扫描文本节点
2051
- } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) {
2052
- scanText(node, vmodels) //扫描注释节点
2053
- }
2054
- }
2055
2006
  function scanAttr(elem, vmodels) {
2056
2007
  //防止setAttribute, removeAttribute时 attributes自动被同步,导致for循环出错
2057
2008
  var attributes = getAttributes ? getAttributes(elem) : avalon.slice(elem.attributes)
@@ -2120,8 +2071,8 @@ function scanAttr(elem, vmodels) {
2120
2071
  log("warning!一个元素上不能同时定义ms-attr-checked与ms-duplex")
2121
2072
  }
2122
2073
  var scanNode = true
2123
- for (var i = 0, binding; binding = bindings[i]; i++) {
2124
- var type = binding.type
2074
+ for (i = 0; binding = bindings[i]; i++) {
2075
+ type = binding.type
2125
2076
  if (rnoscanAttrBinding.test(type)) {
2126
2077
  return executeBindings(bindings.slice(0, i + 1), vmodels)
2127
2078
  } else if (scanNode) {
@@ -2185,14 +2136,66 @@ if (!"1" [0]) {
2185
2136
  }
2186
2137
  }
2187
2138
 
2139
+ function scanNodeList(parent, vmodels) {
2140
+ var node = parent.firstChild
2141
+ while (node) {
2142
+ var nextNode = node.nextSibling
2143
+ scanNode(node, node.nodeType, vmodels)
2144
+ node = nextNode
2145
+ }
2146
+ }
2147
+
2148
+ function scanNodeArray(nodes, vmodels) {
2149
+ for (var i = 0, node; node = nodes[i++]; ) {
2150
+ scanNode(node, node.nodeType, vmodels)
2151
+ }
2152
+ }
2153
+ function scanNode(node, nodeType, vmodels) {
2154
+ if (nodeType === 1) {
2155
+ scanTag(node, vmodels) //扫描元素节点
2156
+ } else if (nodeType === 3 && rexpr.test(node.data)){
2157
+ scanText(node, vmodels) //扫描文本节点
2158
+ } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) {
2159
+ scanText(node, vmodels) //扫描注释节点
2160
+ }
2161
+ }
2162
+ function scanTag(elem, vmodels, node) {
2163
+ //扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
2164
+ //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
2165
+ var a = elem.getAttribute("ms-skip")
2166
+ //#360 在旧式IE中 Object标签在引入Flash等资源时,可能出现没有getAttributeNode,innerHTML的情形
2167
+ if (!elem.getAttributeNode) {
2168
+ return log("warning " + elem.tagName + " no getAttributeNode method")
2169
+ }
2170
+ var b = elem.getAttributeNode("ms-important")
2171
+ var c = elem.getAttributeNode("ms-controller")
2172
+ if (typeof a === "string") {
2173
+ return
2174
+ } else if (node = b || c) {
2175
+ var newVmodel = avalon.vmodels[node.value]
2176
+ if (!newVmodel) {
2177
+ return
2178
+ }
2179
+ //ms-important不包含父VM,ms-controller相反
2180
+ vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
2181
+ var name = node.name
2182
+ elem.removeAttribute(name) //removeAttributeNode不会刷新[ms-controller]样式规则
2183
+ avalon(elem).removeClass(name)
2184
+ createSignalTower(elem, newVmodel)
2185
+ }
2186
+ scanAttr(elem, vmodels) //扫描特性节点
2187
+ }
2188
2188
  var rhasHtml = /\|\s*html\s*/,
2189
2189
  r11a = /\|\|/g,
2190
2190
  rlt = /&lt;/g,
2191
2191
  rgt = /&gt;/g
2192
-
2192
+ rstringLiteral = /(['"])(\\\1|.)+?\1/g
2193
2193
  function getToken(value) {
2194
2194
  if (value.indexOf("|") > 0) {
2195
- var index = value.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
2195
+ var scapegoat = value.replace( rstringLiteral, function(_){
2196
+ return Math.pow(10,_.length)
2197
+ })
2198
+ var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
2196
2199
  if (index > -1) {
2197
2200
  return {
2198
2201
  filters: value.slice(index),
@@ -2256,7 +2259,7 @@ function scanText(textNode, vmodels) {
2256
2259
  tokens = scanExpr(textNode.data)
2257
2260
  }
2258
2261
  if (tokens.length) {
2259
- for (var i = 0, token; token = tokens[i++]; ) {
2262
+ for (var i = 0; token = tokens[i++]; ) {
2260
2263
  var node = DOC.createTextNode(token.value) //将文本转换为文本节点,并替换原来的文本节点
2261
2264
  if (token.expr) {
2262
2265
  token.type = "text"
@@ -2295,7 +2298,7 @@ function camelize(target) {
2295
2298
  })
2296
2299
  }
2297
2300
 
2298
- var ClassListMethods = {
2301
+ var fakeClassListMethods = {
2299
2302
  _toString: function() {
2300
2303
  var node = this.node
2301
2304
  var cls = node.className
@@ -2325,13 +2328,13 @@ var ClassListMethods = {
2325
2328
  } //toggle存在版本差异,因此不使用它
2326
2329
  }
2327
2330
 
2328
- function ClassList(node) {
2331
+ function fakeClassList(node) {
2329
2332
  if (!("classList" in node)) {
2330
2333
  node.classList = {
2331
2334
  node: node
2332
2335
  }
2333
- for (var k in ClassListMethods) {
2334
- node.classList[k.slice(1)] = ClassListMethods[k]
2336
+ for (var k in fakeClassListMethods) {
2337
+ node.classList[k.slice(1)] = fakeClassListMethods[k]
2335
2338
  }
2336
2339
  }
2337
2340
  return node.classList
@@ -2344,7 +2347,7 @@ function ClassList(node) {
2344
2347
  //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
2345
2348
  if (cls && typeof cls === "string" && el && el.nodeType === 1) {
2346
2349
  cls.replace(/\S+/g, function(c) {
2347
- ClassList(el)[method](c)
2350
+ fakeClassList(el)[method](c)
2348
2351
  })
2349
2352
  }
2350
2353
  return this
@@ -2353,7 +2356,7 @@ function ClassList(node) {
2353
2356
  avalon.fn.mix({
2354
2357
  hasClass: function(cls) {
2355
2358
  var el = this[0] || {}
2356
- return el.nodeType === 1 && ClassList(el).contains(cls)
2359
+ return el.nodeType === 1 && fakeClassList(el).contains(cls)
2357
2360
  },
2358
2361
  toggleClass: function(value, stateVal) {
2359
2362
  var className, i = 0
@@ -2845,14 +2848,14 @@ var keywords =
2845
2848
  // 关键字
2846
2849
  "break,case,catch,continue,debugger,default,delete,do,else,false" +
2847
2850
  ",finally,for,function,if,in,instanceof,new,null,return,switch,this" +
2848
- ",throw,true,try,typeof,var,void,while,with"
2851
+ ",throw,true,try,typeof,var,void,while,with" +
2849
2852
  // 保留字
2850
- + ",abstract,boolean,byte,char,class,const,double,enum,export,extends" +
2853
+ ",abstract,boolean,byte,char,class,const,double,enum,export,extends" +
2851
2854
  ",final,float,goto,implements,import,int,interface,long,native" +
2852
2855
  ",package,private,protected,public,short,static,super,synchronized" +
2853
- ",throws,transient,volatile"
2856
+ ",throws,transient,volatile" +
2854
2857
  // ECMA 5 - use strict
2855
- + ",arguments,let,yield" + ",undefined"
2858
+ ",arguments,let,yield" + ",undefined"
2856
2859
  var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g
2857
2860
  var rsplit = /[^\w$]+/g
2858
2861
  var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g')
@@ -2992,7 +2995,7 @@ function parseExpr(code, scopes, data) {
2992
2995
  data.evaluator = fn
2993
2996
  return
2994
2997
  }
2995
- var prefix = assigns.join(", ")
2998
+ prefix = assigns.join(", ")
2996
2999
  if (prefix) {
2997
3000
  prefix = "var " + prefix
2998
3001
  }
@@ -3060,12 +3063,6 @@ function parseExprProxy(code, scopes, data, tokens, noregister) {
3060
3063
  }
3061
3064
  }
3062
3065
  avalon.parseExprProxy = parseExprProxy
3063
- /*********************************************************************
3064
- * 各种指令 *
3065
- **********************************************************************/
3066
- //ms-skip绑定已经在scanTag 方法中实现
3067
- //ms-controller绑定已经在scanTag 方法中实现
3068
- //ms-important绑定已经在scanTag 方法中实现
3069
3066
  var bools = "autofocus,autoplay,async,allowTransparency,checked,controls,declare,disabled,defer,defaultChecked,defaultSelected" +
3070
3067
  "contentEditable,isMap,loop,multiple,noHref,noResize,noShade,open,readOnly,selected"
3071
3068
  var boolMap = {}
@@ -3163,7 +3160,7 @@ bindingExecutors.attr = function(val, elem, data) {
3163
3160
  var loaded = data.includeLoaded
3164
3161
  var replace = data.includeReplaced
3165
3162
  var target = replace ? elem.parentNode : elem
3166
- function scanTemplate(text) {
3163
+ var scanTemplate = function(text) {
3167
3164
  if (loaded) {
3168
3165
  text = loaded.apply(target, [text].concat(vmodels))
3169
3166
  }
@@ -3213,7 +3210,7 @@ bindingExecutors.attr = function(val, elem, data) {
3213
3210
  var el = val && val.nodeType === 1 ? val : DOC.getElementById(val)
3214
3211
  if (el) {
3215
3212
  if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法取得其内容,IE6能取得其innerHTML
3216
- var xhr = getXHR() //IE9-11与chrome的innerHTML会得到转义的内容,它们的innerText可以
3213
+ xhr = getXHR() //IE9-11与chrome的innerHTML会得到转义的内容,它们的innerText可以
3217
3214
  xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构
3218
3215
  xhr.send(null)
3219
3216
  //http://bbs.csdn.net/topics/390349046?page=1#post-393492653
@@ -3251,8 +3248,6 @@ bindingExecutors.attr = function(val, elem, data) {
3251
3248
  "title,alt,src,value,css,include,href".replace(rword, function(name) {
3252
3249
  bindingHandlers[name] = bindingHandlers.attr
3253
3250
  })
3254
- //ms-include绑定已由ms-attr绑定实现
3255
-
3256
3251
  //根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
3257
3252
  //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
3258
3253
  bindingHandlers["class"] = function(data, vmodels) {
@@ -3343,6 +3338,10 @@ bindingExecutors ["class"] = function(val, elem, data) {
3343
3338
  "hover,active".replace(rword, function(method) {
3344
3339
  bindingHandlers[method] = bindingHandlers["class"]
3345
3340
  })
3341
+ //ms-controller绑定已经在scanTag 方法中实现
3342
+ //ms-css绑定已由ms-attr绑定实现
3343
+
3344
+
3346
3345
  // bindingHandlers.data 定义在if.js
3347
3346
  bindingExecutors.data = function(val, elem, data) {
3348
3347
  var key = "data-" + data.param
@@ -3353,350 +3352,95 @@ bindingExecutors.data = function(val, elem, data) {
3353
3352
  }
3354
3353
  }
3355
3354
 
3356
- // bindingHandlers.text 定义在if.js
3357
- bindingExecutors.text = function(val, elem) {
3358
- val = val == null ? "" : val //不在页面上显示undefined null
3359
- if (elem.nodeType === 3) { //绑定在文本节点上
3360
- try { //IE对游离于DOM树外的节点赋值会报错
3361
- elem.data = val
3362
- } catch (e) {
3355
+ //双工绑定
3356
+ var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
3357
+ var elem = data.element,
3358
+ hasCast
3359
+ parseExprProxy(data.value, vmodels, data, 0, 1)
3360
+
3361
+ data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
3362
+ if (data.evaluator && data.args) {
3363
+ var params = []
3364
+ var casting = oneObject("string,number,boolean,checked")
3365
+ if (elem.type === "radio" && data.param === "") {
3366
+ data.param = "checked"
3363
3367
  }
3364
- } else { //绑定在特性节点上
3365
- if ("textContent" in elem) {
3366
- elem.textContent = val
3367
- } else {
3368
- elem.innerText = val
3368
+ if (elem.msData) {
3369
+ elem.msData["ms-duplex"] = data.value
3369
3370
  }
3370
- }
3371
- }
3372
-
3373
-
3374
- // bindingHandlers.html 定义在if.js
3375
- bindingExecutors.html = function(val, elem, data) {
3376
- val = val == null ? "" : val
3377
- var isHtmlFilter = "group" in data
3378
- var parent = isHtmlFilter ? elem.parentNode : elem
3379
- if (!parent)
3380
- return
3381
- if (val.nodeType === 11) { //将val转换为文档碎片
3382
- var fragment = val
3383
- } else if (val.nodeType === 1 || val.item) {
3384
- var nodes = val.nodeType === 1 ? val.childNodes : val.item ? val : []
3385
- fragment = hyperspace.cloneNode(true)
3386
- while (nodes[0]) {
3387
- fragment.appendChild(nodes[0])
3371
+ data.param.replace(/\w+/g, function(name) {
3372
+ if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
3373
+ if (name === "radio")
3374
+ log("ms-duplex-radio已经更名为ms-duplex-checked")
3375
+ name = "checked"
3376
+ data.isChecked = true
3377
+ }
3378
+ if (name === "bool") {
3379
+ name = "boolean"
3380
+ log("ms-duplex-bool已经更名为ms-duplex-boolean")
3381
+ } else if (name === "text") {
3382
+ name = "string"
3383
+ log("ms-duplex-text已经更名为ms-duplex-string")
3384
+ }
3385
+ if (casting[name]) {
3386
+ hasCast = true
3387
+ }
3388
+ avalon.Array.ensure(params, name)
3389
+ })
3390
+ if (!hasCast) {
3391
+ params.push("string")
3388
3392
  }
3389
- } else {
3390
- fragment = avalon.parseHTML(val)
3391
- }
3392
- //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空
3393
- var comment = DOC.createComment("ms-html")
3394
- if (isHtmlFilter) {
3395
- parent.insertBefore(comment, elem)
3396
- var n = data.group, i = 1
3397
- while (i < n) {
3398
- var node = elem.nextSibling
3399
- if (node) {
3400
- parent.removeChild(node)
3401
- i++
3393
+ data.param = params.join("-")
3394
+ data.bound = function(type, callback) {
3395
+ if (elem.addEventListener) {
3396
+ elem.addEventListener(type, callback, false)
3397
+ } else {
3398
+ elem.attachEvent("on" + type, callback)
3399
+ }
3400
+ var old = data.rollback
3401
+ data.rollback = function() {
3402
+ elem.avalonSetter = null
3403
+ avalon.unbind(elem, type, callback)
3404
+ old && old()
3402
3405
  }
3403
3406
  }
3404
- parent.removeChild(elem)
3405
- data.element = comment //防止被CG
3406
- } else {
3407
- avalon.clearHTML(parent).appendChild(comment)
3408
- }
3409
- if (isHtmlFilter) {
3410
- data.group = fragment.childNodes.length || 1
3407
+ for (var i in avalon.vmodels) {
3408
+ var v = avalon.vmodels[i]
3409
+ v.$fire("avalon-ms-duplex-init", data)
3410
+ }
3411
+ var cpipe = data.pipe || (data.pipe = pipe)
3412
+ cpipe(null, data, "init")
3413
+ var tagName = elem.tagName
3414
+ duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data)
3411
3415
  }
3412
- var nodes = avalon.slice(fragment.childNodes)
3413
- if (nodes[0]) {
3414
- if (comment.parentNode)
3415
- comment.parentNode.replaceChild(fragment, comment)
3416
- if (isHtmlFilter) {
3417
- data.element = nodes[0]
3416
+ }
3417
+ //不存在 bindingExecutors.duplex
3418
+ function fixNull(val) {
3419
+ return val == null ? "" : val
3420
+ }
3421
+ avalon.duplexHooks = {
3422
+ checked: {
3423
+ get: function(val, data) {
3424
+ return !data.element.oldValue
3418
3425
  }
3419
- }
3420
- scanNodeArray(nodes, data.vmodels)
3421
- }
3422
-
3423
- bindingHandlers["if"] =
3424
- bindingHandlers.data =
3425
- bindingHandlers.text =
3426
- bindingHandlers.html =
3427
- function(data, vmodels) {
3428
- parseExprProxy(data.value, vmodels, data)
3429
- }
3430
-
3431
- bindingExecutors["if"] = function(val, elem, data) {
3432
- if (val) { //插回DOM树
3433
- if (elem.nodeType === 8) {
3434
- elem.parentNode.replaceChild(data.template, elem)
3435
- elem = data.element = data.template //这时可能为null
3436
- }
3437
- if (elem.getAttribute(data.name)) {
3438
- elem.removeAttribute(data.name)
3439
- scanAttr(elem, data.vmodels)
3440
- }
3441
- data.rollback = null
3442
- } else { //移出DOM树,并用注释节点占据原位置
3443
- if (elem.nodeType === 1) {
3444
- var node = data.element = DOC.createComment("ms-if")
3445
- elem.parentNode.replaceChild(node, elem)
3446
- data.template = elem //元素节点
3447
- ifGroup.appendChild(elem)
3448
- data.rollback = function() {
3449
- if (elem.parentNode === ifGroup) {
3450
- ifGroup.removeChild(elem)
3451
- }
3452
- }
3453
- }
3454
- }
3455
- }
3456
-
3457
-
3458
- function parseDisplay(nodeName, val) {
3459
- //用于取得此类标签的默认display值
3460
- var key = "_" + nodeName
3461
- if (!parseDisplay[key]) {
3462
- var node = DOC.createElement(nodeName)
3463
- root.appendChild(node)
3464
- if (W3C) {
3465
- val = getComputedStyle(node, null).display
3466
- } else {
3467
- val = node.currentStyle.display
3468
- }
3469
- root.removeChild(node)
3470
- parseDisplay[key] = val
3471
- }
3472
- return parseDisplay[key]
3473
- }
3474
-
3475
- avalon.parseDisplay = parseDisplay
3476
-
3477
- bindingHandlers.visible = function(data, vmodels) {
3478
- var elem = avalon(data.element)
3479
- var display = elem.css("display")
3480
- if (display === "none") {
3481
- var style = elem[0].style
3482
- var has = /visibility/i.test(style.cssText)
3483
- var visible = elem.css("visibility")
3484
- style.display = ""
3485
- style.visibility = "hidden"
3486
- display = elem.css("display")
3487
- if (display === "none") {
3488
- display = parseDisplay(elem[0].nodeName)
3489
- }
3490
- style.visibility = has ? visible : ""
3491
- }
3492
- data.display = display
3493
- parseExprProxy(data.value, vmodels, data)
3494
- }
3495
-
3496
- bindingExecutors.visible = function(val, elem, data) {
3497
- elem.style.display = val ? data.display : "none"
3498
- }
3499
-
3500
- var rdash = /\(([^)]*)\)/
3501
- bindingHandlers.on = function(data, vmodels) {
3502
- var value = data.value
3503
- data.type = "on"
3504
- var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
3505
- if (typeof bindingHandlers.on[eventType + "Hook"] === "function") {
3506
- bindingHandlers.on[eventType + "Hook"](data)
3507
- }
3508
- if (value.indexOf("(") > 0 && value.indexOf(")") > -1) {
3509
- var matched = (value.match(rdash) || ["", ""])[1].trim()
3510
- if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理
3511
- value = value.replace(rdash, "")
3512
- }
3513
- }
3514
- parseExprProxy(value, vmodels, data)
3515
- }
3516
-
3517
- bindingExecutors.on = function(callback, elem, data) {
3518
- callback = function(e) {
3519
- var fn = data.evaluator || noop
3520
- return fn.apply(this, data.args.concat(e))
3521
- }
3522
- var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
3523
- if (eventType === "scan") {
3524
- callback.call(elem, {
3525
- type: eventType
3526
- })
3527
- } else if (typeof data.specialBind === "function") {
3528
- data.specialBind(elem, callback)
3529
- } else {
3530
- var removeFn = avalon.bind(elem, eventType, callback)
3531
- }
3532
- data.rollback = function() {
3533
- if (typeof data.specialUnbind === "function") {
3534
- data.specialUnbind()
3535
- } else {
3536
- avalon.unbind(elem, eventType, removeFn)
3537
- }
3538
- }
3539
- }
3540
-
3541
-
3542
- bindingHandlers.widget = function(data, vmodels) {
3543
- var args = data.value.match(rword)
3544
- var elem = data.element
3545
- var widget = args[0]
3546
- var id = args[1]
3547
- if (!id || id === "$") {//没有定义或为$时,取组件名+随机数
3548
- id = generateID(widget)
3549
- }
3550
- var optName = args[2] || widget//没有定义,取组件名
3551
- var constructor = avalon.ui[widget]
3552
- if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
3553
- vmodels = elem.vmodels || vmodels
3554
- for (var i = 0, v; v = vmodels[i++]; ) {
3555
- if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
3556
- var vmOptions = v[optName]
3557
- vmOptions = vmOptions.$model || vmOptions
3558
- break
3559
- }
3560
- }
3561
- if (vmOptions) {
3562
- var wid = vmOptions[widget + "Id"]
3563
- if (typeof wid === "string") {
3564
- id = wid
3565
- }
3566
- }
3567
- //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
3568
- var widgetData = avalon.getWidgetData(elem, widget)
3569
- data.value = [widget, id, optName].join(",")
3570
- data[widget + "Id"] = id
3571
- data.evaluator = noop
3572
- elem.msData["ms-widget-id"] = id
3573
- var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
3574
- elem.removeAttribute("ms-widget")
3575
- var vmodel = constructor(elem, data, vmodels) || {} //防止组件不返回VM
3576
- if (vmodel.$id) {
3577
- avalon.vmodels[id] = vmodel
3578
- createSignalTower(elem, vmodel)
3579
- if (vmodel.hasOwnProperty("$init")) {
3580
- vmodel.$init(function() {
3581
- avalon.scan(elem, [vmodel].concat(vmodels))
3582
- if (typeof options.onInit === "function") {
3583
- options.onInit.call(elem, vmodel, options, vmodels)
3584
- }
3585
- })
3586
- }
3587
- data.rollback = function() {
3588
- try {
3589
- vmodel.widgetElement = null
3590
- vmodel.$remove()
3591
- } catch (e) {
3592
- }
3593
- elem.msData = {}
3594
- delete avalon.vmodels[vmodel.$id]
3595
- }
3596
- addSubscribers(data, widgetList)
3597
- if (window.chrome) {
3598
- elem.addEventListener("DOMNodeRemovedFromDocument", function() {
3599
- setTimeout(removeSubscribers)
3600
- })
3601
- }
3602
- } else {
3603
- avalon.scan(elem, vmodels)
3604
- }
3605
- } else if (vmodels.length) { //如果该组件还没有加载,那么保存当前的vmodels
3606
- elem.vmodels = vmodels
3607
- }
3608
- }
3609
- var widgetList = []
3610
- //不存在 bindingExecutors.widget
3611
- //双工绑定
3612
- var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
3613
- var elem = data.element,
3614
- hasCast
3615
- parseExprProxy(data.value, vmodels, data, 0, 1)
3616
-
3617
- data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
3618
- if (data.evaluator && data.args) {
3619
- var params = []
3620
- var casting = oneObject("string,number,boolean,checked")
3621
- if (elem.type === "radio" && data.param === "") {
3622
- data.param = "checked"
3623
- }
3624
- if (elem.msData) {
3625
- elem.msData["ms-duplex"] = data.value
3626
- }
3627
- data.param.replace(/\w+/g, function(name) {
3628
- if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
3629
- if (name === "radio")
3630
- log("ms-duplex-radio已经更名为ms-duplex-checked")
3631
- name = "checked"
3632
- data.isChecked = true
3633
- }
3634
- if (name === "bool") {
3635
- name = "boolean"
3636
- log("ms-duplex-bool已经更名为ms-duplex-boolean")
3637
- } else if (name === "text") {
3638
- name = "string"
3639
- log("ms-duplex-text已经更名为ms-duplex-string")
3640
- }
3641
- if (casting[name]) {
3642
- hasCast = true
3643
- }
3644
- avalon.Array.ensure(params, name)
3645
- })
3646
- if (!hasCast) {
3647
- params.push("string")
3648
- }
3649
- data.param = params.join("-")
3650
- data.bound = function(type, callback) {
3651
- if (elem.addEventListener) {
3652
- elem.addEventListener(type, callback, false)
3653
- } else {
3654
- elem.attachEvent("on" + type, callback)
3655
- }
3656
- var old = data.rollback
3657
- data.rollback = function() {
3658
- elem.avalonSetter = null
3659
- avalon.unbind(elem, type, callback)
3660
- old && old()
3661
- }
3662
- }
3663
- for (var i in avalon.vmodels) {
3664
- var v = avalon.vmodels[i]
3665
- v.$fire("avalon-ms-duplex-init", data)
3666
- }
3667
- var cpipe = data.pipe || (data.pipe = pipe)
3668
- cpipe(null, data, "init")
3669
- var tagName = elem.tagName
3670
- duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data)
3671
- }
3672
- }
3673
- //不存在 bindingExecutors.duplex
3674
- function fixNull(val) {
3675
- return val == null ? "" : val
3676
- }
3677
- avalon.duplexHooks = {
3678
- checked: {
3679
- get: function(val, data) {
3680
- return !data.element.oldValue
3681
- }
3682
- },
3683
- string: {
3684
- get: function(val) { //同步到VM
3685
- return val
3686
- },
3687
- set: fixNull
3688
- },
3689
- "boolean": {
3690
- get: function(val) {
3691
- return val === "true"
3692
- },
3693
- set: fixNull
3694
- },
3695
- number: {
3696
- get: function(val) {
3697
- return isFinite(val) ? parseFloat(val) || 0 : val
3698
- },
3699
- set: fixNull
3426
+ },
3427
+ string: {
3428
+ get: function(val) { //同步到VM
3429
+ return val
3430
+ },
3431
+ set: fixNull
3432
+ },
3433
+ "boolean": {
3434
+ get: function(val) {
3435
+ return val === "true"
3436
+ },
3437
+ set: fixNull
3438
+ },
3439
+ number: {
3440
+ get: function(val) {
3441
+ return isFinite(val) ? parseFloat(val) || 0 : val
3442
+ },
3443
+ set: fixNull
3700
3444
  }
3701
3445
  }
3702
3446
 
@@ -3970,6 +3714,135 @@ duplexBinding.SELECT = function(element, evaluator, data) {
3970
3714
  }
3971
3715
 
3972
3716
 
3717
+ // bindingHandlers.html 定义在if.js
3718
+ bindingExecutors.html = function(val, elem, data) {
3719
+ val = val == null ? "" : val
3720
+ var isHtmlFilter = "group" in data
3721
+ var parent = isHtmlFilter ? elem.parentNode : elem
3722
+ if (!parent)
3723
+ return
3724
+ if (val.nodeType === 11) { //将val转换为文档碎片
3725
+ var fragment = val
3726
+ } else if (val.nodeType === 1 || val.item) {
3727
+ var nodes = val.nodeType === 1 ? val.childNodes : val.item ? val : []
3728
+ fragment = hyperspace.cloneNode(true)
3729
+ while (nodes[0]) {
3730
+ fragment.appendChild(nodes[0])
3731
+ }
3732
+ } else {
3733
+ fragment = avalon.parseHTML(val)
3734
+ }
3735
+ //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空
3736
+ var comment = DOC.createComment("ms-html")
3737
+ if (isHtmlFilter) {
3738
+ parent.insertBefore(comment, elem)
3739
+ var n = data.group, i = 1
3740
+ while (i < n) {
3741
+ var node = elem.nextSibling
3742
+ if (node) {
3743
+ parent.removeChild(node)
3744
+ i++
3745
+ }
3746
+ }
3747
+ parent.removeChild(elem)
3748
+ data.element = comment //防止被CG
3749
+ } else {
3750
+ avalon.clearHTML(parent).appendChild(comment)
3751
+ }
3752
+ if (isHtmlFilter) {
3753
+ data.group = fragment.childNodes.length || 1
3754
+ }
3755
+ nodes = avalon.slice(fragment.childNodes)
3756
+ if (nodes[0]) {
3757
+ if (comment.parentNode)
3758
+ comment.parentNode.replaceChild(fragment, comment)
3759
+ if (isHtmlFilter) {
3760
+ data.element = nodes[0]
3761
+ }
3762
+ }
3763
+ scanNodeArray(nodes, data.vmodels)
3764
+ }
3765
+
3766
+ bindingHandlers["if"] =
3767
+ bindingHandlers.data =
3768
+ bindingHandlers.text =
3769
+ bindingHandlers.html =
3770
+ function(data, vmodels) {
3771
+ parseExprProxy(data.value, vmodels, data)
3772
+ }
3773
+
3774
+ bindingExecutors["if"] = function(val, elem, data) {
3775
+ if (val) { //插回DOM树
3776
+ if (elem.nodeType === 8) {
3777
+ elem.parentNode.replaceChild(data.template, elem)
3778
+ elem = data.element = data.template //这时可能为null
3779
+ }
3780
+ if (elem.getAttribute(data.name)) {
3781
+ elem.removeAttribute(data.name)
3782
+ scanAttr(elem, data.vmodels)
3783
+ }
3784
+ data.rollback = null
3785
+ } else { //移出DOM树,并用注释节点占据原位置
3786
+ if (elem.nodeType === 1) {
3787
+ var node = data.element = DOC.createComment("ms-if")
3788
+ elem.parentNode.replaceChild(node, elem)
3789
+ data.template = elem //元素节点
3790
+ ifGroup.appendChild(elem)
3791
+ data.rollback = function() {
3792
+ if (elem.parentNode === ifGroup) {
3793
+ ifGroup.removeChild(elem)
3794
+ }
3795
+ }
3796
+ }
3797
+ }
3798
+ }
3799
+
3800
+
3801
+ //ms-important绑定已经在scanTag 方法中实现
3802
+ //ms-include绑定已由ms-attr绑定实现
3803
+
3804
+ var rdash = /\(([^)]*)\)/
3805
+ bindingHandlers.on = function(data, vmodels) {
3806
+ var value = data.value
3807
+ data.type = "on"
3808
+ var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
3809
+ if (typeof bindingHandlers.on[eventType + "Hook"] === "function") {
3810
+ bindingHandlers.on[eventType + "Hook"](data)
3811
+ }
3812
+ if (value.indexOf("(") > 0 && value.indexOf(")") > -1) {
3813
+ var matched = (value.match(rdash) || ["", ""])[1].trim()
3814
+ if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理
3815
+ value = value.replace(rdash, "")
3816
+ }
3817
+ }
3818
+ parseExprProxy(value, vmodels, data)
3819
+ }
3820
+
3821
+ bindingExecutors.on = function(callback, elem, data) {
3822
+ callback = function(e) {
3823
+ var fn = data.evaluator || noop
3824
+ return fn.apply(this, data.args.concat(e))
3825
+ }
3826
+ var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
3827
+ if (eventType === "scan") {
3828
+ callback.call(elem, {
3829
+ type: eventType
3830
+ })
3831
+ } else if (typeof data.specialBind === "function") {
3832
+ data.specialBind(elem, callback)
3833
+ } else {
3834
+ var removeFn = avalon.bind(elem, eventType, callback)
3835
+ }
3836
+ data.rollback = function() {
3837
+ if (typeof data.specialUnbind === "function") {
3838
+ data.specialUnbind()
3839
+ } else {
3840
+ avalon.unbind(elem, eventType, removeFn)
3841
+ }
3842
+ }
3843
+ }
3844
+
3845
+
3973
3846
  bindingHandlers.repeat = function(data, vmodels) {
3974
3847
  var type = data.type
3975
3848
  parseExprProxy(data.value, vmodels, data, 0, 1)
@@ -4042,9 +3915,9 @@ bindingHandlers.repeat = function(data, vmodels) {
4042
3915
  check0 = "$first"
4043
3916
  check1 = "$last"
4044
3917
  }
4045
- for (var i = 0, p; p = vmodels[i++]; ) {
4046
- if (p.hasOwnProperty(check0) && p.hasOwnProperty(check1)) {
4047
- data.$outer = p
3918
+ for (i = 0; v = vmodels[i++]; ) {
3919
+ if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) {
3920
+ data.$outer = v
4048
3921
  break
4049
3922
  }
4050
3923
  }
@@ -4074,7 +3947,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4074
3947
  var n = pos + el
4075
3948
  var array = data.$repeat
4076
3949
  var last = array.length - 1
4077
- var fragments = []
3950
+ var fragments = [], fragment
4078
3951
  var start = locateNode(data, pos)
4079
3952
  for (var i = pos; i < n; i++) {
4080
3953
  var proxy = eachProxyAgent(i, data)
@@ -4082,7 +3955,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4082
3955
  shimController(data, transation, proxy, fragments)
4083
3956
  }
4084
3957
  parent.insertBefore(transation, start)
4085
- for (var i = 0, fragment; fragment = fragments[i++]; ) {
3958
+ for (i = 0; fragment = fragments[i++]; ) {
4086
3959
  scanNodeArray(fragment.nodes, fragment.vmodels)
4087
3960
  fragment.nodes = fragment.vmodels = null
4088
3961
  }
@@ -4124,7 +3997,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4124
3997
  parent.insertBefore(transation, end)
4125
3998
  break
4126
3999
  case "index": //将proxies中的第pos个起的所有元素重新索引
4127
- var last = proxies.length - 1
4000
+ last = proxies.length - 1
4128
4001
  for (; el = proxies[pos]; pos++) {
4129
4002
  el.$index = pos
4130
4003
  el.$first = pos === 0
@@ -4132,7 +4005,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4132
4005
  }
4133
4006
  return
4134
4007
  case "set": //将proxies中的第pos个元素的VM设置为el(pos为数字,el任意)
4135
- var proxy = proxies[pos]
4008
+ proxy = proxies[pos]
4136
4009
  if (proxy) {
4137
4010
  notifySubscribers(proxy.$events.$index)
4138
4011
  }
@@ -4140,7 +4013,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4140
4013
  case "append": //将pos的键值对从el中取出(pos为一个普通对象,el为预先生成好的代理VM对象池)
4141
4014
  var pool = el
4142
4015
  var keys = []
4143
- var fragments = []
4016
+ fragments = []
4144
4017
  for (var key in pos) { //得到所有键名
4145
4018
  if (pos.hasOwnProperty(key) && key !== "hasOwnProperty") {
4146
4019
  keys.push(key)
@@ -4152,7 +4025,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4152
4025
  keys = keys2
4153
4026
  }
4154
4027
  }
4155
- for (var i = 0, key; key = keys[i++]; ) {
4028
+ for (i = 0; key = keys[i++]; ) {
4156
4029
  if (key !== "hasOwnProperty") {
4157
4030
  if (!pool[key]) {
4158
4031
  pool[key] = withProxyAgent(key, data)
@@ -4163,7 +4036,7 @@ bindingExecutors.repeat = function(method, pos, el) {
4163
4036
  var comment = data.$stamp = data.clone
4164
4037
  parent.insertBefore(comment, end)
4165
4038
  parent.insertBefore(transation, end)
4166
- for (var i = 0, fragment; fragment = fragments[i++]; ) {
4039
+ for (i = 0; fragment = fragments[i++]; ) {
4167
4040
  scanNodeArray(fragment.nodes, fragment.vmodels)
4168
4041
  fragment.nodes = fragment.vmodels = null
4169
4042
  }
@@ -4330,19 +4203,152 @@ function recycleProxies(proxies, type) {
4330
4203
  proxy.$events[i].length = 0
4331
4204
  }
4332
4205
  }
4333
- proxy.$host = proxy.$outer = {}
4334
- if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
4335
- proxyPool.pop()
4206
+ proxy.$host = proxy.$outer = {}
4207
+ if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
4208
+ proxyPool.pop()
4209
+ }
4210
+ }
4211
+ })
4212
+ if (type === "each")
4213
+ proxies.length = 0
4214
+ }
4215
+
4216
+
4217
+
4218
+
4219
+ /*********************************************************************
4220
+ * 各种指令 *
4221
+ **********************************************************************/
4222
+ //ms-skip绑定已经在scanTag 方法中实现
4223
+ // bindingHandlers.text 定义在if.js
4224
+ bindingExecutors.text = function(val, elem) {
4225
+ val = val == null ? "" : val //不在页面上显示undefined null
4226
+ if (elem.nodeType === 3) { //绑定在文本节点上
4227
+ try { //IE对游离于DOM树外的节点赋值会报错
4228
+ elem.data = val
4229
+ } catch (e) {
4230
+ }
4231
+ } else { //绑定在特性节点上
4232
+ if ("textContent" in elem) {
4233
+ elem.textContent = val
4234
+ } else {
4235
+ elem.innerText = val
4236
+ }
4237
+ }
4238
+ }
4239
+
4240
+
4241
+ function parseDisplay(nodeName, val) {
4242
+ //用于取得此类标签的默认display值
4243
+ var key = "_" + nodeName
4244
+ if (!parseDisplay[key]) {
4245
+ var node = DOC.createElement(nodeName)
4246
+ root.appendChild(node)
4247
+ if (W3C) {
4248
+ val = getComputedStyle(node, null).display
4249
+ } else {
4250
+ val = node.currentStyle.display
4251
+ }
4252
+ root.removeChild(node)
4253
+ parseDisplay[key] = val
4254
+ }
4255
+ return parseDisplay[key]
4256
+ }
4257
+
4258
+ avalon.parseDisplay = parseDisplay
4259
+
4260
+ bindingHandlers.visible = function(data, vmodels) {
4261
+ var elem = avalon(data.element)
4262
+ var display = elem.css("display")
4263
+ if (display === "none") {
4264
+ var style = elem[0].style
4265
+ var has = /visibility/i.test(style.cssText)
4266
+ var visible = elem.css("visibility")
4267
+ style.display = ""
4268
+ style.visibility = "hidden"
4269
+ display = elem.css("display")
4270
+ if (display === "none") {
4271
+ display = parseDisplay(elem[0].nodeName)
4272
+ }
4273
+ style.visibility = has ? visible : ""
4274
+ }
4275
+ data.display = display
4276
+ parseExprProxy(data.value, vmodels, data)
4277
+ }
4278
+
4279
+ bindingExecutors.visible = function(val, elem, data) {
4280
+ elem.style.display = val ? data.display : "none"
4281
+ }
4282
+
4283
+ bindingHandlers.widget = function(data, vmodels) {
4284
+ var args = data.value.match(rword)
4285
+ var elem = data.element
4286
+ var widget = args[0]
4287
+ var id = args[1]
4288
+ if (!id || id === "$") {//没有定义或为$时,取组件名+随机数
4289
+ id = generateID(widget)
4290
+ }
4291
+ var optName = args[2] || widget//没有定义,取组件名
4292
+ var constructor = avalon.ui[widget]
4293
+ if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
4294
+ vmodels = elem.vmodels || vmodels
4295
+ for (var i = 0, v; v = vmodels[i++]; ) {
4296
+ if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
4297
+ var vmOptions = v[optName]
4298
+ vmOptions = vmOptions.$model || vmOptions
4299
+ break
4300
+ }
4301
+ }
4302
+ if (vmOptions) {
4303
+ var wid = vmOptions[widget + "Id"]
4304
+ if (typeof wid === "string") {
4305
+ id = wid
4306
+ }
4307
+ }
4308
+ //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
4309
+ var widgetData = avalon.getWidgetData(elem, widget)
4310
+ data.value = [widget, id, optName].join(",")
4311
+ data[widget + "Id"] = id
4312
+ data.evaluator = noop
4313
+ elem.msData["ms-widget-id"] = id
4314
+ var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
4315
+ elem.removeAttribute("ms-widget")
4316
+ var vmodel = constructor(elem, data, vmodels) || {} //防止组件不返回VM
4317
+ if (vmodel.$id) {
4318
+ avalon.vmodels[id] = vmodel
4319
+ createSignalTower(elem, vmodel)
4320
+ if (vmodel.hasOwnProperty("$init")) {
4321
+ vmodel.$init(function() {
4322
+ avalon.scan(elem, [vmodel].concat(vmodels))
4323
+ if (typeof options.onInit === "function") {
4324
+ options.onInit.call(elem, vmodel, options, vmodels)
4325
+ }
4326
+ })
4327
+ }
4328
+ data.rollback = function() {
4329
+ try {
4330
+ vmodel.widgetElement = null
4331
+ vmodel.$remove()
4332
+ } catch (e) {
4333
+ }
4334
+ elem.msData = {}
4335
+ delete avalon.vmodels[vmodel.$id]
4336
+ }
4337
+ addSubscribers(data, widgetList)
4338
+ if (window.chrome) {
4339
+ elem.addEventListener("DOMNodeRemovedFromDocument", function() {
4340
+ setTimeout(removeSubscribers)
4341
+ })
4336
4342
  }
4343
+ } else {
4344
+ avalon.scan(elem, vmodels)
4337
4345
  }
4338
- })
4339
- if (type === "each")
4340
- proxies.length = 0
4346
+ } else if (vmodels.length) { //如果该组件还没有加载,那么保存当前的vmodels
4347
+ elem.vmodels = vmodels
4348
+ }
4341
4349
  }
4342
-
4343
-
4344
-
4345
-
4350
+ var widgetList = []
4351
+ //不存在 bindingExecutors.widget
4346
4352
  /*********************************************************************
4347
4353
  * 自带过滤器 *
4348
4354
  **********************************************************************/
@@ -4567,6 +4573,7 @@ new function() {
4567
4573
  Z: timeZoneGetter
4568
4574
  }
4569
4575
  var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/
4576
+ var raspnetjson = /^\/Date\((\d+)\)\/$/
4570
4577
  filters.date = function(date, format) {
4571
4578
  var locate = filters.date.locate,
4572
4579
  text = "",
@@ -4577,6 +4584,8 @@ new function() {
4577
4584
  if (typeof date === "string") {
4578
4585
  if (/^\d+$/.test(date)) {
4579
4586
  date = toInt(date)
4587
+ } else if (raspnetjson.test(date)) {
4588
+ date = +RegExp.$1
4580
4589
  } else {
4581
4590
  var trimDate = date.trim()
4582
4591
  var dateArray = [0, 0, 0, 0, 0, 0, 0]
@@ -4584,9 +4593,9 @@ new function() {
4584
4593
  //取得年月日
4585
4594
  trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function(_, a, b, c) {
4586
4595
  var array = c.length === 4 ? [c, a, b] : [a, b, c]
4587
- dateArray[0] = toInt(array[0]) //年
4596
+ dateArray[0] = toInt(array[0]) //年
4588
4597
  dateArray[1] = toInt(array[1]) - 1 //月
4589
- dateArray[2] = toInt(array[2])//日
4598
+ dateArray[2] = toInt(array[2]) //日
4590
4599
  return ""
4591
4600
  })
4592
4601
  var dateSetter = oDate.setFullYear
@@ -4595,10 +4604,9 @@ new function() {
4595
4604
  dateArray[3] = toInt(a) //小时
4596
4605
  dateArray[4] = toInt(b) //分钟
4597
4606
  dateArray[5] = toInt(c) //秒
4598
- if (d) {
4599
- dateArray[6] = Math.round(parseFloat("0." + d) * 1000) //毫秒
4607
+ if (d) { //毫秒
4608
+ dateArray[6] = Math.round(parseFloat("0." + d) * 1000)
4600
4609
  }
4601
- dateArray[6] = d || ""
4602
4610
  return ""
4603
4611
  })
4604
4612
  var tzHour = 0
@@ -4695,44 +4703,161 @@ new function() {
4695
4703
  * AMD加载器 *
4696
4704
  **********************************************************************/
4697
4705
  //https://www.devbridge.com/articles/understanding-amd-requirejs/
4706
+ //http://maxogden.com/nested-dependencies.html
4698
4707
  var modules = avalon.modules = {
4699
- "ready!": {
4700
- exports: avalon
4708
+ "domReady!": {
4709
+ exports: avalon,
4710
+ state: 3
4701
4711
  },
4702
4712
  "avalon": {
4703
4713
  exports: avalon,
4704
- state: 2
4714
+ state: 4
4705
4715
  }
4706
4716
  }
4717
+ //Object(modules[id]).state拥有如下值
4718
+ // undefined 没有定义
4719
+ // 1(send) 已经发出请求
4720
+ // 2(loading) 已经被执行但还没有执行完成,在这个阶段define方法会被执行
4721
+ // 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行
4722
+ // 4(execute) 其依赖也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行
4707
4723
  modules.exports = modules.avalon
4708
- //http://stackoverflow.com/questions/25175914/bundles-in-requirejs
4709
- //http://maxogden.com/nested-dependencies.html
4724
+
4710
4725
  new function() {
4711
4726
  var loadings = [] //正在加载中的模块列表
4712
- var factorys = [] //储存需要绑定ID与factory对应关系的模块(标准浏览器下,先parse的script节点会先onload)
4713
- //核心API之一 require
4714
- innerRequire = avalon.require = function(array, factory, parentUrl) {
4727
+ var factorys = [] //放置define方法的factory函数
4728
+ var rjsext = /\.js$/i
4729
+ var name2url = {}
4730
+ function makeRequest(name, config) {
4731
+ //1. 去掉资源前缀
4732
+ var res = "js"
4733
+ name = name.replace(/^(\w+)\!/, function(a, b) {
4734
+ res = b
4735
+ return ""
4736
+ })
4737
+ if (res === "ready") {
4738
+ log("debug: ready!已经被废弃,请使用domReady!")
4739
+ res = "domReady"
4740
+ }
4741
+ //2. 去掉querystring, hash
4742
+ var query = ""
4743
+ name = name.replace(rquery, function(a) {
4744
+ query = a
4745
+ return ""
4746
+ })
4747
+ //3. 去掉扩展名
4748
+ var suffix = "." + res
4749
+ var ext = /js|css/.test(suffix) ? suffix : ""
4750
+ name = name.replace(/\.[a-z0-9]+$/g, function(a) {
4751
+ if (a === suffix) {
4752
+ ext = a
4753
+ return ""
4754
+ } else {
4755
+ return a
4756
+ }
4757
+ })
4758
+ var req = avalon.mix({
4759
+ query: query,
4760
+ ext: ext,
4761
+ res: res,
4762
+ name: name,
4763
+ toUrl: toUrl
4764
+ }, config)
4765
+ req.toUrl(name)
4766
+ return req
4767
+ }
4768
+
4769
+ function fireRequest(req) {
4770
+ var name = req.name
4771
+ var res = req.res
4772
+ //1. 如果该模块已经发出请求,直接返回
4773
+ var module = modules[name]
4774
+ var urlNoQuery = name && req.urlNoQuery
4775
+ if (module && module.state >= 3) {
4776
+ return name
4777
+ }
4778
+ module = modules[urlNoQuery]
4779
+ if (module && module.state >= 3) {
4780
+ innerRequire(module.deps || [], module.factory, urlNoQuery)
4781
+ return urlNoQuery
4782
+ }
4783
+ if (name && !module) {
4784
+ module = modules[urlNoQuery] = {
4785
+ id: urlNoQuery,
4786
+ state: 1 //send
4787
+ }
4788
+ var wrap = function(obj) {
4789
+ resources[res] = obj
4790
+ obj.load(name, req, function(a) {
4791
+ if (arguments.length && a !== void 0) {
4792
+ module.exports = a
4793
+ }
4794
+ module.state = 4
4795
+ checkDeps()
4796
+ })
4797
+ }
4798
+
4799
+ if (!resources[res]) {
4800
+ innerRequire([res], wrap)
4801
+ } else {
4802
+ wrap(resources[res])
4803
+ }
4804
+ }
4805
+ return name ? urlNoQuery : res + "!"
4806
+ }
4807
+
4808
+ //核心API之一 require
4809
+ var requireQueue = []
4810
+ var isUserFirstRequire = false
4811
+ innerRequire = avalon.require = function(array, factory, parentUrl, defineConfig) {
4812
+ if (!isUserFirstRequire) {
4813
+ requireQueue.push(avalon.slice(arguments))
4814
+ if (arguments.length <= 2) {
4815
+ isUserFirstRequire = true
4816
+ var queue = requireQueue.splice(0, requireQueue.length), args
4817
+ while (args = queue.shift()) {
4818
+ innerRequire.apply(null, args)
4819
+ }
4820
+ }
4821
+ return
4822
+ }
4823
+
4715
4824
  if (!Array.isArray(array)) {
4716
- avalon.error("require的第一个参数必须是依赖列数,类型为数组 " + array)
4825
+ avalon.error("require方法的第一个参数应为数组 " + array)
4717
4826
  }
4718
- var args = [] // 放置所有依赖项的完整路径
4719
- var deps = {} // args的另一种表现形式,为的是方便去重
4827
+ var deps = [] // 放置所有依赖项的完整路径
4828
+ var uniq = {}
4720
4829
  var id = parentUrl || "callback" + setTimeout("1")
4721
- var mapUrl = parentUrl && parentUrl.replace(/\.js$/i, "")
4722
- parentUrl = getBaseUrl(parentUrl)
4723
-
4724
- array.forEach(function(el) {
4725
- var url = loadResources(el, parentUrl, mapUrl) //加载资源,并返回.能加载资源的完整路径
4726
- if (url) {
4727
- if (!deps[url]) {
4728
- args.push(url)
4729
- deps[url] = "司徒正美" //去重
4830
+ defineConfig = defineConfig || {}
4831
+ defineConfig.baseUrl = kernel.baseUrl
4832
+ var isBuilt = !!defineConfig.built
4833
+ if (parentUrl) {
4834
+ defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/"))
4835
+ defineConfig.mapUrl = parentUrl.replace(rjsext, "")
4836
+ }
4837
+ if (isBuilt) {
4838
+ var req = makeRequest(defineConfig.defineName, defineConfig)
4839
+ id = req.urlNoQuery
4840
+ } else {
4841
+ array.forEach(function(name) {
4842
+ var req = makeRequest(name, defineConfig)
4843
+ var url = fireRequest(req) //加载资源,并返回该资源的完整地址
4844
+ if (url) {
4845
+ if (!uniq[url]) {
4846
+ deps.push(url)
4847
+ uniq[url] = "司徒正美" //去重
4848
+ }
4730
4849
  }
4731
- }
4732
- })
4850
+ })
4851
+ }
4852
+
4733
4853
  var module = modules[id]
4734
- if (!module || module.state !== 2) {
4735
- modules[id] = makeModule(id, 1, factory, deps, args)//更新此模块信息
4854
+ if (!module || module.state !== 4) {
4855
+ modules[id] = {
4856
+ id: id,
4857
+ deps: isBuilt ? array.concat() : deps,
4858
+ factory: factory || noop,
4859
+ state: 3
4860
+ }
4736
4861
  }
4737
4862
  if (!module) {
4738
4863
  //如果此模块是定义在另一个JS文件中, 那必须等该文件加载完毕, 才能放到检测列队中
@@ -4740,47 +4865,58 @@ new function() {
4740
4865
  }
4741
4866
  checkDeps()
4742
4867
  }
4743
- //核心API之二 require
4744
- innerRequire.define = function(urlOrId, deps, factory) { //模块名,依赖列表,模块本身
4745
- var args = aslice.call(arguments)
4746
- if (typeof urlOrId === "string") {
4747
- var id = args.shift()
4868
+
4869
+ //核心API之二 require
4870
+ innerRequire.define = function(name, deps, factory) { //模块名,依赖列表,模块本身
4871
+ if (typeof name !== "string") {
4872
+ factory = deps
4873
+ deps = name
4874
+ name = "anonymous"
4748
4875
  }
4749
- if (typeof args[0] === "function") {
4750
- args.unshift([])
4876
+ if (!Array.isArray(deps)) {
4877
+ factory = deps
4878
+ deps = []
4751
4879
  }
4752
- //上线合并后能直接得到模块ID,否则寻找当前正在解析中的script节点的src作为模块ID
4753
- //现在除了safari5,1-外,我们都能直接通过getCurrentScript一步到位得到当前执行的script节点,
4754
- //safari可通过onload+ factory.require闭包组合解决
4755
- var url = modules[id] && modules[id].state >= 1 ? id : trimQuery(getCurrentScript())
4756
- factory = args[1]
4757
- factory.id = id //用于调试
4758
-
4759
- if (!modules[url] && id) {
4760
- //必须先行定义,并且不存在deps,用于checkCycle方法
4761
- modules[url] = makeModule(url, 1, factory)
4880
+ var config = {
4881
+ built: !isUserFirstRequire, //用r.js打包后,所有define会放到requirejs之前
4882
+ defineName: name
4762
4883
  }
4763
-
4884
+ var args = [deps, factory, config]
4764
4885
  factory.require = function(url) {
4765
- args.push(url)
4766
- var isCycle = true
4767
- try {
4768
- isCycle = checkCycle(modules[url].deps, url)
4769
- } catch (e) {
4770
- }
4771
- if (isCycle) {
4772
- avalon.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块")
4886
+ args.splice(2, 0, url)
4887
+ if (modules[url]) {
4888
+ modules[url].state = 3 //loaded
4889
+ var isCycle = false
4890
+ try {
4891
+ isCycle = checkCycle(modules[url].deps, url)
4892
+ } catch (e) {
4893
+ }
4894
+ if (isCycle) {
4895
+ avalon.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块")
4896
+ }
4773
4897
  }
4774
4898
  delete factory.require //释放内存
4775
4899
  innerRequire.apply(null, args) //0,1,2 --> 1,2,0
4776
4900
  }
4901
+ //根据标准,所有遵循W3C标准的浏览器,script标签会按标签的出现顺序执行。
4902
+ //老的浏览器中,加载也是按顺序的:一个文件下载完成后,才开始下载下一个文件。
4903
+ //较新的浏览器中(IE8+ 、FireFox3.5+ 、Chrome4+ 、Safari4+),为了减小请求时间以优化体验,
4904
+ //下载可以是并行的,但是执行顺序还是按照标签出现的顺序。
4905
+ //但如果script标签是动态插入的, 就未必按照先请求先执行的原则了,目测只有firefox遵守
4906
+ //唯一比较一致的是,IE10+及其他标准浏览器,一旦开始解析脚本, 就会一直堵在那里,直接脚本解析完毕
4907
+ //亦即,先进入loading阶段的script标签(模块)必然会先进入loaded阶段
4908
+ var url = config.built ? "unknown" : getCurrentScript()
4777
4909
  if (url) {
4910
+ var module = modules[url]
4911
+ if (module) {
4912
+ module.state = 2
4913
+ }
4778
4914
  factory.require(url)
4779
- } else { //先进先出
4915
+ } else {//合并前后的safari,合并后的IE6-9走此分支
4780
4916
  factorys.push(factory)
4781
4917
  }
4782
4918
  }
4783
- //核心API之三 require.config(settings)
4919
+ //核心API之三 require.config(settings)
4784
4920
  innerRequire.config = kernel
4785
4921
  //核心API之四 define.amd 标识其符合AMD规范
4786
4922
  innerRequire.define.amd = modules
@@ -4808,11 +4944,11 @@ new function() {
4808
4944
  var uniq = {}
4809
4945
  var ret = []
4810
4946
  for (var i = 0, pkg; pkg = array[i++]; ) {
4811
- var pkg = typeof pkg === "string" ? {name: pkg} : pkg
4947
+ pkg = typeof pkg === "string" ? {name: pkg} : pkg
4812
4948
  var name = pkg.name
4813
4949
  if (!uniq[name]) {
4814
4950
  var url = pkg.location ? pkg.location : joinPath(name, pkg.main || "main")
4815
- url = url.replace(/\.js$/i, "")
4951
+ url = url.replace(rjsext, "")
4816
4952
  ret.push(pkg)
4817
4953
  uniq[name] = pkg.location = url
4818
4954
  pkg.reg = makeMatcher(name)
@@ -4835,12 +4971,13 @@ new function() {
4835
4971
  }
4836
4972
  var node = DOC.createElement("a")
4837
4973
  node.href = url
4838
- url = "1"[0] ? node.href : node.getAttribute("href", 4)
4974
+ url = getFullUrl(node, "href")
4839
4975
  if (baseElement) {
4840
4976
  head.insertBefore(baseElement, head.firstChild)
4841
4977
  }
4842
4978
  }
4843
- kernel.baseUrl = url
4979
+ if (url.length > 3)
4980
+ kernel.baseUrl = url
4844
4981
  },
4845
4982
  shim: function(obj) {
4846
4983
  for (var i in obj) {
@@ -4851,76 +4988,21 @@ new function() {
4851
4988
  }
4852
4989
  }
4853
4990
  if (!value.exportsFn && (value.exports || value.init)) {
4854
- value.exportsFn = makeShimExports(value)
4991
+ value.exportsFn = makeExports(value)
4855
4992
  }
4856
4993
  }
4857
4994
  kernel.shim = obj
4858
- },
4859
- //三大常用资源插件 js!, css!, text!
4860
- js: function(url, shim) {
4861
- var id = trimQuery(url)
4862
- if (!modules[id]) { //如果之前没有加载过
4863
- var module = modules[id] = makeModule(id)
4864
- if (shim) { //shim机制
4865
- innerRequire(shim.deps || [], function() {
4866
- var args = avalon.slice(arguments)
4867
- loadJS(url, id, function() {
4868
- module.state = 2
4869
- if (shim.exportsFn) {
4870
- module.exports = shim.exportsFn.apply(0, args)
4871
- }
4872
- innerRequire.checkDeps()
4873
- })
4874
- })
4875
- } else {
4876
- loadJS(url, id)
4877
- }
4878
- }
4879
- return id
4880
- },
4881
- css: function(url) {
4882
- var id = trimQuery(url)
4883
- if (!DOC.getElementById(id)) {
4884
- var node = DOC.createElement("link")
4885
- node.rel = "stylesheet"
4886
- node.href = url
4887
- node.id = id
4888
- head.insertBefore(node, head.firstChild)
4889
- }
4890
- },
4891
- text: function(url) {
4892
- var id = trimQuery(url)
4893
- modules[id] = {}
4894
- var xhr = getXHR()
4895
- xhr.onreadystatechange = function() {
4896
- if (xhr.readyState === 4) {
4897
- var status = xhr.status;
4898
- if (status > 399 && status < 600) {
4899
- avalon.error(url + " 对应资源不存在或没有开启 CORS")
4900
- } else {
4901
- modules[id].state = 2
4902
- modules[id].exports = xhr.responseText
4903
- innerRequire.checkDeps()
4904
- }
4905
- }
4906
- }
4907
- xhr.open("GET", url, true)
4908
- if ("withCredentials" in xhr) {
4909
- xhr.withCredentials = true
4910
- }
4911
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
4912
- xhr.send()
4913
- return id
4914
4995
  }
4996
+
4915
4997
  })
4916
4998
 
4917
- plugins.css.ext = ".css"
4918
- plugins.js.ext = ".js"
4999
+
4919
5000
  //==============================内部方法=================================
4920
5001
  function checkCycle(deps, nick) {
4921
5002
  //检测是否存在循环依赖
4922
- for (var id in deps) {
4923
- if (deps[id] === "司徒正美" && modules[id].state !== 2 && (id === nick || checkCycle(modules[id].deps, nick))) {
5003
+ for (var i = 0, id; id = deps[i++]; ) {
5004
+ if (modules[id].state !== 4 &&
5005
+ (id === nick || checkCycle(modules[id].deps, nick))) {
4924
5006
  return true
4925
5007
  }
4926
5008
  }
@@ -4929,7 +5011,7 @@ new function() {
4929
5011
  function checkFail(node, onError, fuckIE) {
4930
5012
  var id = trimQuery(node.src) //检测是否死链
4931
5013
  node.onload = node.onreadystatechange = node.onerror = null
4932
- if (onError || (fuckIE && !modules[id].state)) {
5014
+ if (onError || (fuckIE && modules[id] && !modules[id].state)) {
4933
5015
  setTimeout(function() {
4934
5016
  head.removeChild(node)
4935
5017
  node = null // 处理旧式IE下的循环引用问题
@@ -4945,19 +5027,120 @@ new function() {
4945
5027
  loop: for (var i = loadings.length, id; id = loadings[--i]; ) {
4946
5028
  var obj = modules[id],
4947
5029
  deps = obj.deps
4948
- for (var key in deps) {
4949
- if (ohasOwn.call(deps, key) && modules[key].state !== 2) {
5030
+ if (!deps)
5031
+ continue
5032
+ for (var j = 0, key; key = deps[j]; j++) {
5033
+ var k = name2url[key]
5034
+ if (k) {
5035
+ key = deps[j] = k
5036
+ }
5037
+ if (Object(modules[key]).state !== 4) {
4950
5038
  continue loop
4951
5039
  }
4952
5040
  }
4953
5041
  //如果deps是空对象或者其依赖的模块的状态都是2
4954
- if (obj.state !== 2) {
5042
+ if (obj.state !== 4) {
4955
5043
  loadings.splice(i, 1) //必须先移除再安装,防止在IE下DOM树建完后手动刷新页面,会多次执行它
4956
- fireFactory(obj.id, obj.args, obj.factory)
5044
+ fireFactory(obj.id, obj.deps, obj.factory)
4957
5045
  checkDeps() //如果成功,则再执行一次,以防有些模块就差本模块没有安装好
4958
5046
  }
4959
5047
  }
4960
5048
  }
5049
+
5050
+ var rreadyState = DOC.documentMode >= 8 ? /loaded/ : /complete|loaded/
5051
+ function loadJS(url, id, callback) {
5052
+ //通过script节点加载目标模块
5053
+ var node = DOC.createElement("script")
5054
+ node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点
5055
+ var timeID
5056
+ var supportLoad = "onload" in node
5057
+ var onEvent = supportLoad ? "onload" : "onreadystatechange"
5058
+ function onload() {
5059
+ if (!"1"[0] && !timeID) {
5060
+ return timeID = setTimeout(onload, 150)
5061
+ }
5062
+ if (supportLoad || rreadyState.test(node.readyState)) {
5063
+ clearTimeout(timeID)
5064
+ var factory = factorys.pop()
5065
+ factory && factory.require(id)
5066
+ if (callback) {
5067
+ callback()
5068
+ }
5069
+ if (checkFail(node, false, !supportLoad)) {
5070
+ log("debug: 已成功加载 " + url)
5071
+ id && loadings.push(id)
5072
+ checkDeps()
5073
+ }
5074
+ }
5075
+ }
5076
+ node[onEvent] = onload
5077
+ node.onerror = function() {
5078
+ checkFail(node, true)
5079
+ }
5080
+
5081
+ head.insertBefore(node, head.firstChild) //chrome下第二个参数不能为null
5082
+ node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错
5083
+ log("debug: 正准备加载 " + url) //更重要的是IE6下可以收窄getCurrentScript的寻找范围
5084
+ }
5085
+
5086
+ var resources = innerRequire.plugins = {
5087
+ //三大常用资源插件 js!, css!, text!, ready!
5088
+ ready: {
5089
+ load: noop
5090
+ },
5091
+ js: {
5092
+ load: function(name, req, onLoad) {
5093
+ var url = req.url
5094
+ var id = req.urlNoQuery
5095
+ var shim = kernel.shim[name.replace(rjsext, "")]
5096
+ if (shim) { //shim机制
5097
+ innerRequire(shim.deps || [], function() {
5098
+ var args = avalon.slice(arguments)
5099
+ loadJS(url, id, function() {
5100
+ onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0)
5101
+ })
5102
+ })
5103
+ } else {
5104
+ loadJS(url, id)
5105
+ }
5106
+ }
5107
+ },
5108
+ css: {
5109
+ load: function(name, req, onLoad) {
5110
+ var url = req.url
5111
+ var node = DOC.createElement("link")
5112
+ node.rel = "stylesheet"
5113
+ node.href = url
5114
+ head.insertBefore(node, head.firstChild)
5115
+ log("debug: 已成功加载 " + url)
5116
+ onLoad()
5117
+ }
5118
+ },
5119
+ text: {
5120
+ load: function(name, req, onLoad) {
5121
+ var url = req.url
5122
+ var xhr = getXHR()
5123
+ xhr.onreadystatechange = function() {
5124
+ if (xhr.readyState === 4) {
5125
+ var status = xhr.status;
5126
+ if (status > 399 && status < 600) {
5127
+ avalon.error(url + " 对应资源不存在或没有开启 CORS")
5128
+ } else {
5129
+ log("debug: 已成功加载 " + url)
5130
+ onLoad(xhr.responseText)
5131
+ }
5132
+ }
5133
+ }
5134
+ xhr.open("GET", url, true)
5135
+ if ("withCredentials" in xhr) {//这是处理跨域
5136
+ xhr.withCredentials = true
5137
+ }
5138
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉后端这是AJAX请求
5139
+ xhr.send()
5140
+ log("debug: 正准备加载 " + url)
5141
+ }
5142
+ }
5143
+ }
4961
5144
  innerRequire.checkDeps = checkDeps
4962
5145
 
4963
5146
  var rquery = /(\?[^#]*)$/
@@ -4970,19 +5153,16 @@ new function() {
4970
5153
  return /^(?:[a-z]+:)?\/\//i.test(String(path))
4971
5154
  }
4972
5155
 
4973
- function getBaseUrl(parentUrl) {
4974
- return parentUrl ?
4975
- parentUrl.substr(0, parentUrl.lastIndexOf("/")) :
4976
- kernel.baseUrl ? kernel.baseUrl :
4977
- kernel.loaderUrl
5156
+ function getFullUrl(node, src) {
5157
+ return"1"[0] ? node[src] : node.getAttribute(src, 4)
4978
5158
  }
4979
5159
 
4980
- function getCurrentScript(base) {
5160
+ function getCurrentScript() {
4981
5161
  // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js
4982
5162
  var stack
4983
5163
  try {
4984
5164
  a.b.c() //强制报错,以便捕获e.stack
4985
- } catch (e) { //safari的错误对象只有line,sourceId,sourceURL
5165
+ } catch (e) { //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样
4986
5166
  stack = e.stack
4987
5167
  if (!stack && window.opera) {
4988
5168
  //opera 9没有e.stack,但有e.Backtrace,但不能直接取得,需要对e对象转字符串进行抽取
@@ -5003,116 +5183,83 @@ new function() {
5003
5183
  */
5004
5184
  stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分
5005
5185
  stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉换行符
5006
- return stack.replace(/(:\d+)?:\d+$/i, "") //去掉行号与或许存在的出错字符起始位置
5186
+ return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行号与或许存在的出错字符起始位置
5007
5187
  }
5008
- var nodes = (base ? DOC : head).getElementsByTagName("script") //只在head标签中寻找
5188
+ var nodes = head.getElementsByTagName("script") //只在head标签中寻找
5009
5189
  for (var i = nodes.length, node; node = nodes[--i]; ) {
5010
- if ((base || node.className === subscribers) && node.readyState === "interactive") {
5011
- var url = "1"[0] ? node.src : node.getAttribute("src", 4)
5012
- return node.className = url
5190
+ if (node.className === subscribers && node.readyState === "interactive") {
5191
+ var url = getFullUrl(node, "src")
5192
+ return node.className = trimQuery(url)
5013
5193
  }
5014
5194
  }
5015
5195
  }
5016
5196
 
5017
- function loadResources(url, parentUrl, mapUrl) {
5018
- //1. 特别处理ready标识符及已经加载好的模块
5019
- if (url === "ready!" || (modules[url] && modules[url].state === 2)) {
5020
- return url
5197
+
5198
+ function fireFactory(id, deps, factory) {
5199
+ var module = Object(modules[id])
5200
+ module.state = 4
5201
+ for (var i = 0, array = [], d; d = deps[i++]; ) {
5202
+ d = name2url[d] || d
5203
+ if (d === "exports") {
5204
+ var obj = module.exports || (module.exports = {})
5205
+ array.push(obj)
5206
+ } else {
5207
+ array.push(modules[d].exports)
5208
+ }
5021
5209
  }
5022
- //2. 获取模块ID(去掉资源前缀,扩展名 hash, query)
5023
- var res = "js"
5024
- url = url.replace(/^(\w+)\!/, function(a, b) {
5025
- res = b
5026
- return ""
5027
- })
5028
- var plugin = plugins[res] || noop
5029
- var query = ""
5030
- var id = url.replace(rquery, function(a) {
5031
- query = a
5032
- return ""
5033
- })
5034
- var ext = ""
5035
- if (res === "js") {
5036
- url = id = id.replace(/\.js$/i, "")
5037
- ext = ".js"
5210
+ var ret = factory.apply(window, array)
5211
+ if (ret !== void 0) {
5212
+ module.exports = ret
5213
+ }
5214
+ delete module.factory
5215
+ return ret
5216
+ }
5217
+ function toUrl(id) {
5218
+ if (id.indexOf(this.res + "!") === 0) {
5219
+ id = id.slice(this.res.length + 1) //处理define("css!style",[], function(){})的情况
5038
5220
  }
5039
- //3. 是否命中paths配置项
5221
+ var url = id
5222
+ //1. 是否命中paths配置项
5040
5223
  var usePath = 0
5224
+ var baseUrl = this.baseUrl
5225
+ var rootUrl = this.parentUrl || baseUrl
5041
5226
  eachIndexArray(id, kernel.paths, function(value, key) {
5042
5227
  url = url.replace(key, value)
5043
5228
  usePath = 1
5044
5229
  })
5045
- //4. 是否命中packages配置项
5230
+ //2. 是否命中packages配置项
5046
5231
  if (!usePath) {
5047
5232
  eachIndexArray(id, kernel.packages, function(value, key, item) {
5048
5233
  url = url.replace(item.name, item.location)
5049
5234
  })
5050
5235
  }
5051
- //5. 是否命中map配置项
5052
- if (mapUrl) {
5053
- eachIndexArray(mapUrl, kernel.map, function(array) {
5236
+ //3. 是否命中map配置项
5237
+ if (this.mapUrl) {
5238
+ eachIndexArray(this.mapUrl, kernel.map, function(array) {
5054
5239
  eachIndexArray(url, array, function(mdValue, mdKey) {
5055
5240
  url = url.replace(mdKey, mdValue)
5241
+ rootUrl = baseUrl
5056
5242
  })
5057
5243
  })
5058
5244
  }
5059
- //6. 转换为绝对路径
5245
+ var ext = this.ext
5246
+ if (ext && usePath && url.slice(-ext.length) === ext) {
5247
+ url = url.slice(0, -ext.length)
5248
+ }
5249
+ //4. 转换为绝对路径
5060
5250
  if (!isAbsUrl(url)) {
5061
- url = joinPath(/\w/.test(url.charAt(0)) ? getBaseUrl() : parentUrl, url)
5251
+ rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl
5252
+ url = joinPath(rootUrl, url)
5062
5253
  }
5063
- //7. 还原扩展名,query
5064
- url += ext + query
5065
- //8. 处理urlArgs
5254
+ //5. 还原扩展名,query
5255
+ var urlNoQuery = url + ext
5256
+ url = urlNoQuery + this.query
5257
+ //6. 处理urlArgs
5066
5258
  eachIndexArray(id, kernel.urlArgs, function(value) {
5067
5259
  url += (url.indexOf("?") === -1 ? "?" : "&") + value;
5068
5260
  })
5069
- return plugin(url, kernel.shim[id])
5070
- }
5071
-
5072
- function loadJS(url, id, callback) {
5073
- //通过script节点加载目标模块
5074
- var node = DOC.createElement("script")
5075
- node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点
5076
- node[W3C ? "onload" : "onreadystatechange"] = function() {
5077
- if (W3C || /loaded|complete/i.test(node.readyState)) {
5078
- //mass Framework会在_checkFail把它上面的回调清掉,尽可能释放回存,尽管DOM0事件写法在IE6下GC无望
5079
- var factory = factorys.pop()
5080
-
5081
- factory && factory.require(id)
5082
- if (callback) {
5083
- callback()
5084
- }
5085
- if (checkFail(node, false, !W3C)) {
5086
- log("debug: 已成功加载 " + url)
5087
- loadings.push(id)
5088
- checkDeps()
5089
- }
5090
- }
5091
- }
5092
- node.onerror = function() {
5093
- checkFail(node, true)
5094
- }
5095
- node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错
5096
- head.insertBefore(node, head.firstChild) //chrome下第二个参数不能为null
5097
- log("debug: 正准备加载 " + url) //更重要的是IE6下可以收窄getCurrentScript的寻找范围
5098
- }
5099
-
5100
- function fireFactory(id, deps, factory) {
5101
- var module = Object(modules[id])
5102
- module.state = 2
5103
- for (var i = 0, array = [], d; d = deps[i++]; ) {
5104
- if (d === "exports") {
5105
- var obj = module.exports || (module.exports = {})
5106
- array.push(obj)
5107
- } else {
5108
- array.push(modules[d].exports)
5109
- }
5110
- }
5111
- var ret = factory.apply(window, array)
5112
- if (ret !== void 0) {
5113
- modules[id].exports = ret
5114
- }
5115
- return ret
5261
+ this.url = url
5262
+ return this.urlNoQuery = urlNoQuery
5116
5263
  }
5117
5264
 
5118
5265
  function makeIndexArray(hash, useStar, part) {
@@ -5126,7 +5273,7 @@ new function() {
5126
5273
  return new RegExp('^' + prefix + '(/|$)')
5127
5274
  }
5128
5275
 
5129
- function makeShimExports(value) {
5276
+ function makeExports(value) {
5130
5277
  return function() {
5131
5278
  var ret
5132
5279
  if (value.init) {
@@ -5136,15 +5283,6 @@ new function() {
5136
5283
  }
5137
5284
  }
5138
5285
 
5139
- function makeModule(id, state, factory, deps, args) {
5140
- return {
5141
- id: id,
5142
- state: state || 1,
5143
- factory: factory || noop,
5144
- deps: deps || {},
5145
- args: args || []
5146
- }
5147
- }
5148
5286
 
5149
5287
  function hash2array(hash, useStar, part) {
5150
5288
  var array = [];
@@ -5155,9 +5293,7 @@ new function() {
5155
5293
  val: hash[key]
5156
5294
  }
5157
5295
  array.push(item)
5158
- item.reg = key === "*" && useStar
5159
- ? /^/
5160
- : makeMatcher(key)
5296
+ item.reg = key === "*" && useStar ? /^/ : makeMatcher(key)
5161
5297
  if (part && key !== "*") {
5162
5298
  item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)')
5163
5299
  }
@@ -5220,14 +5356,17 @@ new function() {
5220
5356
  return g
5221
5357
  }
5222
5358
 
5223
-
5224
- var cur = getCurrentScript(true) //求得当前avalon.js 所在的JS文件的路径
5225
- if (!cur) { //处理window safari的Error没有stack的问题
5226
- cur = DOC.scripts[DOC.scripts.length - 1].src
5359
+ var mainNode = DOC.scripts[DOC.scripts.length - 1]
5360
+ var dataMain = mainNode.getAttribute("data-main")
5361
+ if (dataMain) {
5362
+ plugins.baseUrl(dataMain)
5363
+ var href = kernel.baseUrl
5364
+ kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1)
5365
+ loadJS(href.replace(rjsext, "") + ".js")
5366
+ } else {
5367
+ var loaderUrl = trimQuery(getFullUrl(mainNode, "src"))
5368
+ kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1)
5227
5369
  }
5228
- var url = trimQuery(cur)
5229
- kernel.loaderUrl = url.slice(0, url.lastIndexOf("/") + 1)
5230
-
5231
5370
  }
5232
5371
 
5233
5372
  /*********************************************************************
@@ -5238,13 +5377,12 @@ var readyList = []
5238
5377
  function fireReady() {
5239
5378
  if (DOC.body) { // 在IE8 iframe中doScrollCheck可能不正确
5240
5379
  if (innerRequire) {
5241
- modules["ready!"].state = 2
5380
+ modules["domReady!"].state = 4
5242
5381
  innerRequire.checkDeps()
5243
- } else {
5244
- readyList.forEach(function(a) {
5245
- a(avalon)
5246
- })
5247
5382
  }
5383
+ readyList.forEach(function(a) {
5384
+ a(avalon)
5385
+ })
5248
5386
  fireReady = noop //隋性函数,防止IE9二次调用_checkDeps
5249
5387
  }
5250
5388
  }
@@ -5268,23 +5406,18 @@ if (DOC.readyState === "complete") {
5268
5406
  fireReady()
5269
5407
  }
5270
5408
  })
5271
- var isFrame;
5272
5409
  try {
5273
- isFrame = window.frameElement != null//当前页面处于iframe中时,访问frameElement会抛出不允许跨域访问异常
5274
- }
5275
- catch (e) {
5276
- isFrame = true
5410
+ var isTop = window.frameElement === null
5411
+ } catch (e) {
5277
5412
  }
5278
- if (root.doScroll && !isFrame) {//只有不处于iframe时才用doScroll判断,否则可能会不准
5413
+ if (root.doScroll && isTop && window.external) {//只有不处于iframe时才用doScroll判断,否则可能会不准
5279
5414
  doScrollCheck()
5280
5415
  }
5281
5416
  }
5282
5417
  avalon.bind(window, "load", fireReady)
5283
5418
 
5284
5419
  avalon.ready = function(fn) {
5285
- if (innerRequire) {
5286
- innerRequire(["ready!"], fn)
5287
- } else if (fireReady === noop) {
5420
+ if (fireReady === noop) {
5288
5421
  fn(avalon)
5289
5422
  } else {
5290
5423
  readyList.push(fn)
@@ -5331,4 +5464,4 @@ avalon.ready(function() {
5331
5464
  }
5332
5465
  return avalon
5333
5466
 
5334
- }));
5467
+ }));