avalon-rails 1.3.9.1 → 1.3.9.1.20150212184918

Sign up to get free protection for your applications and to get access to all the features.
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
+ }));