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.
@@ -5,9 +5,8 @@
5
5
  http://weibo.com/jslouvre/
6
6
 
7
7
  Released under the MIT license
8
- avalon.modern.js 1.391 build in 2015.1.31
9
- _____________________________
10
- support IE6+ and other browsers
8
+ avalon.modern.js 1.391 built in 2015.2.12
9
+ support IE10+ and other browsers
11
10
  ==================================================*/
12
11
  (function(global, factory) {
13
12
 
@@ -38,7 +37,7 @@ var expose = Date.now()
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.head //HEAD元素
41
- head.insertAdjacentHTML("afterBegin", '<avalon ms-skip><style id="avalonStyle">.avalonHide{ display: none!important }</style></avalon>')
40
+ head.insertAdjacentHTML("afterBegin", '<avalon ms-skip class="avalonHide"><style id="avalonStyle">.avalonHide{ display: none!important }</style></avalon>')
42
41
  var ifGroup = head.firstChild
43
42
 
44
43
  function log() {
@@ -135,7 +134,7 @@ avalon.type = function(obj) { //取得目标的类型
135
134
  }
136
135
 
137
136
  var isFunction = function(fn) {
138
- return serialize.call(fn) == "[object Function]"
137
+ return serialize.call(fn) === "[object Function]"
139
138
  }
140
139
 
141
140
  avalon.isFunction = isFunction
@@ -245,7 +244,7 @@ avalon.mix({
245
244
  }
246
245
  var index = -1,
247
246
  length = Math.max(0, Math.ceil((end - start) / step)),
248
- result = Array(length)
247
+ result = new Array(length)
249
248
  while (++index < length) {
250
249
  result[index] = start
251
250
  start += step
@@ -285,10 +284,10 @@ avalon.mix({
285
284
  if (node instanceof avalon) {
286
285
  node = node[0]
287
286
  }
288
- var prop = /[_-]/.test(name) ? camelize(name) : name
287
+ var prop = /[_-]/.test(name) ? camelize(name) : name, fn
289
288
  name = avalon.cssName(prop) || prop
290
289
  if (value === void 0 || typeof value === "boolean") { //获取样式
291
- var fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
290
+ fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
292
291
  if (name === "background") {
293
292
  name = "backgroundColor"
294
293
  }
@@ -318,7 +317,7 @@ avalon.mix({
318
317
  }
319
318
  } else {
320
319
  for (i in obj) {
321
- if (obj.hasOwnProperty(i) && fn(i, obj[i] === false)) {
320
+ if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) {
322
321
  break
323
322
  }
324
323
  }
@@ -619,7 +618,7 @@ var EventBus = {
619
618
  return this
620
619
  },
621
620
  $fire: function(type) {
622
- var special
621
+ var special, i, v, callback
623
622
  if (/^(\w+)!(\S+)$/.test(type)) {
624
623
  special = RegExp.$1
625
624
  type = RegExp.$2
@@ -628,8 +627,8 @@ var EventBus = {
628
627
  var args = aslice.call(arguments, 1)
629
628
  var detail = [type].concat(args)
630
629
  if (special === "all") {
631
- for (var i in avalon.vmodels) {
632
- var v = avalon.vmodels[i]
630
+ for (i in avalon.vmodels) {
631
+ v = avalon.vmodels[i]
633
632
  if (v !== this) {
634
633
  v.$fire.apply(v, detail)
635
634
  }
@@ -638,8 +637,8 @@ var EventBus = {
638
637
  var elements = events.expr ? findNodes(events.expr) : []
639
638
  if (elements.length === 0)
640
639
  return
641
- for (var i in avalon.vmodels) {
642
- var v = avalon.vmodels[i]
640
+ for (i in avalon.vmodels) {
641
+ v = avalon.vmodels[i]
643
642
  if (v !== this) {
644
643
  if (v.$events.expr) {
645
644
  var eventNodes = findNodes(v.$events.expr)
@@ -672,19 +671,19 @@ var EventBus = {
672
671
  if (special === "up") {
673
672
  alls.reverse()
674
673
  }
675
- for (var i = 0, el; el = alls[i++]; ) {
676
- if (el.$fire.apply(el, detail) === false) {
674
+ for (i = 0; callback = alls[i++]; ) {
675
+ if (callback.$fire.apply(callback, detail) === false) {
677
676
  break
678
677
  }
679
678
  }
680
679
  } else {
681
680
  var callbacks = events[type] || []
682
681
  var all = events.$all || []
683
- for (var i = 0, callback; callback = callbacks[i++]; ) {
682
+ for (i = 0; callback = callbacks[i++]; ) {
684
683
  if (isFunction(callback))
685
684
  callback.apply(this, args)
686
685
  }
687
- for (var i = 0, callback; callback = all[i++]; ) {
686
+ for (i = 0; callback = all[i++]; ) {
688
687
  if (isFunction(callback))
689
688
  callback.apply(this, arguments)
690
689
  }
@@ -852,7 +851,7 @@ function modelFactory(source, $special, $model) {
852
851
  } else {
853
852
  if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性
854
853
  //计算属性不需要收集视图刷新函数,都是由其他监控属性代劳
855
- var newValue = accessor.get.call($vmodel)
854
+ newValue = accessor.get.call($vmodel)
856
855
  if (oldValue !== newValue) {
857
856
  $model[name] = newValue
858
857
  //这里不用同步视图
@@ -884,12 +883,12 @@ function modelFactory(source, $special, $model) {
884
883
  initCallbacks.push(function() {
885
884
  var data = {
886
885
  evaluator: function() {
887
- data.type = new Date - 0
886
+ data.type = Math.random(),
888
887
  data.element = null
889
888
  $model[name] = accessor.get.call($vmodel)
890
889
  },
891
890
  element: head,
892
- type: new Date - 0,
891
+ type: Math.random(),
893
892
  handler: noop,
894
893
  args: []
895
894
  }
@@ -930,7 +929,7 @@ function modelFactory(source, $special, $model) {
930
929
  $vmodel.$id = generateID()
931
930
  $vmodel.$model = $model
932
931
  $vmodel.$events = $events
933
- for (var i in EventBus) {
932
+ for ( i in EventBus) {
934
933
  var fn = EventBus[i]
935
934
  if (!W3C) { //在IE6-8下,VB对象的方法里的this并不指向自身,需要用bind处理一下
936
935
  fn = fn.bind($vmodel)
@@ -1372,7 +1371,7 @@ function removeSubscribers() {
1372
1371
  if (diff) {
1373
1372
  //avalon.log("有需要移除的元素")
1374
1373
  while (obj = $$subscribers[--i]) {
1375
- var data = obj.data
1374
+ data = obj.data
1376
1375
  if (data.element === void 0)
1377
1376
  continue
1378
1377
  if (needTest[data.type] && isRemove(data.element)) { //如果它没有在DOM树
@@ -1576,50 +1575,6 @@ function bindingSorter(a, b) {
1576
1575
  return a.priority - b.priority
1577
1576
  }
1578
1577
 
1579
- function scanTag(elem, vmodels, node) {
1580
- //扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
1581
- //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
1582
- var a = elem.getAttribute("ms-skip")
1583
- var b = elem.getAttributeNode("ms-important")
1584
- var c = elem.getAttributeNode("ms-controller")
1585
- if (typeof a === "string") {
1586
- return
1587
- } else if (node = b || c) {
1588
- var newVmodel = avalon.vmodels[node.value]
1589
- if (!newVmodel) {
1590
- return
1591
- }
1592
- //ms-important不包含父VM,ms-controller相反
1593
- vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
1594
- elem.removeAttribute(node.name) //removeAttributeNode不会刷新[ms-controller]样式规则
1595
- elem.classList.remove(node.name)
1596
- createSignalTower(elem, newVmodel)
1597
- }
1598
- scanAttr(elem, vmodels) //扫描特性节点
1599
- }
1600
- function scanNodeList(parent, vmodels) {
1601
- var node = parent.firstChild
1602
- while (node) {
1603
- var nextNode = node.nextSibling
1604
- scanNode(node, node.nodeType, vmodels)
1605
- node = nextNode
1606
- }
1607
- }
1608
-
1609
- function scanNodeArray(nodes, vmodels) {
1610
- for (var i = 0, node; node = nodes[i++]; ) {
1611
- scanNode(node, node.nodeType, vmodels)
1612
- }
1613
- }
1614
- function scanNode(node, nodeType, vmodels) {
1615
- if (nodeType === 1) {
1616
- scanTag(node, vmodels) //扫描元素节点
1617
- } else if (nodeType === 3 && rexpr.test(node.data)){
1618
- scanText(node, vmodels) //扫描文本节点
1619
- } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) {
1620
- scanText(node, vmodels) //扫描注释节点
1621
- }
1622
- }
1623
1578
  function scanAttr(elem, vmodels) {
1624
1579
  //防止setAttribute, removeAttribute时 attributes自动被同步,导致for循环出错
1625
1580
  var attributes = elem.hasAttributes() ? avalon.slice(elem.attributes) : []
@@ -1688,8 +1643,8 @@ function scanAttr(elem, vmodels) {
1688
1643
  }
1689
1644
  bindings.sort(bindingSorter)
1690
1645
  var scanNode = true
1691
- for (var i = 0, binding; binding = bindings[i]; i++) {
1692
- var type = binding.type
1646
+ for (i = 0; binding = bindings[i]; i++) {
1647
+ type = binding.type
1693
1648
  if (rnoscanAttrBinding.test(type)) {
1694
1649
  return executeBindings(bindings.slice(0, i + 1), vmodels)
1695
1650
  } else if (scanNode) {
@@ -1705,14 +1660,61 @@ function scanAttr(elem, vmodels) {
1705
1660
 
1706
1661
  var rnoscanAttrBinding = /^if|widget|repeat$/
1707
1662
  var rnoscanNodeBinding = /^each|with|html|include$/
1663
+ function scanNodeList(parent, vmodels) {
1664
+ var node = parent.firstChild
1665
+ while (node) {
1666
+ var nextNode = node.nextSibling
1667
+ scanNode(node, node.nodeType, vmodels)
1668
+ node = nextNode
1669
+ }
1670
+ }
1671
+
1672
+ function scanNodeArray(nodes, vmodels) {
1673
+ for (var i = 0, node; node = nodes[i++]; ) {
1674
+ scanNode(node, node.nodeType, vmodels)
1675
+ }
1676
+ }
1677
+ function scanNode(node, nodeType, vmodels) {
1678
+ if (nodeType === 1) {
1679
+ scanTag(node, vmodels) //扫描元素节点
1680
+ } else if (nodeType === 3 && rexpr.test(node.data)){
1681
+ scanText(node, vmodels) //扫描文本节点
1682
+ } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) {
1683
+ scanText(node, vmodels) //扫描注释节点
1684
+ }
1685
+ }
1686
+ function scanTag(elem, vmodels, node) {
1687
+ //扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
1688
+ //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
1689
+ var a = elem.getAttribute("ms-skip")
1690
+ var b = elem.getAttributeNode("ms-important")
1691
+ var c = elem.getAttributeNode("ms-controller")
1692
+ if (typeof a === "string") {
1693
+ return
1694
+ } else if (node = b || c) {
1695
+ var newVmodel = avalon.vmodels[node.value]
1696
+ if (!newVmodel) {
1697
+ return
1698
+ }
1699
+ //ms-important不包含父VM,ms-controller相反
1700
+ vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
1701
+ elem.removeAttribute(node.name) //removeAttributeNode不会刷新[ms-controller]样式规则
1702
+ elem.classList.remove(node.name)
1703
+ createSignalTower(elem, newVmodel)
1704
+ }
1705
+ scanAttr(elem, vmodels) //扫描特性节点
1706
+ }
1708
1707
  var rhasHtml = /\|\s*html\s*/,
1709
1708
  r11a = /\|\|/g,
1710
1709
  rlt = /&lt;/g,
1711
1710
  rgt = /&gt;/g
1712
-
1711
+ rstringLiteral = /(['"])(\\\1|.)+?\1/g
1713
1712
  function getToken(value) {
1714
1713
  if (value.indexOf("|") > 0) {
1715
- var index = value.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
1714
+ var scapegoat = value.replace( rstringLiteral, function(_){
1715
+ return Math.pow(10,_.length)
1716
+ })
1717
+ var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
1716
1718
  if (index > -1) {
1717
1719
  return {
1718
1720
  filters: value.slice(index),
@@ -1776,7 +1778,7 @@ function scanText(textNode, vmodels) {
1776
1778
  tokens = scanExpr(textNode.data)
1777
1779
  }
1778
1780
  if (tokens.length) {
1779
- for (var i = 0, token; token = tokens[i++]; ) {
1781
+ for (var i = 0; token = tokens[i++]; ) {
1780
1782
  var node = DOC.createTextNode(token.value) //将文本转换为文本节点,并替换原来的文本节点
1781
1783
  if (token.expr) {
1782
1784
  token.type = "text"
@@ -2226,14 +2228,14 @@ var keywords =
2226
2228
  // 关键字
2227
2229
  "break,case,catch,continue,debugger,default,delete,do,else,false" +
2228
2230
  ",finally,for,function,if,in,instanceof,new,null,return,switch,this" +
2229
- ",throw,true,try,typeof,var,void,while,with"
2231
+ ",throw,true,try,typeof,var,void,while,with" +
2230
2232
  // 保留字
2231
- + ",abstract,boolean,byte,char,class,const,double,enum,export,extends" +
2233
+ ",abstract,boolean,byte,char,class,const,double,enum,export,extends" +
2232
2234
  ",final,float,goto,implements,import,int,interface,long,native" +
2233
2235
  ",package,private,protected,public,short,static,super,synchronized" +
2234
- ",throws,transient,volatile"
2236
+ ",throws,transient,volatile" +
2235
2237
  // ECMA 5 - use strict
2236
- + ",arguments,let,yield" + ",undefined"
2238
+ ",arguments,let,yield" + ",undefined"
2237
2239
  var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g
2238
2240
  var rsplit = /[^\w$]+/g
2239
2241
  var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g')
@@ -2373,7 +2375,7 @@ function parseExpr(code, scopes, data) {
2373
2375
  data.evaluator = fn
2374
2376
  return
2375
2377
  }
2376
- var prefix = assigns.join(", ")
2378
+ prefix = assigns.join(", ")
2377
2379
  if (prefix) {
2378
2380
  prefix = "var " + prefix
2379
2381
  }
@@ -2441,12 +2443,6 @@ function parseExprProxy(code, scopes, data, tokens, noregister) {
2441
2443
  }
2442
2444
  }
2443
2445
  avalon.parseExprProxy = parseExprProxy
2444
- /*********************************************************************
2445
- * 各种指令 *
2446
- **********************************************************************/
2447
- //ms-skip绑定已经在scanTag 方法中实现
2448
- //ms-controller绑定已经在scanTag 方法中实现
2449
- //ms-important绑定已经在scanTag 方法中实现
2450
2446
  var bools = "autofocus,autoplay,async,allowTransparency,checked,controls,declare,disabled,defer,defaultChecked,defaultSelected" +
2451
2447
  "contentEditable,isMap,loop,multiple,noHref,noResize,noShade,open,readOnly,selected"
2452
2448
  var boolMap = {}
@@ -2544,7 +2540,7 @@ bindingExecutors.attr = function(val, elem, data) {
2544
2540
  var loaded = data.includeLoaded
2545
2541
  var replace = data.includeReplaced
2546
2542
  var target = replace ? elem.parentNode : elem
2547
- function scanTemplate(text) {
2543
+ var scanTemplate = function(text) {
2548
2544
  if (loaded) {
2549
2545
  text = loaded.apply(target, [text].concat(vmodels))
2550
2546
  }
@@ -2594,7 +2590,7 @@ bindingExecutors.attr = function(val, elem, data) {
2594
2590
  var el = val && val.nodeType === 1 ? val : DOC.getElementById(val)
2595
2591
  if (el) {
2596
2592
  if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法取得其内容,IE6能取得其innerHTML
2597
- var xhr = getXHR() //IE9-11与chrome的innerHTML会得到转义的内容,它们的innerText可以
2593
+ xhr = getXHR() //IE9-11与chrome的innerHTML会得到转义的内容,它们的innerText可以
2598
2594
  xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构
2599
2595
  xhr.send(null)
2600
2596
  //http://bbs.csdn.net/topics/390349046?page=1#post-393492653
@@ -2632,8 +2628,6 @@ bindingExecutors.attr = function(val, elem, data) {
2632
2628
  "title,alt,src,value,css,include,href".replace(rword, function(name) {
2633
2629
  bindingHandlers[name] = bindingHandlers.attr
2634
2630
  })
2635
- //ms-include绑定已由ms-attr绑定实现
2636
-
2637
2631
  //根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
2638
2632
  //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
2639
2633
  bindingHandlers["class"] = function(data, vmodels) {
@@ -2724,6 +2718,10 @@ bindingExecutors ["class"] = function(val, elem, data) {
2724
2718
  "hover,active".replace(rword, function(method) {
2725
2719
  bindingHandlers[method] = bindingHandlers["class"]
2726
2720
  })
2721
+ //ms-controller绑定已经在scanTag 方法中实现
2722
+ //ms-css绑定已由ms-attr绑定实现
2723
+
2724
+
2727
2725
  // bindingHandlers.data 定义在if.js
2728
2726
  bindingExecutors.data = function(val, elem, data) {
2729
2727
  var key = "data-" + data.param
@@ -2734,357 +2732,107 @@ bindingExecutors.data = function(val, elem, data) {
2734
2732
  }
2735
2733
  }
2736
2734
 
2737
- // bindingHandlers.text 定义在if.js
2738
- bindingExecutors.text = function(val, elem) {
2739
- val = val == null ? "" : val //不在页面上显示undefined null
2740
- if (elem.nodeType === 3) { //绑定在文本节点上
2741
- try { //IE对游离于DOM树外的节点赋值会报错
2742
- elem.data = val
2743
- } catch (e) {
2744
- }
2745
- } else { //绑定在特性节点上
2746
- elem.textContent = val
2747
- }
2748
- }
2735
+ //双工绑定
2736
+ var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
2737
+ var elem = data.element,
2738
+ hasCast
2739
+ parseExprProxy(data.value, vmodels, data, 0, 1)
2749
2740
 
2750
- // bindingHandlers.html 定义在if.js
2751
- bindingExecutors.html = function(val, elem, data) {
2752
- val = val == null ? "" : val
2753
- var isHtmlFilter = "group" in data
2754
- var parent = isHtmlFilter ? elem.parentNode : elem
2755
- if (!parent)
2756
- return
2757
- if (val.nodeType === 11) { //将val转换为文档碎片
2758
- var fragment = val
2759
- } else if (val.nodeType === 1 || val.item) {
2760
- var nodes = val.nodeType === 1 ? val.childNodes : val.item ? val : []
2761
- fragment = hyperspace.cloneNode(true)
2762
- while (nodes[0]) {
2763
- fragment.appendChild(nodes[0])
2741
+ data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
2742
+ if (data.evaluator && data.args) {
2743
+ var params = []
2744
+ var casting = oneObject("string,number,boolean,checked")
2745
+ if (elem.type === "radio" && data.param === "") {
2746
+ data.param = "checked"
2764
2747
  }
2765
- } else {
2766
- fragment = avalon.parseHTML(val)
2767
- }
2768
- //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空
2769
- var comment = DOC.createComment("ms-html")
2770
- if (isHtmlFilter) {
2771
- parent.insertBefore(comment, elem)
2772
- var n = data.group, i = 1
2773
- while (i < n) {
2774
- var node = elem.nextSibling
2775
- if (node) {
2776
- parent.removeChild(node)
2777
- i++
2748
+ if (elem.msData) {
2749
+ elem.msData["ms-duplex"] = data.value
2750
+ }
2751
+ data.param.replace(/\w+/g, function(name) {
2752
+ if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
2753
+ if (name === "radio")
2754
+ log("ms-duplex-radio已经更名为ms-duplex-checked")
2755
+ name = "checked"
2756
+ data.isChecked = true
2757
+ }
2758
+ if (name === "bool") {
2759
+ name = "boolean"
2760
+ log("ms-duplex-bool已经更名为ms-duplex-boolean")
2761
+ } else if (name === "text") {
2762
+ name = "string"
2763
+ log("ms-duplex-text已经更名为ms-duplex-string")
2778
2764
  }
2765
+ if (casting[name]) {
2766
+ hasCast = true
2767
+ }
2768
+ avalon.Array.ensure(params, name)
2769
+ })
2770
+ if (!hasCast) {
2771
+ params.push("string")
2779
2772
  }
2780
- parent.removeChild(elem)
2781
- data.element = comment //防止被CG
2782
- } else {
2783
- avalon.clearHTML(parent).appendChild(comment)
2784
- }
2785
- if (isHtmlFilter) {
2786
- data.group = fragment.childNodes.length || 1
2773
+ data.param = params.join("-")
2774
+ data.bound = function(type, callback) {
2775
+ if (elem.addEventListener) {
2776
+ elem.addEventListener(type, callback, false)
2777
+ } else {
2778
+ elem.attachEvent("on" + type, callback)
2779
+ }
2780
+ var old = data.rollback
2781
+ data.rollback = function() {
2782
+ elem.avalonSetter = null
2783
+ avalon.unbind(elem, type, callback)
2784
+ old && old()
2785
+ }
2786
+ }
2787
+ for (var i in avalon.vmodels) {
2788
+ var v = avalon.vmodels[i]
2789
+ v.$fire("avalon-ms-duplex-init", data)
2790
+ }
2791
+ var cpipe = data.pipe || (data.pipe = pipe)
2792
+ cpipe(null, data, "init")
2793
+ var tagName = elem.tagName
2794
+ duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data)
2787
2795
  }
2788
- var nodes = avalon.slice(fragment.childNodes)
2789
- if (nodes[0]) {
2790
- if (comment.parentNode)
2791
- comment.parentNode.replaceChild(fragment, comment)
2792
- if (isHtmlFilter) {
2793
- data.element = nodes[0]
2796
+ }
2797
+ //不存在 bindingExecutors.duplex
2798
+ function fixNull(val) {
2799
+ return val == null ? "" : val
2800
+ }
2801
+ avalon.duplexHooks = {
2802
+ checked: {
2803
+ get: function(val, data) {
2804
+ return !data.element.oldValue
2794
2805
  }
2806
+ },
2807
+ string: {
2808
+ get: function(val) { //同步到VM
2809
+ return val
2810
+ },
2811
+ set: fixNull
2812
+ },
2813
+ "boolean": {
2814
+ get: function(val) {
2815
+ return val === "true"
2816
+ },
2817
+ set: fixNull
2818
+ },
2819
+ number: {
2820
+ get: function(val) {
2821
+ return isFinite(val) ? parseFloat(val) || 0 : val
2822
+ },
2823
+ set: fixNull
2795
2824
  }
2796
- scanNodeArray(nodes, data.vmodels)
2797
2825
  }
2798
2826
 
2799
- bindingHandlers["if"] =
2800
- bindingHandlers.data =
2801
- bindingHandlers.text =
2802
- bindingHandlers.html =
2803
- function(data, vmodels) {
2804
- parseExprProxy(data.value, vmodels, data)
2827
+ function pipe(val, data, action, e) {
2828
+ data.param.replace(/\w+/g, function(name) {
2829
+ var hook = avalon.duplexHooks[name]
2830
+ if (hook && typeof hook[action] === "function") {
2831
+ val = hook[action](val, data)
2805
2832
  }
2806
-
2807
- bindingExecutors["if"] = function(val, elem, data) {
2808
- if (val) { //插回DOM树
2809
- if (elem.nodeType === 8) {
2810
- elem.parentNode.replaceChild(data.template, elem)
2811
- elem = data.element = data.template //这时可能为null
2812
- }
2813
- if (elem.getAttribute(data.name)) {
2814
- elem.removeAttribute(data.name)
2815
- scanAttr(elem, data.vmodels)
2816
- }
2817
- data.rollback = null
2818
- } else { //移出DOM树,并用注释节点占据原位置
2819
- if (elem.nodeType === 1) {
2820
- var node = data.element = DOC.createComment("ms-if")
2821
- elem.parentNode.replaceChild(node, elem)
2822
- data.template = elem //元素节点
2823
- ifGroup.appendChild(elem)
2824
- data.rollback = function() {
2825
- if (elem.parentNode === ifGroup) {
2826
- ifGroup.removeChild(elem)
2827
- }
2828
- }
2829
- }
2830
- }
2831
- }
2832
-
2833
-
2834
- function parseDisplay(nodeName, val) {
2835
- //用于取得此类标签的默认display值
2836
- var key = "_" + nodeName
2837
- if (!parseDisplay[key]) {
2838
- var node = DOC.createElement(nodeName)
2839
- root.appendChild(node)
2840
- if (W3C) {
2841
- val = getComputedStyle(node, null).display
2842
- } else {
2843
- val = node.currentStyle.display
2844
- }
2845
- root.removeChild(node)
2846
- parseDisplay[key] = val
2847
- }
2848
- return parseDisplay[key]
2849
- }
2850
-
2851
- avalon.parseDisplay = parseDisplay
2852
-
2853
- bindingHandlers.visible = function(data, vmodels) {
2854
- var elem = avalon(data.element)
2855
- var display = elem.css("display")
2856
- if (display === "none") {
2857
- var style = elem[0].style
2858
- var has = /visibility/i.test(style.cssText)
2859
- var visible = elem.css("visibility")
2860
- style.display = ""
2861
- style.visibility = "hidden"
2862
- display = elem.css("display")
2863
- if (display === "none") {
2864
- display = parseDisplay(elem[0].nodeName)
2865
- }
2866
- style.visibility = has ? visible : ""
2867
- }
2868
- data.display = display
2869
- parseExprProxy(data.value, vmodels, data)
2870
- }
2871
-
2872
- bindingExecutors.visible = function(val, elem, data) {
2873
- elem.style.display = val ? data.display : "none"
2874
- }
2875
-
2876
- var rdash = /\(([^)]*)\)/
2877
- bindingHandlers.on = function(data, vmodels) {
2878
- var value = data.value
2879
- data.type = "on"
2880
- var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
2881
- if (typeof bindingHandlers.on[eventType + "Hook"] === "function") {
2882
- bindingHandlers.on[eventType + "Hook"](data)
2883
- }
2884
- if (value.indexOf("(") > 0 && value.indexOf(")") > -1) {
2885
- var matched = (value.match(rdash) || ["", ""])[1].trim()
2886
- if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理
2887
- value = value.replace(rdash, "")
2888
- }
2889
- }
2890
- parseExprProxy(value, vmodels, data)
2891
- }
2892
-
2893
- bindingExecutors.on = function(callback, elem, data) {
2894
- callback = function(e) {
2895
- var fn = data.evaluator || noop
2896
- return fn.apply(this, data.args.concat(e))
2897
- }
2898
- var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
2899
- if (eventType === "scan") {
2900
- callback.call(elem, {
2901
- type: eventType
2902
- })
2903
- } else if (typeof data.specialBind === "function") {
2904
- data.specialBind(elem, callback)
2905
- } else {
2906
- var removeFn = avalon.bind(elem, eventType, callback)
2907
- }
2908
- data.rollback = function() {
2909
- if (typeof data.specialUnbind === "function") {
2910
- data.specialUnbind()
2911
- } else {
2912
- avalon.unbind(elem, eventType, removeFn)
2913
- }
2914
- }
2915
- }
2916
-
2917
-
2918
- bindingHandlers.widget = function(data, vmodels) {
2919
- var args = data.value.match(rword)
2920
- var elem = data.element
2921
- var widget = args[0]
2922
- var id = args[1]
2923
- if (!id || id === "$") {//没有定义或为$时,取组件名+随机数
2924
- id = generateID(widget)
2925
- }
2926
- var optName = args[2] || widget//没有定义,取组件名
2927
- var constructor = avalon.ui[widget]
2928
- if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
2929
- vmodels = elem.vmodels || vmodels
2930
- for (var i = 0, v; v = vmodels[i++]; ) {
2931
- if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
2932
- var vmOptions = v[optName]
2933
- vmOptions = vmOptions.$model || vmOptions
2934
- break
2935
- }
2936
- }
2937
- if (vmOptions) {
2938
- var wid = vmOptions[widget + "Id"]
2939
- if (typeof wid === "string") {
2940
- id = wid
2941
- }
2942
- }
2943
- //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
2944
- var widgetData = avalon.getWidgetData(elem, widget)
2945
- data.value = [widget, id, optName].join(",")
2946
- data[widget + "Id"] = id
2947
- data.evaluator = noop
2948
- elem.msData["ms-widget-id"] = id
2949
- var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
2950
- elem.removeAttribute("ms-widget")
2951
- var vmodel = constructor(elem, data, vmodels) || {} //防止组件不返回VM
2952
- if (vmodel.$id) {
2953
- avalon.vmodels[id] = vmodel
2954
- createSignalTower(elem, vmodel)
2955
- if (vmodel.hasOwnProperty("$init")) {
2956
- vmodel.$init(function() {
2957
- avalon.scan(elem, [vmodel].concat(vmodels))
2958
- if (typeof options.onInit === "function") {
2959
- options.onInit.call(elem, vmodel, options, vmodels)
2960
- }
2961
- })
2962
- }
2963
- data.rollback = function() {
2964
- try {
2965
- vmodel.widgetElement = null
2966
- vmodel.$remove()
2967
- } catch (e) {
2968
- }
2969
- elem.msData = {}
2970
- delete avalon.vmodels[vmodel.$id]
2971
- }
2972
- addSubscribers(data, widgetList)
2973
- if (window.chrome) {
2974
- elem.addEventListener("DOMNodeRemovedFromDocument", function() {
2975
- setTimeout(removeSubscribers)
2976
- })
2977
- }
2978
- } else {
2979
- avalon.scan(elem, vmodels)
2980
- }
2981
- } else if (vmodels.length) { //如果该组件还没有加载,那么保存当前的vmodels
2982
- elem.vmodels = vmodels
2983
- }
2984
- }
2985
- var widgetList = []
2986
- //不存在 bindingExecutors.widget
2987
- //双工绑定
2988
- var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
2989
- var elem = data.element,
2990
- hasCast
2991
- parseExprProxy(data.value, vmodels, data, 0, 1)
2992
-
2993
- data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
2994
- if (data.evaluator && data.args) {
2995
- var params = []
2996
- var casting = oneObject("string,number,boolean,checked")
2997
- if (elem.type === "radio" && data.param === "") {
2998
- data.param = "checked"
2999
- }
3000
- if (elem.msData) {
3001
- elem.msData["ms-duplex"] = data.value
3002
- }
3003
- data.param.replace(/\w+/g, function(name) {
3004
- if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
3005
- if (name === "radio")
3006
- log("ms-duplex-radio已经更名为ms-duplex-checked")
3007
- name = "checked"
3008
- data.isChecked = true
3009
- }
3010
- if (name === "bool") {
3011
- name = "boolean"
3012
- log("ms-duplex-bool已经更名为ms-duplex-boolean")
3013
- } else if (name === "text") {
3014
- name = "string"
3015
- log("ms-duplex-text已经更名为ms-duplex-string")
3016
- }
3017
- if (casting[name]) {
3018
- hasCast = true
3019
- }
3020
- avalon.Array.ensure(params, name)
3021
- })
3022
- if (!hasCast) {
3023
- params.push("string")
3024
- }
3025
- data.param = params.join("-")
3026
- data.bound = function(type, callback) {
3027
- if (elem.addEventListener) {
3028
- elem.addEventListener(type, callback, false)
3029
- } else {
3030
- elem.attachEvent("on" + type, callback)
3031
- }
3032
- var old = data.rollback
3033
- data.rollback = function() {
3034
- elem.avalonSetter = null
3035
- avalon.unbind(elem, type, callback)
3036
- old && old()
3037
- }
3038
- }
3039
- for (var i in avalon.vmodels) {
3040
- var v = avalon.vmodels[i]
3041
- v.$fire("avalon-ms-duplex-init", data)
3042
- }
3043
- var cpipe = data.pipe || (data.pipe = pipe)
3044
- cpipe(null, data, "init")
3045
- var tagName = elem.tagName
3046
- duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data)
3047
- }
3048
- }
3049
- //不存在 bindingExecutors.duplex
3050
- function fixNull(val) {
3051
- return val == null ? "" : val
3052
- }
3053
- avalon.duplexHooks = {
3054
- checked: {
3055
- get: function(val, data) {
3056
- return !data.element.oldValue
3057
- }
3058
- },
3059
- string: {
3060
- get: function(val) { //同步到VM
3061
- return val
3062
- },
3063
- set: fixNull
3064
- },
3065
- "boolean": {
3066
- get: function(val) {
3067
- return val === "true"
3068
- },
3069
- set: fixNull
3070
- },
3071
- number: {
3072
- get: function(val) {
3073
- return isFinite(val) ? parseFloat(val) || 0 : val
3074
- },
3075
- set: fixNull
3076
- }
3077
- }
3078
-
3079
- function pipe(val, data, action, e) {
3080
- data.param.replace(/\w+/g, function(name) {
3081
- var hook = avalon.duplexHooks[name]
3082
- if (hook && typeof hook[action] === "function") {
3083
- val = hook[action](val, data)
3084
- }
3085
- })
3086
- return val
3087
- }
2833
+ })
2834
+ return val
2835
+ }
3088
2836
 
3089
2837
  var TimerID, ribbon = []
3090
2838
  function W3CFire(el, name, detail) {
@@ -3244,60 +2992,189 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3244
2992
  if (element.value !== element.oldValue) {
3245
2993
  updateVModel()
3246
2994
  }
3247
- } else if (!element.msRetain) {
3248
- return false
2995
+ } else if (!element.msRetain) {
2996
+ return false
2997
+ }
2998
+ })
2999
+ }
3000
+
3001
+ element.avalonSetter = updateVModel
3002
+ element.oldValue = element.value
3003
+ registerSubscriber(data)
3004
+ callback.call(element, element.value)
3005
+ }
3006
+ duplexBinding.TEXTAREA = duplexBinding.INPUT
3007
+ duplexBinding.SELECT = function(element, evaluator, data) {
3008
+ var $elem = avalon(element)
3009
+ function updateVModel() {
3010
+ if ($elem.data("duplex-observe") !== false) {
3011
+ var val = $elem.val() //字符串或字符串数组
3012
+ if (Array.isArray(val)) {
3013
+ val = val.map(function(v) {
3014
+ return data.pipe(v, data, "get")
3015
+ })
3016
+ } else {
3017
+ val = data.pipe(val, data, "get")
3018
+ }
3019
+ if (val + "" !== element.oldValue) {
3020
+ evaluator(val)
3021
+ }
3022
+ data.changed.call(element, val, data)
3023
+ }
3024
+ }
3025
+ data.handler = function() {
3026
+ var val = evaluator()
3027
+ val = val && val.$model || val
3028
+ if (Array.isArray(val)) {
3029
+ if (!element.multiple) {
3030
+ log("ms-duplex在<select multiple=true>上要求对应一个数组")
3031
+ }
3032
+ } else {
3033
+ if (element.multiple) {
3034
+ log("ms-duplex在<select multiple=false>不能对应一个数组")
3035
+ }
3036
+ }
3037
+ //必须变成字符串后才能比较
3038
+ val = Array.isArray(val) ? val.map(String) : val + ""
3039
+ if (val + "" !== element.oldValue) {
3040
+ $elem.val(val)
3041
+ element.oldValue = val + ""
3042
+ }
3043
+ }
3044
+ data.bound("change", updateVModel)
3045
+ checkScan(element, function() {
3046
+ registerSubscriber(data)
3047
+ data.changed.call(element, evaluator(), data)
3048
+ }, NaN)
3049
+ }
3050
+
3051
+
3052
+ // bindingHandlers.html 定义在if.js
3053
+ bindingExecutors.html = function(val, elem, data) {
3054
+ val = val == null ? "" : val
3055
+ var isHtmlFilter = "group" in data
3056
+ var parent = isHtmlFilter ? elem.parentNode : elem
3057
+ if (!parent)
3058
+ return
3059
+ if (val.nodeType === 11) { //将val转换为文档碎片
3060
+ var fragment = val
3061
+ } else if (val.nodeType === 1 || val.item) {
3062
+ var nodes = val.nodeType === 1 ? val.childNodes : val.item ? val : []
3063
+ fragment = hyperspace.cloneNode(true)
3064
+ while (nodes[0]) {
3065
+ fragment.appendChild(nodes[0])
3066
+ }
3067
+ } else {
3068
+ fragment = avalon.parseHTML(val)
3069
+ }
3070
+ //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空
3071
+ var comment = DOC.createComment("ms-html")
3072
+ if (isHtmlFilter) {
3073
+ parent.insertBefore(comment, elem)
3074
+ var n = data.group, i = 1
3075
+ while (i < n) {
3076
+ var node = elem.nextSibling
3077
+ if (node) {
3078
+ parent.removeChild(node)
3079
+ i++
3080
+ }
3081
+ }
3082
+ parent.removeChild(elem)
3083
+ data.element = comment //防止被CG
3084
+ } else {
3085
+ avalon.clearHTML(parent).appendChild(comment)
3086
+ }
3087
+ if (isHtmlFilter) {
3088
+ data.group = fragment.childNodes.length || 1
3089
+ }
3090
+ nodes = avalon.slice(fragment.childNodes)
3091
+ if (nodes[0]) {
3092
+ if (comment.parentNode)
3093
+ comment.parentNode.replaceChild(fragment, comment)
3094
+ if (isHtmlFilter) {
3095
+ data.element = nodes[0]
3096
+ }
3097
+ }
3098
+ scanNodeArray(nodes, data.vmodels)
3099
+ }
3100
+
3101
+ bindingHandlers["if"] =
3102
+ bindingHandlers.data =
3103
+ bindingHandlers.text =
3104
+ bindingHandlers.html =
3105
+ function(data, vmodels) {
3106
+ parseExprProxy(data.value, vmodels, data)
3107
+ }
3108
+
3109
+ bindingExecutors["if"] = function(val, elem, data) {
3110
+ if (val) { //插回DOM树
3111
+ if (elem.nodeType === 8) {
3112
+ elem.parentNode.replaceChild(data.template, elem)
3113
+ elem = data.element = data.template //这时可能为null
3114
+ }
3115
+ if (elem.getAttribute(data.name)) {
3116
+ elem.removeAttribute(data.name)
3117
+ scanAttr(elem, data.vmodels)
3118
+ }
3119
+ data.rollback = null
3120
+ } else { //移出DOM树,并用注释节点占据原位置
3121
+ if (elem.nodeType === 1) {
3122
+ var node = data.element = DOC.createComment("ms-if")
3123
+ elem.parentNode.replaceChild(node, elem)
3124
+ data.template = elem //元素节点
3125
+ ifGroup.appendChild(elem)
3126
+ data.rollback = function() {
3127
+ if (elem.parentNode === ifGroup) {
3128
+ ifGroup.removeChild(elem)
3129
+ }
3249
3130
  }
3250
- })
3131
+ }
3251
3132
  }
3252
-
3253
- element.avalonSetter = updateVModel
3254
- element.oldValue = element.value
3255
- registerSubscriber(data)
3256
- callback.call(element, element.value)
3257
3133
  }
3258
- duplexBinding.TEXTAREA = duplexBinding.INPUT
3259
- duplexBinding.SELECT = function(element, evaluator, data) {
3260
- var $elem = avalon(element)
3261
- function updateVModel() {
3262
- if ($elem.data("duplex-observe") !== false) {
3263
- var val = $elem.val() //字符串或字符串数组
3264
- if (Array.isArray(val)) {
3265
- val = val.map(function(v) {
3266
- return data.pipe(v, data, "get")
3267
- })
3268
- } else {
3269
- val = data.pipe(val, data, "get")
3270
- }
3271
- if (val + "" !== element.oldValue) {
3272
- evaluator(val)
3273
- }
3274
- data.changed.call(element, val, data)
3134
+
3135
+
3136
+ //ms-important绑定已经在scanTag 方法中实现
3137
+ //ms-include绑定已由ms-attr绑定实现
3138
+
3139
+ var rdash = /\(([^)]*)\)/
3140
+ bindingHandlers.on = function(data, vmodels) {
3141
+ var value = data.value
3142
+ data.type = "on"
3143
+ var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
3144
+ if (typeof bindingHandlers.on[eventType + "Hook"] === "function") {
3145
+ bindingHandlers.on[eventType + "Hook"](data)
3146
+ }
3147
+ if (value.indexOf("(") > 0 && value.indexOf(")") > -1) {
3148
+ var matched = (value.match(rdash) || ["", ""])[1].trim()
3149
+ if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理
3150
+ value = value.replace(rdash, "")
3275
3151
  }
3276
3152
  }
3277
- data.handler = function() {
3278
- var val = evaluator()
3279
- val = val && val.$model || val
3280
- if (Array.isArray(val)) {
3281
- if (!element.multiple) {
3282
- log("ms-duplex在<select multiple=true>上要求对应一个数组")
3283
- }
3153
+ parseExprProxy(value, vmodels, data)
3154
+ }
3155
+
3156
+ bindingExecutors.on = function(callback, elem, data) {
3157
+ callback = function(e) {
3158
+ var fn = data.evaluator || noop
3159
+ return fn.apply(this, data.args.concat(e))
3160
+ }
3161
+ var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
3162
+ if (eventType === "scan") {
3163
+ callback.call(elem, {
3164
+ type: eventType
3165
+ })
3166
+ } else if (typeof data.specialBind === "function") {
3167
+ data.specialBind(elem, callback)
3168
+ } else {
3169
+ var removeFn = avalon.bind(elem, eventType, callback)
3170
+ }
3171
+ data.rollback = function() {
3172
+ if (typeof data.specialUnbind === "function") {
3173
+ data.specialUnbind()
3284
3174
  } else {
3285
- if (element.multiple) {
3286
- log("ms-duplex在<select multiple=false>不能对应一个数组")
3287
- }
3288
- }
3289
- //必须变成字符串后才能比较
3290
- val = Array.isArray(val) ? val.map(String) : val + ""
3291
- if (val + "" !== element.oldValue) {
3292
- $elem.val(val)
3293
- element.oldValue = val + ""
3175
+ avalon.unbind(elem, eventType, removeFn)
3294
3176
  }
3295
3177
  }
3296
- data.bound("change", updateVModel)
3297
- checkScan(element, function() {
3298
- registerSubscriber(data)
3299
- data.changed.call(element, evaluator(), data)
3300
- }, NaN)
3301
3178
  }
3302
3179
 
3303
3180
 
@@ -3373,9 +3250,9 @@ bindingHandlers.repeat = function(data, vmodels) {
3373
3250
  check0 = "$first"
3374
3251
  check1 = "$last"
3375
3252
  }
3376
- for (var i = 0, p; p = vmodels[i++]; ) {
3377
- if (p.hasOwnProperty(check0) && p.hasOwnProperty(check1)) {
3378
- data.$outer = p
3253
+ for (i = 0; v = vmodels[i++]; ) {
3254
+ if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) {
3255
+ data.$outer = v
3379
3256
  break
3380
3257
  }
3381
3258
  }
@@ -3405,7 +3282,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3405
3282
  var n = pos + el
3406
3283
  var array = data.$repeat
3407
3284
  var last = array.length - 1
3408
- var fragments = []
3285
+ var fragments = [], fragment
3409
3286
  var start = locateNode(data, pos)
3410
3287
  for (var i = pos; i < n; i++) {
3411
3288
  var proxy = eachProxyAgent(i, data)
@@ -3413,7 +3290,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3413
3290
  shimController(data, transation, proxy, fragments)
3414
3291
  }
3415
3292
  parent.insertBefore(transation, start)
3416
- for (var i = 0, fragment; fragment = fragments[i++]; ) {
3293
+ for (i = 0; fragment = fragments[i++]; ) {
3417
3294
  scanNodeArray(fragment.nodes, fragment.vmodels)
3418
3295
  fragment.nodes = fragment.vmodels = null
3419
3296
  }
@@ -3455,7 +3332,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3455
3332
  parent.insertBefore(transation, end)
3456
3333
  break
3457
3334
  case "index": //将proxies中的第pos个起的所有元素重新索引
3458
- var last = proxies.length - 1
3335
+ last = proxies.length - 1
3459
3336
  for (; el = proxies[pos]; pos++) {
3460
3337
  el.$index = pos
3461
3338
  el.$first = pos === 0
@@ -3463,7 +3340,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3463
3340
  }
3464
3341
  return
3465
3342
  case "set": //将proxies中的第pos个元素的VM设置为el(pos为数字,el任意)
3466
- var proxy = proxies[pos]
3343
+ proxy = proxies[pos]
3467
3344
  if (proxy) {
3468
3345
  notifySubscribers(proxy.$events.$index)
3469
3346
  }
@@ -3471,7 +3348,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3471
3348
  case "append": //将pos的键值对从el中取出(pos为一个普通对象,el为预先生成好的代理VM对象池)
3472
3349
  var pool = el
3473
3350
  var keys = []
3474
- var fragments = []
3351
+ fragments = []
3475
3352
  for (var key in pos) { //得到所有键名
3476
3353
  if (pos.hasOwnProperty(key) && key !== "hasOwnProperty") {
3477
3354
  keys.push(key)
@@ -3483,7 +3360,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3483
3360
  keys = keys2
3484
3361
  }
3485
3362
  }
3486
- for (var i = 0, key; key = keys[i++]; ) {
3363
+ for (i = 0; key = keys[i++]; ) {
3487
3364
  if (key !== "hasOwnProperty") {
3488
3365
  if (!pool[key]) {
3489
3366
  pool[key] = withProxyAgent(key, data)
@@ -3494,7 +3371,7 @@ bindingExecutors.repeat = function(method, pos, el) {
3494
3371
  var comment = data.$stamp = data.clone
3495
3372
  parent.insertBefore(comment, end)
3496
3373
  parent.insertBefore(transation, end)
3497
- for (var i = 0, fragment; fragment = fragments[i++]; ) {
3374
+ for (i = 0; fragment = fragments[i++]; ) {
3498
3375
  scanNodeArray(fragment.nodes, fragment.vmodels)
3499
3376
  fragment.nodes = fragment.vmodels = null
3500
3377
  }
@@ -3623,57 +3500,185 @@ function withProxyFactory() {
3623
3500
  set: function(val) {
3624
3501
  this.$host[this.$key] = val
3625
3502
  }
3626
- }
3627
- }, {
3628
- $val: 1
3629
- })
3630
- proxy.$id = generateID("$proxy$with")
3631
- return proxy
3632
- }
3633
-
3634
- function withProxyAgent(key, data) {
3635
- var proxy = withProxyPool.pop()
3636
- if (!proxy) {
3637
- proxy = withProxyFactory()
3638
- }
3639
- var host = data.$repeat
3640
- proxy.$key = key
3641
- proxy.$host = host
3642
- proxy.$outer = data.$outer
3643
- if (host.$events) {
3644
- proxy.$events.$val = host.$events[key]
3645
- } else {
3646
- proxy.$events = {}
3647
- }
3648
- return proxy
3649
- }
3650
-
3651
- function recycleProxies(proxies, type) {
3652
- var proxyPool = type === "each" ? eachProxyPool : withProxyPool
3653
- avalon.each(proxies, function(key, proxy) {
3654
- if (proxy.$events) {
3655
- for (var i in proxy.$events) {
3656
- if (Array.isArray(proxy.$events[i])) {
3657
- proxy.$events[i].forEach(function(data) {
3658
- if (typeof data === "object")
3659
- disposeData(data)
3660
- })
3661
- proxy.$events[i].length = 0
3503
+ }
3504
+ }, {
3505
+ $val: 1
3506
+ })
3507
+ proxy.$id = generateID("$proxy$with")
3508
+ return proxy
3509
+ }
3510
+
3511
+ function withProxyAgent(key, data) {
3512
+ var proxy = withProxyPool.pop()
3513
+ if (!proxy) {
3514
+ proxy = withProxyFactory()
3515
+ }
3516
+ var host = data.$repeat
3517
+ proxy.$key = key
3518
+ proxy.$host = host
3519
+ proxy.$outer = data.$outer
3520
+ if (host.$events) {
3521
+ proxy.$events.$val = host.$events[key]
3522
+ } else {
3523
+ proxy.$events = {}
3524
+ }
3525
+ return proxy
3526
+ }
3527
+
3528
+ function recycleProxies(proxies, type) {
3529
+ var proxyPool = type === "each" ? eachProxyPool : withProxyPool
3530
+ avalon.each(proxies, function(key, proxy) {
3531
+ if (proxy.$events) {
3532
+ for (var i in proxy.$events) {
3533
+ if (Array.isArray(proxy.$events[i])) {
3534
+ proxy.$events[i].forEach(function(data) {
3535
+ if (typeof data === "object")
3536
+ disposeData(data)
3537
+ })
3538
+ proxy.$events[i].length = 0
3539
+ }
3540
+ }
3541
+ proxy.$host = proxy.$outer = {}
3542
+ if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
3543
+ proxyPool.pop()
3544
+ }
3545
+ }
3546
+ })
3547
+ if (type === "each")
3548
+ proxies.length = 0
3549
+ }
3550
+
3551
+
3552
+
3553
+
3554
+ /*********************************************************************
3555
+ * 各种指令 *
3556
+ **********************************************************************/
3557
+ //ms-skip绑定已经在scanTag 方法中实现
3558
+ // bindingHandlers.text 定义在if.js
3559
+ bindingExecutors.text = function(val, elem) {
3560
+ val = val == null ? "" : val //不在页面上显示undefined null
3561
+ if (elem.nodeType === 3) { //绑定在文本节点上
3562
+ try { //IE对游离于DOM树外的节点赋值会报错
3563
+ elem.data = val
3564
+ } catch (e) {
3565
+ }
3566
+ } else { //绑定在特性节点上
3567
+ elem.textContent = val
3568
+ }
3569
+ }
3570
+
3571
+ function parseDisplay(nodeName, val) {
3572
+ //用于取得此类标签的默认display值
3573
+ var key = "_" + nodeName
3574
+ if (!parseDisplay[key]) {
3575
+ var node = DOC.createElement(nodeName)
3576
+ root.appendChild(node)
3577
+ if (W3C) {
3578
+ val = getComputedStyle(node, null).display
3579
+ } else {
3580
+ val = node.currentStyle.display
3581
+ }
3582
+ root.removeChild(node)
3583
+ parseDisplay[key] = val
3584
+ }
3585
+ return parseDisplay[key]
3586
+ }
3587
+
3588
+ avalon.parseDisplay = parseDisplay
3589
+
3590
+ bindingHandlers.visible = function(data, vmodels) {
3591
+ var elem = avalon(data.element)
3592
+ var display = elem.css("display")
3593
+ if (display === "none") {
3594
+ var style = elem[0].style
3595
+ var has = /visibility/i.test(style.cssText)
3596
+ var visible = elem.css("visibility")
3597
+ style.display = ""
3598
+ style.visibility = "hidden"
3599
+ display = elem.css("display")
3600
+ if (display === "none") {
3601
+ display = parseDisplay(elem[0].nodeName)
3602
+ }
3603
+ style.visibility = has ? visible : ""
3604
+ }
3605
+ data.display = display
3606
+ parseExprProxy(data.value, vmodels, data)
3607
+ }
3608
+
3609
+ bindingExecutors.visible = function(val, elem, data) {
3610
+ elem.style.display = val ? data.display : "none"
3611
+ }
3612
+
3613
+ bindingHandlers.widget = function(data, vmodels) {
3614
+ var args = data.value.match(rword)
3615
+ var elem = data.element
3616
+ var widget = args[0]
3617
+ var id = args[1]
3618
+ if (!id || id === "$") {//没有定义或为$时,取组件名+随机数
3619
+ id = generateID(widget)
3620
+ }
3621
+ var optName = args[2] || widget//没有定义,取组件名
3622
+ var constructor = avalon.ui[widget]
3623
+ if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
3624
+ vmodels = elem.vmodels || vmodels
3625
+ for (var i = 0, v; v = vmodels[i++]; ) {
3626
+ if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
3627
+ var vmOptions = v[optName]
3628
+ vmOptions = vmOptions.$model || vmOptions
3629
+ break
3630
+ }
3631
+ }
3632
+ if (vmOptions) {
3633
+ var wid = vmOptions[widget + "Id"]
3634
+ if (typeof wid === "string") {
3635
+ id = wid
3636
+ }
3637
+ }
3638
+ //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
3639
+ var widgetData = avalon.getWidgetData(elem, widget)
3640
+ data.value = [widget, id, optName].join(",")
3641
+ data[widget + "Id"] = id
3642
+ data.evaluator = noop
3643
+ elem.msData["ms-widget-id"] = id
3644
+ var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
3645
+ elem.removeAttribute("ms-widget")
3646
+ var vmodel = constructor(elem, data, vmodels) || {} //防止组件不返回VM
3647
+ if (vmodel.$id) {
3648
+ avalon.vmodels[id] = vmodel
3649
+ createSignalTower(elem, vmodel)
3650
+ if (vmodel.hasOwnProperty("$init")) {
3651
+ vmodel.$init(function() {
3652
+ avalon.scan(elem, [vmodel].concat(vmodels))
3653
+ if (typeof options.onInit === "function") {
3654
+ options.onInit.call(elem, vmodel, options, vmodels)
3655
+ }
3656
+ })
3657
+ }
3658
+ data.rollback = function() {
3659
+ try {
3660
+ vmodel.widgetElement = null
3661
+ vmodel.$remove()
3662
+ } catch (e) {
3662
3663
  }
3664
+ elem.msData = {}
3665
+ delete avalon.vmodels[vmodel.$id]
3663
3666
  }
3664
- proxy.$host = proxy.$outer = {}
3665
- if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
3666
- proxyPool.pop()
3667
+ addSubscribers(data, widgetList)
3668
+ if (window.chrome) {
3669
+ elem.addEventListener("DOMNodeRemovedFromDocument", function() {
3670
+ setTimeout(removeSubscribers)
3671
+ })
3667
3672
  }
3673
+ } else {
3674
+ avalon.scan(elem, vmodels)
3668
3675
  }
3669
- })
3670
- if (type === "each")
3671
- proxies.length = 0
3676
+ } else if (vmodels.length) { //如果该组件还没有加载,那么保存当前的vmodels
3677
+ elem.vmodels = vmodels
3678
+ }
3672
3679
  }
3673
-
3674
-
3675
-
3676
-
3680
+ var widgetList = []
3681
+ //不存在 bindingExecutors.widget
3677
3682
  /*********************************************************************
3678
3683
  * 自带过滤器 *
3679
3684
  **********************************************************************/
@@ -3898,6 +3903,7 @@ new function() {
3898
3903
  Z: timeZoneGetter
3899
3904
  }
3900
3905
  var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/
3906
+ var raspnetjson = /^\/Date\((\d+)\)\/$/
3901
3907
  filters.date = function(date, format) {
3902
3908
  var locate = filters.date.locate,
3903
3909
  text = "",
@@ -3908,6 +3914,8 @@ new function() {
3908
3914
  if (typeof date === "string") {
3909
3915
  if (/^\d+$/.test(date)) {
3910
3916
  date = toInt(date)
3917
+ } else if (raspnetjson.test(date)) {
3918
+ date = +RegExp.$1
3911
3919
  } else {
3912
3920
  var trimDate = date.trim()
3913
3921
  var dateArray = [0, 0, 0, 0, 0, 0, 0]
@@ -3915,9 +3923,9 @@ new function() {
3915
3923
  //取得年月日
3916
3924
  trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function(_, a, b, c) {
3917
3925
  var array = c.length === 4 ? [c, a, b] : [a, b, c]
3918
- dateArray[0] = toInt(array[0]) //年
3926
+ dateArray[0] = toInt(array[0]) //年
3919
3927
  dateArray[1] = toInt(array[1]) - 1 //月
3920
- dateArray[2] = toInt(array[2])//日
3928
+ dateArray[2] = toInt(array[2]) //日
3921
3929
  return ""
3922
3930
  })
3923
3931
  var dateSetter = oDate.setFullYear
@@ -3926,10 +3934,9 @@ new function() {
3926
3934
  dateArray[3] = toInt(a) //小时
3927
3935
  dateArray[4] = toInt(b) //分钟
3928
3936
  dateArray[5] = toInt(c) //秒
3929
- if (d) {
3930
- dateArray[6] = Math.round(parseFloat("0." + d) * 1000) //毫秒
3937
+ if (d) { //毫秒
3938
+ dateArray[6] = Math.round(parseFloat("0." + d) * 1000)
3931
3939
  }
3932
- dateArray[6] = d || ""
3933
3940
  return ""
3934
3941
  })
3935
3942
  var tzHour = 0
@@ -4025,45 +4032,164 @@ new function() {
4025
4032
  /*********************************************************************
4026
4033
  * AMD加载器 *
4027
4034
  **********************************************************************/
4028
- //https://www.devbridge.com/articles/understanding-amd-requirejs/
4035
+ //去掉getFullUrl 精简loadJS text!插件 baseUrl插件
4029
4036
  var modules = avalon.modules = {
4030
- "ready!": {
4031
- exports: avalon
4037
+ "domReady!": {
4038
+ exports: avalon,
4039
+ state: 3
4032
4040
  },
4033
4041
  "avalon": {
4034
4042
  exports: avalon,
4035
- state: 2
4043
+ state: 4
4036
4044
  }
4037
4045
  }
4046
+ //Object(modules[id]).state拥有如下值
4047
+ // undefined 没有定义
4048
+ // 1(send) 已经发出请求
4049
+ // 2(loading) 已经被执行但还没有执行完成,在这个阶段define方法会被执行
4050
+ // 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行
4051
+ // 4(execute) 其依赖也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行
4038
4052
  modules.exports = modules.avalon
4039
- //http://stackoverflow.com/questions/25175914/bundles-in-requirejs
4040
- //http://maxogden.com/nested-dependencies.html
4053
+
4041
4054
  new function() {
4042
4055
  var loadings = [] //正在加载中的模块列表
4043
- var factorys = [] //储存需要绑定ID与factory对应关系的模块(标准浏览器下,先parse的script节点会先onload)
4044
- //核心API之一 require
4045
- innerRequire = avalon.require = function(array, factory, parentUrl) {
4056
+ var factorys = [] //放置define方法的factory函数
4057
+ var rjsext = /\.js$/i
4058
+ var name2url = {}
4059
+ function makeRequest(name, config) {
4060
+ //1. 去掉资源前缀
4061
+ var res = "js"
4062
+ name = name.replace(/^(\w+)\!/, function(a, b) {
4063
+ res = b
4064
+ return ""
4065
+ })
4066
+ if (res === "ready") {
4067
+ log("debug: ready!已经被废弃,请使用domReady!")
4068
+ res = "domReady"
4069
+ }
4070
+ //2. 去掉querystring, hash
4071
+ var query = ""
4072
+ name = name.replace(rquery, function(a) {
4073
+ query = a
4074
+ return ""
4075
+ })
4076
+ //3. 去掉扩展名
4077
+ var suffix = "." + res
4078
+ var ext = /js|css/.test(suffix) ? suffix : ""
4079
+ name = name.replace(/\.[a-z0-9]+$/g, function(a) {
4080
+ if (a === suffix) {
4081
+ ext = a
4082
+ return ""
4083
+ } else {
4084
+ return a
4085
+ }
4086
+ })
4087
+ var req = avalon.mix({
4088
+ query: query,
4089
+ ext: ext,
4090
+ res: res,
4091
+ name: name,
4092
+ toUrl: toUrl
4093
+ }, config)
4094
+ req.toUrl(name)
4095
+ return req
4096
+ }
4097
+
4098
+ function fireRequest(req) {
4099
+ var name = req.name
4100
+ var res = req.res
4101
+ //1. 如果该模块已经发出请求,直接返回
4102
+ var module = modules[name]
4103
+ var urlNoQuery = name && req.urlNoQuery
4104
+
4105
+ if (module && module.state >= 3) {
4106
+ return name
4107
+ }
4108
+ module = modules[urlNoQuery]
4109
+ if (module && module.state >= 3) {
4110
+ innerRequire(module.deps || [], module.factory, urlNoQuery)
4111
+ return urlNoQuery
4112
+ }
4113
+ if (name && !module) {
4114
+ module = modules[urlNoQuery] = {
4115
+ id: urlNoQuery,
4116
+ state: 1 //send
4117
+ }
4118
+ var wrap = function(obj) {
4119
+ resources[res] = obj
4120
+ obj.load(name, req, function(a) {
4121
+ if (arguments.length && a !== void 0) {
4122
+ module.exports = a
4123
+ }
4124
+ module.state = 4
4125
+ checkDeps()
4126
+ })
4127
+ }
4128
+
4129
+ if (!resources[res]) {
4130
+ innerRequire([res], wrap)
4131
+ } else {
4132
+ wrap(resources[res])
4133
+ }
4134
+ }
4135
+ return name ? urlNoQuery : res + "!"
4136
+ }
4137
+
4138
+
4139
+ //核心API之一 require
4140
+
4141
+ var requireQueue = []
4142
+ var isUserFirstRequire = false
4143
+ innerRequire = avalon.require = function(array, factory, parentUrl, defineConfig) {
4144
+ if (!isUserFirstRequire) {
4145
+ requireQueue.push(avalon.slice(arguments))
4146
+ if (arguments.length <= 2) {
4147
+ isUserFirstRequire = true
4148
+ var queue = requireQueue.splice(0, requireQueue.length), args
4149
+ while (args = queue.shift()) {
4150
+ innerRequire.apply(null, args)
4151
+ }
4152
+ }
4153
+ return
4154
+ }
4155
+
4046
4156
  if (!Array.isArray(array)) {
4047
- avalon.error("require的第一个参数必须是依赖列数,类型为数组 " + array)
4157
+ avalon.error("require方法的第一个参数应为数组 " + array)
4048
4158
  }
4049
- var args = [] // 放置所有依赖项的完整路径
4050
- var deps = {} // args的另一种表现形式,为的是方便去重
4159
+ var deps = [] // 放置所有依赖项的完整路径
4160
+ var uniq = {}
4051
4161
  var id = parentUrl || "callback" + setTimeout("1")
4052
- var mapUrl = parentUrl && parentUrl.replace(/\.js$/i, "")
4053
- parentUrl = getBaseUrl(parentUrl)
4054
-
4055
- array.forEach(function(el) {
4056
- var url = loadResources(el, parentUrl, mapUrl) //加载资源,并返回.能加载资源的完整路径
4057
- if (url) {
4058
- if (!deps[url]) {
4059
- args.push(url)
4060
- deps[url] = "司徒正美" //去重
4162
+ defineConfig = defineConfig || {}
4163
+ defineConfig.baseUrl = kernel.baseUrl
4164
+ var isBuilt = !!defineConfig.built
4165
+ if (parentUrl) {
4166
+ defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/"))
4167
+ defineConfig.mapUrl = parentUrl.replace(rjsext, "")
4168
+ }
4169
+ if (isBuilt) {
4170
+ var req = makeRequest(defineConfig.name, defineConfig)
4171
+ id = req.urlNoQuery
4172
+ } else {
4173
+ array.forEach(function(name) {
4174
+ var req = makeRequest(name, defineConfig)
4175
+ var url = fireRequest(req) //加载资源,并返回该资源的完整地址
4176
+ if (url) {
4177
+ if (!uniq[url]) {
4178
+ deps.push(url)
4179
+ uniq[url] = "司徒正美" //去重
4180
+ }
4061
4181
  }
4062
- }
4063
- })
4182
+ })
4183
+ }
4184
+
4064
4185
  var module = modules[id]
4065
- if (!module || module.state !== 2) {
4066
- modules[id] = makeModule(id, 1, factory, deps, args)//更新此模块信息
4186
+ if (!module || module.state !== 4) {
4187
+ modules[id] = {
4188
+ id: id,
4189
+ deps: isBuilt ? array.concat() : deps,
4190
+ factory: factory || noop,
4191
+ state: 3
4192
+ }
4067
4193
  }
4068
4194
  if (!module) {
4069
4195
  //如果此模块是定义在另一个JS文件中, 那必须等该文件加载完毕, 才能放到检测列队中
@@ -4071,52 +4197,63 @@ new function() {
4071
4197
  }
4072
4198
  checkDeps()
4073
4199
  }
4074
- //核心API之二 require
4075
- innerRequire.define = function(urlOrId, deps, factory) { //模块名,依赖列表,模块本身
4076
- var args = aslice.call(arguments)
4077
- if (typeof urlOrId === "string") {
4078
- var id = args.shift()
4200
+
4201
+ //核心API之二 require
4202
+ innerRequire.define = function(name, deps, factory) { //模块名,依赖列表,模块本身
4203
+ if (typeof name !== "string") {
4204
+ factory = deps
4205
+ deps = name
4206
+ name = "anonymous"
4079
4207
  }
4080
- if (typeof args[0] === "function") {
4081
- args.unshift([])
4208
+ if (!Array.isArray(deps)) {
4209
+ factory = deps
4210
+ deps = []
4082
4211
  }
4083
- //上线合并后能直接得到模块ID,否则寻找当前正在解析中的script节点的src作为模块ID
4084
- //现在除了safari5,1-外,我们都能直接通过getCurrentScript一步到位得到当前执行的script节点,
4085
- //safari可通过onload+ factory.require闭包组合解决
4086
- var url = modules[id] && modules[id].state >= 1 ? id : trimQuery(getCurrentScript())
4087
- factory = args[1]
4088
- factory.id = id //用于调试
4089
-
4090
- if (!modules[url] && id) {
4091
- //必须先行定义,并且不存在deps,用于checkCycle方法
4092
- modules[url] = makeModule(url, 1, factory)
4212
+ var config = {
4213
+ built: !isUserFirstRequire, //用r.js打包后,所有define会放到requirejs之前
4214
+ name: name
4093
4215
  }
4094
-
4216
+ var args = [deps, factory, config]
4095
4217
  factory.require = function(url) {
4096
- args.push(url)
4097
- var isCycle = true
4098
- try {
4099
- isCycle = checkCycle(modules[url].deps, url)
4100
- } catch (e) {
4101
- }
4102
- if (isCycle) {
4103
- avalon.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块")
4218
+ args.splice(2, 0, url)
4219
+ if (modules[url]) {
4220
+ modules[url].state = 3 //loaded
4221
+ var isCycle = false
4222
+ try {
4223
+ isCycle = checkCycle(modules[url].deps, url)
4224
+ } catch (e) {
4225
+ }
4226
+ if (isCycle) {
4227
+ avalon.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块")
4228
+ }
4104
4229
  }
4105
4230
  delete factory.require //释放内存
4106
4231
  innerRequire.apply(null, args) //0,1,2 --> 1,2,0
4107
4232
  }
4233
+ //根据标准,所有遵循W3C标准的浏览器,script标签会按标签的出现顺序执行。
4234
+ //老的浏览器中,加载也是按顺序的:一个文件下载完成后,才开始下载下一个文件。
4235
+ //较新的浏览器中(IE8+ 、FireFox3.5+ 、Chrome4+ 、Safari4+),为了减小请求时间以优化体验,
4236
+ //下载可以是并行的,但是执行顺序还是按照标签出现的顺序。
4237
+ //但如果script标签是动态插入的, 就未必按照先请求先执行的原则了,目测只有firefox遵守
4238
+ //唯一比较一致的是,IE10+及其他标准浏览器,一旦开始解析脚本, 就会一直堵在那里,直接脚本解析完毕
4239
+ //亦即,先进入loading阶段的script标签(模块)必然会先进入loaded阶段
4240
+ var url = config.built ? "unknown" : getCurrentScript()
4108
4241
  if (url) {
4242
+ var module = modules[url]
4243
+ if (module) {
4244
+ module.state = 2
4245
+ }
4109
4246
  factory.require(url)
4110
- } else { //先进先出
4247
+ } else {//合并前后的safari,合并后的IE6-9走此分支
4111
4248
  factorys.push(factory)
4112
4249
  }
4113
4250
  }
4114
- //核心API之三 require.config(settings)
4251
+ //核心API之三 require.config(settings)
4115
4252
  innerRequire.config = kernel
4116
- //核心API之四 define.amd 标识其符合AMD规范
4253
+ //核心API之四 define.amd 标识其符合AMD规范
4117
4254
  innerRequire.define.amd = modules
4118
4255
 
4119
- //==========================对用户配置项进行再加工==========================
4256
+ //==========================对用户配置项进行再加工==========================
4120
4257
  var allpaths = kernel["orig.paths"] = {}
4121
4258
  var allmaps = kernel["orig.map"] = {}
4122
4259
  var allpackages = kernel["packages"] = []
@@ -4139,11 +4276,11 @@ new function() {
4139
4276
  var uniq = {}
4140
4277
  var ret = []
4141
4278
  for (var i = 0, pkg; pkg = array[i++]; ) {
4142
- var pkg = typeof pkg === "string" ? {name: pkg} : pkg
4279
+ pkg = typeof pkg === "string" ? {name: pkg} : pkg
4143
4280
  var name = pkg.name
4144
4281
  if (!uniq[name]) {
4145
4282
  var url = pkg.location ? pkg.location : joinPath(name, pkg.main || "main")
4146
- url = url.replace(/\.js$/i, "")
4283
+ url = url.replace(rjsext, "")
4147
4284
  ret.push(pkg)
4148
4285
  uniq[name] = pkg.location = url
4149
4286
  pkg.reg = makeMatcher(name)
@@ -4160,18 +4297,19 @@ new function() {
4160
4297
  },
4161
4298
  baseUrl: function(url) {
4162
4299
  if (!isAbsUrl(url)) {
4163
- var baseElement = head.getElementsByTagName("base")[0]
4300
+ var baseElement = head.querySelector("base")
4164
4301
  if (baseElement) {
4165
4302
  head.removeChild(baseElement)
4166
4303
  }
4167
4304
  var node = DOC.createElement("a")
4168
4305
  node.href = url
4169
- url = "1"[0] ? node.href : node.getAttribute("href", 4)
4306
+ url = node.href
4170
4307
  if (baseElement) {
4171
4308
  head.insertBefore(baseElement, head.firstChild)
4172
4309
  }
4173
4310
  }
4174
- kernel.baseUrl = url
4311
+ if (url.length > 3)
4312
+ kernel.baseUrl = url
4175
4313
  },
4176
4314
  shim: function(obj) {
4177
4315
  for (var i in obj) {
@@ -4182,85 +4320,30 @@ new function() {
4182
4320
  }
4183
4321
  }
4184
4322
  if (!value.exportsFn && (value.exports || value.init)) {
4185
- value.exportsFn = makeShimExports(value)
4323
+ value.exportsFn = makeExports(value)
4186
4324
  }
4187
4325
  }
4188
4326
  kernel.shim = obj
4189
- },
4190
- //三大常用资源插件 js!, css!, text!
4191
- js: function(url, shim) {
4192
- var id = trimQuery(url)
4193
- if (!modules[id]) { //如果之前没有加载过
4194
- var module = modules[id] = makeModule(id)
4195
- if (shim) { //shim机制
4196
- innerRequire(shim.deps || [], function() {
4197
- var args = avalon.slice(arguments)
4198
- loadJS(url, id, function() {
4199
- module.state = 2
4200
- if (shim.exportsFn) {
4201
- module.exports = shim.exportsFn.apply(0, args)
4202
- }
4203
- innerRequire.checkDeps()
4204
- })
4205
- })
4206
- } else {
4207
- loadJS(url, id)
4208
- }
4209
- }
4210
- return id
4211
- },
4212
- css: function(url) {
4213
- var id = trimQuery(url)
4214
- if (!DOC.getElementById(id)) {
4215
- var node = DOC.createElement("link")
4216
- node.rel = "stylesheet"
4217
- node.href = url
4218
- node.id = id
4219
- head.insertBefore(node, head.firstChild)
4220
- }
4221
- },
4222
- text: function(url) {
4223
- var id = trimQuery(url)
4224
- modules[id] = {}
4225
- var xhr = getXHR()
4226
- xhr.onreadystatechange = function() {
4227
- if (xhr.readyState === 4) {
4228
- var status = xhr.status;
4229
- if (status > 399 && status < 600) {
4230
- avalon.error(url + " 对应资源不存在或没有开启 CORS")
4231
- } else {
4232
- modules[id].state = 2
4233
- modules[id].exports = xhr.responseText
4234
- innerRequire.checkDeps()
4235
- }
4236
- }
4237
- }
4238
- xhr.open("GET", url, true)
4239
- if ("withCredentials" in xhr) {
4240
- xhr.withCredentials = true
4241
- }
4242
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
4243
- xhr.send()
4244
- return id
4245
4327
  }
4328
+
4246
4329
  })
4247
4330
 
4248
- plugins.css.ext = ".css"
4249
- plugins.js.ext = ".js"
4250
- //==============================内部方法=================================
4331
+
4332
+ //==============================内部方法=================================
4251
4333
  function checkCycle(deps, nick) {
4252
4334
  //检测是否存在循环依赖
4253
- for (var id in deps) {
4254
- if (deps[id] === "司徒正美" && modules[id].state !== 2 && (id === nick || checkCycle(modules[id].deps, nick))) {
4335
+ for (var i = 0, id; id = deps[i++]; ) {
4336
+ if (modules[id].state !== 4 &&
4337
+ (id === nick || checkCycle(modules[id].deps, nick))) {
4255
4338
  return true
4256
4339
  }
4257
4340
  }
4258
4341
  }
4259
4342
 
4260
- function checkFail(node, onError, fuckIE) {
4343
+ function checkFail(node, onError) {
4261
4344
  var id = trimQuery(node.src) //检测是否死链
4262
- node.onload = node.onreadystatechange = node.onerror = null
4263
- if (onError || (fuckIE && !modules[id].state)) {
4345
+ node.onload = node.onerror = null
4346
+ if (onError) {
4264
4347
  setTimeout(function() {
4265
4348
  head.removeChild(node)
4266
4349
  node = null // 处理旧式IE下的循环引用问题
@@ -4276,19 +4359,103 @@ new function() {
4276
4359
  loop: for (var i = loadings.length, id; id = loadings[--i]; ) {
4277
4360
  var obj = modules[id],
4278
4361
  deps = obj.deps
4279
- for (var key in deps) {
4280
- if (ohasOwn.call(deps, key) && modules[key].state !== 2) {
4362
+ if (!deps)
4363
+ continue
4364
+ for (var j = 0, key; key = deps[j]; j++) {
4365
+ var k = name2url[key]
4366
+ if (k) {
4367
+ key = deps[j] = k
4368
+ }
4369
+ if (Object(modules[key]).state !== 4) {
4281
4370
  continue loop
4282
4371
  }
4283
4372
  }
4284
4373
  //如果deps是空对象或者其依赖的模块的状态都是2
4285
- if (obj.state !== 2) {
4374
+ if (obj.state !== 4) {
4286
4375
  loadings.splice(i, 1) //必须先移除再安装,防止在IE下DOM树建完后手动刷新页面,会多次执行它
4287
- fireFactory(obj.id, obj.args, obj.factory)
4376
+ fireFactory(obj.id, obj.deps, obj.factory)
4288
4377
  checkDeps() //如果成功,则再执行一次,以防有些模块就差本模块没有安装好
4289
4378
  }
4290
4379
  }
4291
4380
  }
4381
+ function loadJS(url, id, callback) {
4382
+ //通过script节点加载目标模块
4383
+ var node = DOC.createElement("script")
4384
+ node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点
4385
+ node.onload = function() {
4386
+ var factory = factorys.pop()
4387
+ factory && factory.require(id)
4388
+ if (callback) {
4389
+ callback()
4390
+ }
4391
+ log("debug: 已成功加载 " + url)
4392
+ id && loadings.push(id)
4393
+ checkDeps()
4394
+ }
4395
+ node.onerror = function() {
4396
+ checkFail(node, true)
4397
+ }
4398
+
4399
+ head.appendChild(node) //chrome下第二个参数不能为null
4400
+ node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错
4401
+ log("debug: 正准备加载 " + url) //更重要的是IE6下可以收窄getCurrentScript的寻找范围
4402
+ }
4403
+
4404
+ var resources = innerRequire.plugins = {
4405
+ //三大常用资源插件 js!, css!, text!, ready!
4406
+ ready: {
4407
+ load: noop
4408
+ },
4409
+ js: {
4410
+ load: function(name, req, onLoad) {
4411
+ var url = req.url
4412
+ var id = req.urlNoQuery
4413
+ var shim = kernel.shim[name.replace(rjsext, "")]
4414
+ if (shim) { //shim机制
4415
+ innerRequire(shim.deps || [], function() {
4416
+ var args = avalon.slice(arguments)
4417
+ loadJS(url, id, function() {
4418
+ onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0)
4419
+ })
4420
+ })
4421
+ } else {
4422
+ loadJS(url, id)
4423
+ }
4424
+ }
4425
+ },
4426
+ css: {
4427
+ load: function(name, req, onLoad) {
4428
+ var url = req.url
4429
+ var node = DOC.createElement("link")
4430
+ node.rel = "stylesheet"
4431
+ node.href = url
4432
+ head.appendChild(node)
4433
+ log("debug: 已成功加载 " + url)
4434
+ onLoad()
4435
+ }
4436
+ },
4437
+ text: {
4438
+ load: function(name, req, onLoad) {
4439
+ var url = req.url
4440
+ var xhr = getXHR()
4441
+ xhr.onload = function() {
4442
+ var status = xhr.status;
4443
+ if (status > 399 && status < 600) {
4444
+ avalon.error(url + " 对应资源不存在或没有开启 CORS")
4445
+ } else {
4446
+ onLoad(xhr.responseText)
4447
+ }
4448
+ }
4449
+ xhr.open("GET", url, true)
4450
+ if ("withCredentials" in xhr) {//这是处理跨域
4451
+ xhr.withCredentials = true
4452
+ }
4453
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉后端这是AJAX请求
4454
+ xhr.send()
4455
+ log("debug: 正准备加载 " + url)
4456
+ }
4457
+ }
4458
+ }
4292
4459
  innerRequire.checkDeps = checkDeps
4293
4460
 
4294
4461
  var rquery = /(\?[^#]*)$/
@@ -4301,24 +4468,13 @@ new function() {
4301
4468
  return /^(?:[a-z]+:)?\/\//i.test(String(path))
4302
4469
  }
4303
4470
 
4304
- function getBaseUrl(parentUrl) {
4305
- return parentUrl ?
4306
- parentUrl.substr(0, parentUrl.lastIndexOf("/")) :
4307
- kernel.baseUrl ? kernel.baseUrl :
4308
- kernel.loaderUrl
4309
- }
4310
-
4311
- function getCurrentScript(base) {
4471
+ function getCurrentScript() {
4312
4472
  // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js
4313
4473
  var stack
4314
4474
  try {
4315
4475
  a.b.c() //强制报错,以便捕获e.stack
4316
- } catch (e) { //safari的错误对象只有line,sourceId,sourceURL
4476
+ } catch (e) { //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样
4317
4477
  stack = e.stack
4318
- if (!stack && window.opera) {
4319
- //opera 9没有e.stack,但有e.Backtrace,但不能直接取得,需要对e对象转字符串进行抽取
4320
- stack = (String(e).match(/of linked script \S+/g) || []).join(" ")
4321
- }
4322
4478
  }
4323
4479
  if (stack) {
4324
4480
  /**e.stack最后一行在所有支持的浏览器大致如下:
@@ -4334,116 +4490,83 @@ new function() {
4334
4490
  */
4335
4491
  stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分
4336
4492
  stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉换行符
4337
- return stack.replace(/(:\d+)?:\d+$/i, "") //去掉行号与或许存在的出错字符起始位置
4493
+ return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行号与或许存在的出错字符起始位置
4338
4494
  }
4339
- var nodes = (base ? DOC : head).getElementsByTagName("script") //只在head标签中寻找
4495
+ var nodes = head.getElementsByTagName("script") //只在head标签中寻找
4340
4496
  for (var i = nodes.length, node; node = nodes[--i]; ) {
4341
- if ((base || node.className === subscribers) && node.readyState === "interactive") {
4342
- var url = "1"[0] ? node.src : node.getAttribute("src", 4)
4343
- return node.className = url
4497
+ if (node.className === subscribers && node.readyState === "interactive") {
4498
+ var url = node.src
4499
+ return node.className = trimQuery(url)
4344
4500
  }
4345
4501
  }
4346
4502
  }
4347
4503
 
4348
- function loadResources(url, parentUrl, mapUrl) {
4349
- //1. 特别处理ready标识符及已经加载好的模块
4350
- if (url === "ready!" || (modules[url] && modules[url].state === 2)) {
4351
- return url
4504
+
4505
+ function fireFactory(id, deps, factory) {
4506
+ var module = Object(modules[id])
4507
+ module.state = 4
4508
+ for (var i = 0, array = [], d; d = deps[i++]; ) {
4509
+ d = name2url[d] || d
4510
+ if (d === "exports") {
4511
+ var obj = module.exports || (module.exports = {})
4512
+ array.push(obj)
4513
+ } else {
4514
+ array.push(modules[d].exports)
4515
+ }
4352
4516
  }
4353
- //2. 获取模块ID(去掉资源前缀,扩展名 hash, query)
4354
- var res = "js"
4355
- url = url.replace(/^(\w+)\!/, function(a, b) {
4356
- res = b
4357
- return ""
4358
- })
4359
- var plugin = plugins[res] || noop
4360
- var query = ""
4361
- var id = url.replace(rquery, function(a) {
4362
- query = a
4363
- return ""
4364
- })
4365
- var ext = ""
4366
- if (res === "js") {
4367
- url = id = id.replace(/\.js$/i, "")
4368
- ext = ".js"
4517
+ var ret = factory.apply(window, array)
4518
+ if (ret !== void 0) {
4519
+ module.exports = ret
4520
+ }
4521
+ delete module.factory
4522
+ return ret
4523
+ }
4524
+ function toUrl(id) {
4525
+ if (id.indexOf(this.res + "!") === 0) {
4526
+ id = id.slice(this.res.length + 1) //处理define("css!style",[], function(){})的情况
4369
4527
  }
4370
- //3. 是否命中paths配置项
4528
+ var url = id
4529
+ //1. 是否命中paths配置项
4371
4530
  var usePath = 0
4531
+ var baseUrl = this.baseUrl
4532
+ var rootUrl = this.parentUrl || baseUrl
4372
4533
  eachIndexArray(id, kernel.paths, function(value, key) {
4373
4534
  url = url.replace(key, value)
4374
4535
  usePath = 1
4375
4536
  })
4376
- //4. 是否命中packages配置项
4537
+ //2. 是否命中packages配置项
4377
4538
  if (!usePath) {
4378
4539
  eachIndexArray(id, kernel.packages, function(value, key, item) {
4379
4540
  url = url.replace(item.name, item.location)
4380
4541
  })
4381
4542
  }
4382
- //5. 是否命中map配置项
4383
- if (mapUrl) {
4384
- eachIndexArray(mapUrl, kernel.map, function(array) {
4543
+ //3. 是否命中map配置项
4544
+ if (this.mapUrl) {
4545
+ eachIndexArray(this.mapUrl, kernel.map, function(array) {
4385
4546
  eachIndexArray(url, array, function(mdValue, mdKey) {
4386
4547
  url = url.replace(mdKey, mdValue)
4548
+ rootUrl = baseUrl
4387
4549
  })
4388
4550
  })
4389
4551
  }
4390
- //6. 转换为绝对路径
4552
+ var ext = this.ext
4553
+ if (ext && usePath && url.slice(-ext.length) === ext) {
4554
+ url = url.slice(0, -ext.length)
4555
+ }
4556
+ //4. 转换为绝对路径
4391
4557
  if (!isAbsUrl(url)) {
4392
- url = joinPath(/\w/.test(url.charAt(0)) ? getBaseUrl() : parentUrl, url)
4558
+ rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl
4559
+ url = joinPath(rootUrl, url)
4393
4560
  }
4394
- //7. 还原扩展名,query
4395
- url += ext + query
4396
- //8. 处理urlArgs
4561
+ //5. 还原扩展名,query
4562
+ var urlNoQuery = url + ext
4563
+ url = urlNoQuery + this.query
4564
+ //6. 处理urlArgs
4397
4565
  eachIndexArray(id, kernel.urlArgs, function(value) {
4398
4566
  url += (url.indexOf("?") === -1 ? "?" : "&") + value;
4399
4567
  })
4400
- return plugin(url, kernel.shim[id])
4401
- }
4402
-
4403
- function loadJS(url, id, callback) {
4404
- //通过script节点加载目标模块
4405
- var node = DOC.createElement("script")
4406
- node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点
4407
- node[W3C ? "onload" : "onreadystatechange"] = function() {
4408
- if (W3C || /loaded|complete/i.test(node.readyState)) {
4409
- //mass Framework会在_checkFail把它上面的回调清掉,尽可能释放回存,尽管DOM0事件写法在IE6下GC无望
4410
- var factory = factorys.pop()
4411
-
4412
- factory && factory.require(id)
4413
- if (callback) {
4414
- callback()
4415
- }
4416
- if (checkFail(node, false, !W3C)) {
4417
- log("debug: 已成功加载 " + url)
4418
- loadings.push(id)
4419
- checkDeps()
4420
- }
4421
- }
4422
- }
4423
- node.onerror = function() {
4424
- checkFail(node, true)
4425
- }
4426
- node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错
4427
- head.insertBefore(node, head.firstChild) //chrome下第二个参数不能为null
4428
- log("debug: 正准备加载 " + url) //更重要的是IE6下可以收窄getCurrentScript的寻找范围
4429
- }
4430
-
4431
- function fireFactory(id, deps, factory) {
4432
- var module = Object(modules[id])
4433
- module.state = 2
4434
- for (var i = 0, array = [], d; d = deps[i++]; ) {
4435
- if (d === "exports") {
4436
- var obj = module.exports || (module.exports = {})
4437
- array.push(obj)
4438
- } else {
4439
- array.push(modules[d].exports)
4440
- }
4441
- }
4442
- var ret = factory.apply(window, array)
4443
- if (ret !== void 0) {
4444
- modules[id].exports = ret
4445
- }
4446
- return ret
4568
+ this.url = url
4569
+ return this.urlNoQuery = urlNoQuery
4447
4570
  }
4448
4571
 
4449
4572
  function makeIndexArray(hash, useStar, part) {
@@ -4457,7 +4580,7 @@ new function() {
4457
4580
  return new RegExp('^' + prefix + '(/|$)')
4458
4581
  }
4459
4582
 
4460
- function makeShimExports(value) {
4583
+ function makeExports(value) {
4461
4584
  return function() {
4462
4585
  var ret
4463
4586
  if (value.init) {
@@ -4467,15 +4590,6 @@ new function() {
4467
4590
  }
4468
4591
  }
4469
4592
 
4470
- function makeModule(id, state, factory, deps, args) {
4471
- return {
4472
- id: id,
4473
- state: state || 1,
4474
- factory: factory || noop,
4475
- deps: deps || {},
4476
- args: args || []
4477
- }
4478
- }
4479
4593
 
4480
4594
  function hash2array(hash, useStar, part) {
4481
4595
  var array = [];
@@ -4486,9 +4600,7 @@ new function() {
4486
4600
  val: hash[key]
4487
4601
  }
4488
4602
  array.push(item)
4489
- item.reg = key === "*" && useStar
4490
- ? /^/
4491
- : makeMatcher(key)
4603
+ item.reg = key === "*" && useStar ? /^/ : makeMatcher(key)
4492
4604
  if (part && key !== "*") {
4493
4605
  item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)')
4494
4606
  }
@@ -4506,7 +4618,7 @@ new function() {
4506
4618
  }
4507
4619
  }
4508
4620
  }
4509
- // 根据元素的name项进行数组字符数逆序的排序函数
4621
+ // 根据元素的name项进行数组字符数逆序的排序函数
4510
4622
  function descSorterByName(a, b) {
4511
4623
  var aaa = a.name
4512
4624
  var bbb = b.name
@@ -4551,14 +4663,17 @@ new function() {
4551
4663
  return g
4552
4664
  }
4553
4665
 
4554
-
4555
- var cur = getCurrentScript(true) //求得当前avalon.js 所在的JS文件的路径
4556
- if (!cur) { //处理window safari的Error没有stack的问题
4557
- cur = DOC.scripts[DOC.scripts.length - 1].src
4666
+ var mainNode = DOC.scripts[DOC.scripts.length - 1]
4667
+ var dataMain = mainNode.getAttribute("data-main")
4668
+ if (dataMain) {
4669
+ plugins.baseUrl(dataMain)
4670
+ var href = kernel.baseUrl
4671
+ kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1)
4672
+ loadJS(href.replace(rjsext, "") + ".js")
4673
+ } else {
4674
+ var loaderUrl = trimQuery(mainNode.src)
4675
+ kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1)
4558
4676
  }
4559
- var url = trimQuery(cur)
4560
- kernel.loaderUrl = url.slice(0, url.lastIndexOf("/") + 1)
4561
-
4562
4677
  }
4563
4678
 
4564
4679
  /*********************************************************************
@@ -4567,13 +4682,12 @@ new function() {
4567
4682
  var readyList = []
4568
4683
  function fireReady() {
4569
4684
  if (innerRequire) {
4570
- modules["ready!"].state = 2
4685
+ modules["domReady!"].state = 4
4571
4686
  innerRequire.checkDeps()//隋性函数,防止IE9二次调用_checkDeps
4572
- } else {
4573
- readyList.forEach(function(a) {
4574
- a(avalon)
4575
- })
4576
4687
  }
4688
+ readyList.forEach(function(a) {
4689
+ a(avalon)
4690
+ })
4577
4691
  fireReady = noop //隋性函数,防止IE9二次调用_checkDeps
4578
4692
  }
4579
4693
 
@@ -4584,9 +4698,7 @@ if (DOC.readyState === "complete") {
4584
4698
  window.addEventListener("load", fireReady)
4585
4699
  }
4586
4700
  avalon.ready = function(fn) {
4587
- if (innerRequire) {
4588
- innerRequire(["ready!"], fn)
4589
- } else if (fireReady === noop) {
4701
+ if (fireReady === noop) {
4590
4702
  fn(avalon)
4591
4703
  } else {
4592
4704
  readyList.push(fn)
@@ -4624,11 +4736,11 @@ avalon.ready(function() {
4624
4736
  }
4625
4737
  return avalon
4626
4738
  }
4627
- // Expose avalon and $ identifiers, even in AMD
4739
+ // Expose avalon identifiers, even in AMD
4628
4740
  // and CommonJS for browser emulators
4629
4741
  if (noGlobal === void 0) {
4630
4742
  window.avalon = avalon
4631
4743
  }
4632
4744
  return avalon
4633
4745
 
4634
- }));
4746
+ }));