avalon-rails 1.3.9.1.20150212184918 → 1.4.1.1.20150404164109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed801cfd8f10b5d5e8c22716fc0c7c31888d4ba9
4
- data.tar.gz: ccfa1fb5357c02ea306286f143468f96a9f64421
3
+ metadata.gz: 5385931f805ad02b303c591ea5ccf684f47fd244
4
+ data.tar.gz: 49174bf7a1cfb7628eaa6c126fbf3c80fd276c0d
5
5
  SHA512:
6
- metadata.gz: 9d0e70c173180ebadc019ff5dacd67e6fc04cef5c1f27b17c93b8b89898802ad4a273fc12f268e4505abd721edd1fbfc16195295241104497a6bc54ac349863f
7
- data.tar.gz: a4bfabe15172bf4be49d772544fa53f952e0050f7f3fe6a809edc0667f64c7186d80daec5a985f33303fc98ccdf3754f3c26c06e9784f405748aa6d7c526371b
6
+ metadata.gz: 931c7f65e84e90b0a3dac7ca818688f792fcdd1da19a1bc37cb9b43e081b65310dac6d62bb3d6265383de056d174f414eb7b518f098503c4dd1459453aa414f5
7
+ data.tar.gz: abf9e12994bfc133ec1344224bd764acbcced5e69169656c226a535ced199ae2d59121c857d73cd77c52aeaa5d2b00438b69ffa94594611f0c32da88067a87d2
@@ -1,5 +1,5 @@
1
1
  module Avalon
2
2
  module Rails
3
- VERSION = "1.3.9.1.20150212184918"
3
+ VERSION = "1.4.1.1.20150404164109"
4
4
  end
5
5
  end
@@ -5,7 +5,7 @@
5
5
  http://weibo.com/jslouvre/
6
6
 
7
7
  Released under the MIT license
8
- avalon.js 1.391 built in 2015.2.12
8
+ avalon.js 1.41 built in 2015.4.4
9
9
  support IE6+ and other browsers
10
10
  ==================================================*/
11
11
  (function(global, factory) {
@@ -53,6 +53,7 @@ function log() {
53
53
  var subscribers = "$" + expose
54
54
  var otherRequire = window.require
55
55
  var otherDefine = window.define
56
+ var innerRequire
56
57
  var stopRepeatAssign = false
57
58
  var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach
58
59
  var rcomplexType = /^(?:object|array)$/
@@ -90,16 +91,6 @@ function oneObject(array, val) {
90
91
  return result
91
92
  }
92
93
 
93
- function createCache(maxLength) {
94
- var keys = []
95
- function cache(key, value) {
96
- if (keys.push(key) > maxLength) {
97
- delete cache[keys.shift()]
98
- }
99
- return cache[key] = value;
100
- }
101
- return cache;
102
- }
103
94
  //生成UUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
104
95
  var generateID = function(prefix) {
105
96
  prefix = prefix || "avalon"
@@ -114,13 +105,60 @@ function IE() {
114
105
  }
115
106
  }
116
107
  var IEVersion = IE()
117
- /*********************************************************************
118
- * avalon的静态方法定义区 *
119
- **********************************************************************/
108
+
120
109
  avalon = function(el) { //创建jQuery式的无new 实例化结构
121
110
  return new avalon.init(el)
122
111
  }
123
112
 
113
+ /*视浏览器情况采用最快的异步回调*/
114
+ avalon.nextTick = new function() {// jshint ignore:line
115
+ var tickImmediate = window.setImmediate
116
+ var tickObserver = window.MutationObserver
117
+ var tickPost = W3C && window.postMessage
118
+ if (tickImmediate) {
119
+ return tickImmediate.bind(window)
120
+ }
121
+
122
+ var queue = []
123
+ function callback() {
124
+ var n = queue.length
125
+ for (var i = 0; i < n; i++) {
126
+ queue[i]()
127
+ }
128
+ queue = queue.slice(n)
129
+ }
130
+
131
+ if (tickObserver) {
132
+ var node = document.createTextNode("avalon")
133
+ new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line
134
+ return function(fn) {
135
+ queue.push(fn)
136
+ node.data = Math.random()
137
+ }
138
+ }
139
+
140
+ if (tickPost) {
141
+ window.addEventListener("message", function(e) {
142
+ var source = e.source
143
+ if ((source === window || source === null) && e.data === "process-tick") {
144
+ e.stopPropagation()
145
+ callback()
146
+ }
147
+ })
148
+
149
+ return function(fn) {
150
+ queue.push(fn)
151
+ window.postMessage('process-tick', '*')
152
+ }
153
+ }
154
+
155
+ return function(fn) {
156
+ setTimeout(fn, 0)
157
+ }
158
+ }// jshint ignore:line
159
+ /*********************************************************************
160
+ * avalon的静态方法定义区 *
161
+ **********************************************************************/
124
162
  avalon.init = function(el) {
125
163
  this[0] = this.element = el
126
164
  }
@@ -152,7 +190,7 @@ avalon.isWindow = function(obj) {
152
190
  return false
153
191
  // 利用IE678 window == document为true,document == window竟然为false的神奇特性
154
192
  // 标准浏览器及IE9,IE10等使用 正则检测
155
- return obj == obj.document && obj.document != obj
193
+ return obj == obj.document && obj.document != obj //jshint ignore:line
156
194
  }
157
195
 
158
196
  function isWindow(obj) {
@@ -185,7 +223,7 @@ avalon.isPlainObject = function(obj, key) {
185
223
  }
186
224
  for (key in obj) {
187
225
  }
188
- return key === void 0 || ohasOwn.call(obj, key);
226
+ return key === void 0 || ohasOwn.call(obj, key)
189
227
  }
190
228
  if (rnative.test(Object.getPrototypeOf)) {
191
229
  avalon.isPlainObject = function(obj) {
@@ -261,7 +299,7 @@ function _number(a, len) { //用于模拟slice, splice的效果
261
299
  avalon.mix({
262
300
  rword: rword,
263
301
  subscribers: subscribers,
264
- version: 1.391,
302
+ version: 1.41,
265
303
  ui: {},
266
304
  log: log,
267
305
  slice: W3C ? function(nodes, start, end) {
@@ -283,7 +321,7 @@ avalon.mix({
283
321
  noop: noop,
284
322
  /*如果不用Error对象封装一下,str在控制台下可能会乱码*/
285
323
  error: function(str, e) {
286
- throw new (e || Error)(str)
324
+ throw (e || Error)(str)
287
325
  },
288
326
  /*将一个以空格或逗号隔开的字符串或数组,转换成一个键值都为1的对象*/
289
327
  oneObject: oneObject,
@@ -320,7 +358,7 @@ avalon.mix({
320
358
  if (typeof hook === "object") {
321
359
  type = hook.type
322
360
  if (hook.deel) {
323
- fn = hook.deel(el, fn)
361
+ fn = hook.deel(el, type, fn, phase)
324
362
  }
325
363
  }
326
364
  var callback = W3C ? fn : function(e) {
@@ -340,6 +378,9 @@ avalon.mix({
340
378
  var callback = fn || noop
341
379
  if (typeof hook === "object") {
342
380
  type = hook.type
381
+ if (hook.deel) {
382
+ fn = hook.deel(el, type, fn, false)
383
+ }
343
384
  }
344
385
  if (W3C) {
345
386
  el.removeEventListener(type, callback, !!phase)
@@ -451,24 +492,94 @@ function isArrayLike(obj) {
451
492
  }
452
493
  return false
453
494
  }
454
- /*视浏览器情况采用最快的异步回调(在avalon.ready里,还有一个分支,用于处理IE6-9)*/
455
- avalon.nextTick = window.setImmediate ? setImmediate.bind(window) : function(callback) {
456
- setTimeout(callback, 0) //IE10-11 or W3C
457
- }
495
+
496
+
497
+ // https://github.com/rsms/js-lru
498
+ var Cache = new function() {// jshint ignore:line
499
+ function LRU(maxLength) {
500
+ this.size = 0
501
+ this.limit = maxLength
502
+ this.head = this.tail = void 0
503
+ this._keymap = {}
504
+ }
505
+
506
+ var p = LRU.prototype
507
+
508
+ p.put = function(key, value) {
509
+ var entry = {
510
+ key: key,
511
+ value: value
512
+ }
513
+ this._keymap[key] = entry
514
+ if (this.tail) {
515
+ this.tail.newer = entry
516
+ entry.older = this.tail
517
+ } else {
518
+ this.head = entry
519
+ }
520
+ this.tail = entry
521
+ if (this.size === this.limit) {
522
+ this.shift()
523
+ } else {
524
+ this.size++
525
+ }
526
+ return value
527
+ }
528
+
529
+ p.shift = function() {
530
+ var entry = this.head
531
+ if (entry) {
532
+ this.head = this.head.newer
533
+ this.head.older =
534
+ entry.newer =
535
+ entry.older =
536
+ this._keymap[entry.key] = void 0
537
+ }
538
+ }
539
+ p.get = function(key) {
540
+ var entry = this._keymap[key]
541
+ if (entry === void 0)
542
+ return
543
+ if (entry === this.tail) {
544
+ return entry.value
545
+ }
546
+ // HEAD--------------TAIL
547
+ // <.older .newer>
548
+ // <--- add direction --
549
+ // A B C <D> E
550
+ if (entry.newer) {
551
+ if (entry === this.head) {
552
+ this.head = entry.newer
553
+ }
554
+ entry.newer.older = entry.older // C <-- E.
555
+ }
556
+ if (entry.older) {
557
+ entry.older.newer = entry.newer // C. --> E
558
+ }
559
+ entry.newer = void 0 // D --x
560
+ entry.older = this.tail // D. --> E
561
+ if (this.tail) {
562
+ this.tail.newer = entry // E. <-- D
563
+ }
564
+ this.tail = entry
565
+ return entry.value
566
+ }
567
+ return LRU
568
+ }// jshint ignore:line
458
569
 
459
570
  /*********************************************************************
460
571
  * javascript 底层补丁 *
461
572
  **********************************************************************/
462
573
  if (!"司徒正美".trim) {
463
574
  var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
464
- String.prototype.trim = function() {
575
+ String.prototype.trim = function () {
465
576
  return this.replace(rtrim, "")
466
577
  }
467
578
  }
468
579
  var hasDontEnumBug = !({
469
580
  'toString': null
470
581
  }).propertyIsEnumerable('toString'),
471
- hasProtoEnumBug = (function() {
582
+ hasProtoEnumBug = (function () {
472
583
  }).propertyIsEnumerable('prototype'),
473
584
  dontEnums = [
474
585
  "toString",
@@ -481,7 +592,7 @@ var hasDontEnumBug = !({
481
592
  ],
482
593
  dontEnumsLength = dontEnums.length;
483
594
  if (!Object.keys) {
484
- Object.keys = function(object) { //ecma262v5 15.2.3.14
595
+ Object.keys = function (object) { //ecma262v5 15.2.3.14
485
596
  var theKeys = [];
486
597
  var skipProto = hasProtoEnumBug && typeof object === "function"
487
598
  if (typeof object === "string" || (object && object.callee)) {
@@ -510,18 +621,18 @@ if (!Object.keys) {
510
621
  }
511
622
  }
512
623
  if (!Array.isArray) {
513
- Array.isArray = function(a) {
624
+ Array.isArray = function (a) {
514
625
  return serialize.call(a) === "[object Array]"
515
626
  }
516
627
  }
517
628
 
518
629
  if (!noop.bind) {
519
- Function.prototype.bind = function(scope) {
630
+ Function.prototype.bind = function (scope) {
520
631
  if (arguments.length < 2 && scope === void 0)
521
632
  return this
522
633
  var fn = this,
523
634
  argv = arguments
524
- return function() {
635
+ return function () {
525
636
  var args = [],
526
637
  i
527
638
  for (i = 1; i < argv.length; i++)
@@ -535,12 +646,14 @@ if (!noop.bind) {
535
646
 
536
647
  function iterator(vars, body, ret) {
537
648
  var fun = 'for(var ' + vars + 'i=0,n = this.length; i < n; i++){' + body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))') + '}' + ret
649
+ /* jshint ignore:start */
538
650
  return Function("fn,scope", fun)
651
+ /* jshint ignore:end */
539
652
  }
540
653
  if (!rnative.test([].map)) {
541
654
  avalon.mix(ap, {
542
655
  //定位操作,返回数组中第一个等于给定参数的元素的索引值。
543
- indexOf: function(item, index) {
656
+ indexOf: function (item, index) {
544
657
  var n = this.length,
545
658
  i = ~~index
546
659
  if (i < 0)
@@ -551,7 +664,7 @@ if (!rnative.test([].map)) {
551
664
  return -1
552
665
  },
553
666
  //定位操作,同上,不过是从后遍历。
554
- lastIndexOf: function(item, index) {
667
+ lastIndexOf: function (item, index) {
555
668
  var n = this.length,
556
669
  i = index == null ? n - 1 : index
557
670
  if (i < 0)
@@ -581,22 +694,16 @@ function fixContains(root, el) {
581
694
  try { //IE6-8,游离于DOM树外的文本节点,访问parentNode有时会抛错
582
695
  while ((el = el.parentNode))
583
696
  if (el === root)
584
- return true;
697
+ return true
585
698
  return false
586
699
  } catch (e) {
587
700
  return false
588
701
  }
589
702
  }
590
703
  avalon.contains = fixContains
591
- //safari5+是把contains方法放在Element.prototype上而不是Node.prototype
592
- if (!root.contains) {
593
- Node.prototype.contains = function(arg) {
594
- return !!(this.compareDocumentPosition(arg) & 16)
595
- }
596
- }
597
704
  //IE6-11的文档对象没有contains
598
705
  if (!DOC.contains) {
599
- DOC.contains = function(b) {
706
+ DOC.contains = function (b) {
600
707
  return fixContains(DOC, b)
601
708
  }
602
709
  }
@@ -605,22 +712,27 @@ function outerHTML() {
605
712
  return new XMLSerializer().serializeToString(this)
606
713
  }
607
714
 
608
-
609
715
  if (window.SVGElement) {
716
+ //safari5+是把contains方法放在Element.prototype上而不是Node.prototype
717
+ if (!DOC.createTextNode("x").contains) {
718
+ Node.prototype.contains = function (arg) {//IE6-8没有Node对象
719
+ return !!(this.compareDocumentPosition(arg) & 16)
720
+ }
721
+ }
610
722
  var svgns = "http://www.w3.org/2000/svg"
611
723
  var svg = DOC.createElementNS(svgns, "svg")
612
724
  svg.innerHTML = '<circle cx="50" cy="50" r="40" fill="red" />'
613
725
  if (!rsvg.test(svg.firstChild)) { // #409
614
- function enumerateNode(node, targetNode) {
726
+ function enumerateNode(node, targetNode) {// jshint ignore:line
615
727
  if (node && node.childNodes) {
616
728
  var nodes = node.childNodes
617
729
  for (var i = 0, el; el = nodes[i++]; ) {
618
730
  if (el.tagName) {
619
731
  var svg = DOC.createElementNS(svgns,
620
732
  el.tagName.toLowerCase())
621
- ap.forEach.call(el.attributes, function(attr) {
733
+ ap.forEach.call(el.attributes, function (attr) {
622
734
  svg.setAttribute(attr.name, attr.value) //复制属性
623
- })
735
+ })// jshint ignore:line
624
736
  // 递归处理子节点
625
737
  enumerateNode(el, svg)
626
738
  targetNode.appendChild(svg)
@@ -633,7 +745,7 @@ if (window.SVGElement) {
633
745
  enumerable: true,
634
746
  configurable: true,
635
747
  get: outerHTML,
636
- set: function(html) {
748
+ set: function (html) {
637
749
  var tagName = this.tagName.toLowerCase(),
638
750
  par = this.parentNode,
639
751
  frag = avalon.parseHTML(html)
@@ -652,13 +764,13 @@ if (window.SVGElement) {
652
764
  "innerHTML": {
653
765
  enumerable: true,
654
766
  configurable: true,
655
- get: function() {
767
+ get: function () {
656
768
  var s = this.outerHTML
657
769
  var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i")
658
770
  var rclose = new RegExp("<\/" + this.nodeName + ">$", "i")
659
771
  return s.replace(ropen, "").replace(rclose, "")
660
772
  },
661
- set: function(html) {
773
+ set: function (html) {
662
774
  if (avalon.clearHTML) {
663
775
  avalon.clearHTML(this)
664
776
  var frag = avalon.parseHTML(html)
@@ -693,26 +805,26 @@ function fixEvent(event) {
693
805
  }
694
806
  ret.timeStamp = new Date() - 0
695
807
  ret.originalEvent = event
696
- ret.preventDefault = function() { //阻止默认行为
808
+ ret.preventDefault = function () { //阻止默认行为
697
809
  event.returnValue = false
698
810
  }
699
- ret.stopPropagation = function() { //阻止事件在DOM树中的传播
811
+ ret.stopPropagation = function () { //阻止事件在DOM树中的传播
700
812
  event.cancelBubble = true
701
813
  }
702
814
  return ret
703
815
  }
704
816
 
705
- var eventHooks = avalon.eventHooks
817
+ var eventHooks = avalon.eventHooks
706
818
  //针对firefox, chrome修正mouseenter, mouseleave
707
819
  if (!("onmouseenter" in root)) {
708
820
  avalon.each({
709
821
  mouseenter: "mouseover",
710
822
  mouseleave: "mouseout"
711
- }, function(origType, fixType) {
823
+ }, function (origType, fixType) {
712
824
  eventHooks[origType] = {
713
825
  type: fixType,
714
- deel: function(elem, fn) {
715
- return function(e) {
826
+ deel: function (elem, _, fn) {
827
+ return function (e) {
716
828
  var t = e.relatedTarget
717
829
  if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) {
718
830
  delete e.type
@@ -728,7 +840,7 @@ if (!("onmouseenter" in root)) {
728
840
  avalon.each({
729
841
  AnimationEvent: "animationend",
730
842
  WebKitAnimationEvent: "webkitAnimationEnd"
731
- }, function(construct, fixType) {
843
+ }, function (construct, fixType) {
732
844
  if (window[construct] && !eventHooks.animationend) {
733
845
  eventHooks.animationend = {
734
846
  type: fixType
@@ -739,8 +851,8 @@ avalon.each({
739
851
  if (!("oninput" in DOC.createElement("input"))) {
740
852
  eventHooks.input = {
741
853
  type: "propertychange",
742
- deel: function(elem, fn) {
743
- return function(e) {
854
+ deel: function (elem, _, fn) {
855
+ return function (e) {
744
856
  if (e.propertyName === "value") {
745
857
  e.type = "input"
746
858
  return fn.call(elem, e)
@@ -759,8 +871,8 @@ if (DOC.onmousewheel === void 0) {
759
871
  var fixWheelDelta = fixWheelType === "wheel" ? "deltaY" : "detail"
760
872
  eventHooks.mousewheel = {
761
873
  type: fixWheelType,
762
- deel: function(elem, fn) {
763
- return function(e) {
874
+ deel: function (elem, _, fn) {
875
+ return function (e) {
764
876
  e.wheelDeltaY = e.wheelDelta = e[fixWheelDelta] > 0 ? -120 : 120
765
877
  e.wheelDeltaX = 0
766
878
  if (Object.defineProperty) {
@@ -801,13 +913,14 @@ function escapeRegExp(target) {
801
913
  //将字符串安全格式化为正则表达式的源码
802
914
  return (target + "").replace(rregexp, "\\$&")
803
915
  }
804
- var innerRequire = noop
916
+
805
917
  var plugins = {
806
- loader: function(builtin) {
807
- window.define = builtin ? innerRequire.define : otherDefine
808
- window.require = builtin ? innerRequire : otherRequire
918
+ loader: function (builtin) {
919
+ var flag = innerRequire && builtin
920
+ window.require = flag ? innerRequire : otherRequire
921
+ window.define = flag ? innerRequire.define : otherDefine
809
922
  },
810
- interpolate: function(array) {
923
+ interpolate: function (array) {
811
924
  openTag = array[0]
812
925
  closeTag = array[1]
813
926
  if (openTag === closeTag) {
@@ -837,11 +950,25 @@ kernel.paths = {}
837
950
  kernel.shim = {}
838
951
  kernel.maxRepeatSize = 100
839
952
  avalon.config = kernel
953
+ var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/
954
+ var findNodes = DOC.querySelectorAll ? function(str) {
955
+ return DOC.querySelectorAll(str)
956
+ } : function(str) {
957
+ var match = str.match(ravalon)
958
+ var all = DOC.getElementsByTagName(match[1])
959
+ var nodes = []
960
+ for (var i = 0, el; el = all[i++]; ) {
961
+ if (el.getAttribute(match[2]) === match[3]) {
962
+ nodes.push(el)
963
+ }
964
+ }
965
+ return nodes
966
+ }
840
967
  /*********************************************************************
841
968
  * 事件总线 *
842
969
  **********************************************************************/
843
970
  var EventBus = {
844
- $watch: function(type, callback) {
971
+ $watch: function (type, callback) {
845
972
  if (typeof callback === "function") {
846
973
  var callbacks = this.$events[type]
847
974
  if (callbacks) {
@@ -854,7 +981,7 @@ var EventBus = {
854
981
  }
855
982
  return this
856
983
  },
857
- $unwatch: function(type, callback) {
984
+ $unwatch: function (type, callback) {
858
985
  var n = arguments.length
859
986
  if (n === 0) { //让此VM的所有$watch回调无效化
860
987
  this.$watch.backup = this.$events
@@ -872,13 +999,15 @@ var EventBus = {
872
999
  }
873
1000
  return this
874
1001
  },
875
- $fire: function(type) {
1002
+ $fire: function (type) {
876
1003
  var special, i, v, callback
877
1004
  if (/^(\w+)!(\S+)$/.test(type)) {
878
1005
  special = RegExp.$1
879
1006
  type = RegExp.$2
880
1007
  }
881
1008
  var events = this.$events
1009
+ if (!events)
1010
+ return
882
1011
  var args = aslice.call(arguments, 1)
883
1012
  var detail = [type].concat(args)
884
1013
  if (special === "all") {
@@ -901,22 +1030,23 @@ var EventBus = {
901
1030
  continue
902
1031
  }
903
1032
  //循环两个vmodel中的节点,查找匹配(向上匹配或者向下匹配)的节点并设置标识
904
- Array.prototype.forEach.call(eventNodes, function(node) {
905
- Array.prototype.forEach.call(elements, function(element) {
1033
+ /* jshint ignore:start */
1034
+ Array.prototype.forEach.call(eventNodes, function (node) {
1035
+ Array.prototype.forEach.call(elements, function (element) {
906
1036
  var ok = special === "down" ? element.contains(node) : //向下捕获
907
1037
  node.contains(element) //向上冒泡
908
-
909
1038
  if (ok) {
910
1039
  node._avalon = v //符合条件的加一个标识
911
1040
  }
912
1041
  });
913
1042
  })
1043
+ /* jshint ignore:end */
914
1044
  }
915
1045
  }
916
1046
  }
917
1047
  var nodes = DOC.getElementsByTagName("*") //实现节点排序
918
1048
  var alls = []
919
- Array.prototype.forEach.call(nodes, function(el) {
1049
+ Array.prototype.forEach.call(nodes, function (el) {
920
1050
  if (el._avalon) {
921
1051
  alls.push(el._avalon)
922
1052
  el._avalon = ""
@@ -946,26 +1076,12 @@ var EventBus = {
946
1076
  }
947
1077
  }
948
1078
 
949
- var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/
950
- var findNodes = DOC.querySelectorAll ? function(str) {
951
- return DOC.querySelectorAll(str)
952
- } : function(str) {
953
- var match = str.match(ravalon)
954
- var all = DOC.getElementsByTagName(match[1])
955
- var nodes = []
956
- for (var i = 0, el; el = all[i++]; ) {
957
- if (el.getAttribute(match[2]) === match[3]) {
958
- nodes.push(el)
959
- }
960
- }
961
- return nodes
962
- }
963
1079
  /*********************************************************************
964
1080
  * modelFactory *
965
1081
  **********************************************************************/
966
1082
  //avalon最核心的方法的两个方法之一(另一个是avalon.scan),返回一个ViewModel(VM)
967
1083
  var VMODELS = avalon.vmodels = {} //所有vmodel都储存在这里
968
- avalon.define = function(id, factory) {
1084
+ avalon.define = function (id, factory) {
969
1085
  var $id = id.$id || id
970
1086
  if (!$id) {
971
1087
  log("warning: vm必须指定$id")
@@ -1052,14 +1168,12 @@ function modelFactory(source, $special, $model) {
1052
1168
  if (Array.isArray(source)) {
1053
1169
  var arr = source.concat()
1054
1170
  source.length = 0
1055
- var collection = Collection(source)
1171
+ var collection = Collection(source)// jshint ignore:line
1056
1172
  collection.pushArray(arr)
1057
1173
  return collection
1058
1174
  }
1059
- if (typeof source.nodeType === "number") {
1060
- return source
1061
- }
1062
- if (source.$id && source.$events) { //fix IE6-8 createWithProxy $val: val引发的BUG
1175
+ //0 null undefined || Node || VModel(fix IE6-8 createWithProxy $val: val引发的BUG)
1176
+ if (!source || source.nodeType > 0 || (source.$id && source.$events)) {
1063
1177
  return source
1064
1178
  }
1065
1179
  if (!Array.isArray(source.$skipArray)) {
@@ -1072,7 +1186,7 @@ function modelFactory(source, $special, $model) {
1072
1186
  var watchedProperties = {} //监控属性
1073
1187
  var initCallbacks = [] //初始化才执行的函数
1074
1188
  for (var i in source) {
1075
- (function(name, val) {
1189
+ (function (name, val) {
1076
1190
  $model[name] = val
1077
1191
  if (!isObservable(name, val, source.$skipArray)) {
1078
1192
  return //过滤所有非监控属性
@@ -1080,7 +1194,7 @@ function modelFactory(source, $special, $model) {
1080
1194
  //总共产生三种accessor
1081
1195
  $events[name] = []
1082
1196
  var valueType = avalon.type(val)
1083
- var accessor = function(newValue) {
1197
+ var accessor = function (newValue) {
1084
1198
  var name = accessor._name
1085
1199
  var $vmodel = this
1086
1200
  var $model = $vmodel.$model
@@ -1099,19 +1213,8 @@ function modelFactory(source, $special, $model) {
1099
1213
  }
1100
1214
  if (!isEqual(oldValue, newValue)) {
1101
1215
  $model[name] = newValue
1102
- if ($events.$digest) {
1103
- if (!accessor.pedding) {
1104
- accessor.pedding = true
1105
- setTimeout(function() {
1106
- notifySubscribers($events[name]) //同步视图
1107
- safeFire($vmodel, name, $model[name], oldValue) //触发$watch回调
1108
- accessor.pedding = false
1109
- })
1110
- }
1111
- } else {
1112
- notifySubscribers($events[name]) //同步视图
1113
- safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
1114
- }
1216
+ notifySubscribers($events[name]) //同步视图
1217
+ safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
1115
1218
  }
1116
1219
  } else {
1117
1220
  if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性
@@ -1120,17 +1223,7 @@ function modelFactory(source, $special, $model) {
1120
1223
  if (oldValue !== newValue) {
1121
1224
  $model[name] = newValue
1122
1225
  //这里不用同步视图
1123
- if ($events.$digest) {
1124
- if (!accessor.pedding) {
1125
- accessor.pedding = true
1126
- setTimeout(function() {
1127
- safeFire($vmodel, name, $model[name], oldValue) //触发$watch回调
1128
- accessor.pedding = false
1129
- })
1130
- }
1131
- } else {
1132
- safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
1133
- }
1226
+ safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
1134
1227
  }
1135
1228
  return newValue
1136
1229
  } else {
@@ -1145,11 +1238,11 @@ function modelFactory(source, $special, $model) {
1145
1238
  accessor.set = val.set
1146
1239
  accessor.get = val.get
1147
1240
  accessor.type = 0
1148
- initCallbacks.push(function() {
1241
+ initCallbacks.push(function () {
1149
1242
  var data = {
1150
- evaluator: function() {
1243
+ evaluator: function () {
1151
1244
  data.type = Math.random(),
1152
- data.element = null
1245
+ data.element = null
1153
1246
  $model[name] = accessor.get.call($vmodel)
1154
1247
  },
1155
1248
  element: head,
@@ -1165,7 +1258,7 @@ function modelFactory(source, $special, $model) {
1165
1258
  //第2种为对象属性,产生子VM与监控数组
1166
1259
  accessor.type = 2
1167
1260
  accessor.valueType = valueType
1168
- initCallbacks.push(function() {
1261
+ initCallbacks.push(function () {
1169
1262
  var svmodel = modelFactory(val, 0, $model[name])
1170
1263
  accessor.svmodel = svmodel
1171
1264
  svmodel.$events[subscribers] = $events[name]
@@ -1176,10 +1269,10 @@ function modelFactory(source, $special, $model) {
1176
1269
  }
1177
1270
  accessor._name = name
1178
1271
  watchedProperties[name] = accessor
1179
- })(i, source[i])
1272
+ })(i, source[i])// jshint ignore:line
1180
1273
  }
1181
1274
 
1182
- $$skipArray.forEach(function(name) {
1275
+ $$skipArray.forEach(function (name) {
1183
1276
  delete source[name]
1184
1277
  delete $model[name] //这些特殊属性不应该在$model中出现
1185
1278
  })
@@ -1194,7 +1287,7 @@ function modelFactory(source, $special, $model) {
1194
1287
  $vmodel.$id = generateID()
1195
1288
  $vmodel.$model = $model
1196
1289
  $vmodel.$events = $events
1197
- for ( i in EventBus) {
1290
+ for (i in EventBus) {
1198
1291
  var fn = EventBus[i]
1199
1292
  if (!W3C) { //在IE6-8下,VB对象的方法里的this并不指向自身,需要用bind处理一下
1200
1293
  fn = fn.bind($vmodel)
@@ -1204,7 +1297,7 @@ function modelFactory(source, $special, $model) {
1204
1297
 
1205
1298
  if (canHideOwn) {
1206
1299
  Object.defineProperty($vmodel, "hasOwnProperty", {
1207
- value: function(name) {
1300
+ value: function (name) {
1208
1301
  return name in this.$model
1209
1302
  },
1210
1303
  writable: false,
@@ -1213,18 +1306,20 @@ function modelFactory(source, $special, $model) {
1213
1306
  })
1214
1307
 
1215
1308
  } else {
1216
- $vmodel.hasOwnProperty = function(name) {
1309
+ /* jshint ignore:start */
1310
+ $vmodel.hasOwnProperty = function (name) {
1217
1311
  return name in $vmodel.$model
1218
1312
  }
1313
+ /* jshint ignore:end */
1219
1314
  }
1220
- initCallbacks.forEach(function(cb) { //收集依赖
1315
+ initCallbacks.forEach(function (cb) { //收集依赖
1221
1316
  cb()
1222
1317
  })
1223
1318
  return $vmodel
1224
1319
  }
1225
1320
 
1226
1321
  //比较两个值是否相等
1227
- var isEqual = Object.is || function(v1, v2) {
1322
+ var isEqual = Object.is || function (v1, v2) {
1228
1323
  if (v1 === 0 && v2 === 0) {
1229
1324
  return 1 / v1 === 1 / v2
1230
1325
  } else if (v1 !== v1) {
@@ -1240,7 +1335,7 @@ function safeFire(a, b, c, d) {
1240
1335
  }
1241
1336
  }
1242
1337
 
1243
- var descriptorFactory = W3C ? function(obj) {
1338
+ var descriptorFactory = W3C ? function (obj) {
1244
1339
  var descriptors = {}
1245
1340
  for (var i in obj) {
1246
1341
  descriptors[i] = {
@@ -1251,7 +1346,7 @@ var descriptorFactory = W3C ? function(obj) {
1251
1346
  }
1252
1347
  }
1253
1348
  return descriptors
1254
- } : function(a) {
1349
+ } : function (a) {
1255
1350
  return a
1256
1351
  }
1257
1352
 
@@ -1279,16 +1374,17 @@ function objectFactory(parent, name, value, valueType) {
1279
1374
  }
1280
1375
  var ret = modelFactory(value)
1281
1376
  ret.$events[subscribers] = iterators
1282
- midway[ret.$id] = function(data) {
1377
+ midway[ret.$id] = function (data) {
1283
1378
  while (data = iterators.shift()) {
1284
- (function(el) {
1285
- avalon.nextTick(function() {
1286
- if (el.type) { //重新绑定
1379
+ (function (el) {
1380
+ avalon.nextTick(function () {
1381
+ var type = el.type
1382
+ if (type && bindingHandlers[type]) { //#753
1287
1383
  el.rollback && el.rollback() //还原 ms-with ms-on
1288
- bindingHandlers[el.type](el, el.vmodels)
1384
+ bindingHandlers[type](el, el.vmodels)
1289
1385
  }
1290
1386
  })
1291
- })(data)
1387
+ })(data) // jshint ignore:line
1292
1388
  }
1293
1389
  delete midway[ret.$id]
1294
1390
  }
@@ -1298,7 +1394,7 @@ function objectFactory(parent, name, value, valueType) {
1298
1394
  //===================修复浏览器对Object.defineProperties的支持=================
1299
1395
  if (!canHideOwn) {
1300
1396
  if ("__defineGetter__" in avalon) {
1301
- defineProperty = function(obj, prop, desc) {
1397
+ defineProperty = function (obj, prop, desc) {
1302
1398
  if ('value' in desc) {
1303
1399
  obj[prop] = desc.value
1304
1400
  }
@@ -1310,7 +1406,7 @@ if (!canHideOwn) {
1310
1406
  }
1311
1407
  return obj
1312
1408
  }
1313
- defineProperties = function(obj, descs) {
1409
+ defineProperties = function (obj, descs) {
1314
1410
  for (var prop in descs) {
1315
1411
  if (descs.hasOwnProperty(prop)) {
1316
1412
  defineProperty(obj, prop, descs[prop])
@@ -1320,7 +1416,7 @@ if (!canHideOwn) {
1320
1416
  }
1321
1417
  }
1322
1418
  if (IEVersion) {
1323
- window.execScript([
1419
+ window.execScript([ // jshint ignore:line
1324
1420
  "Function parseVB(code)",
1325
1421
  "\tExecuteGlobal(code)",
1326
1422
  "End Function",
@@ -1343,8 +1439,7 @@ if (!canHideOwn) {
1343
1439
  "\tfindOrDefineVBClass=found",
1344
1440
  "End Function"
1345
1441
  ].join("\n"), "VBScript")
1346
-
1347
- function VBMediator(instance, accessors, name, value) {
1442
+ function VBMediator(instance, accessors, name, value) {// jshint ignore:line
1348
1443
  var accessor = accessors[name]
1349
1444
  if (arguments.length === 4) {
1350
1445
  accessor.call(instance, value)
@@ -1352,8 +1447,8 @@ if (!canHideOwn) {
1352
1447
  return accessor.call(instance)
1353
1448
  }
1354
1449
  }
1355
- defineProperties = function(name, accessors, properties) {
1356
- var className = "VBClass" + setTimeout("1"),
1450
+ defineProperties = function (name, accessors, properties) {
1451
+ var className = "VBClass" + setTimeout("1"),// jshint ignore:line
1357
1452
  buffer = []
1358
1453
  buffer.push(
1359
1454
  "\r\n\tPrivate [__data__], [__proxy__]",
@@ -1367,7 +1462,7 @@ if (!canHideOwn) {
1367
1462
  buffer.push("\tPublic [" + name + "]")
1368
1463
  }
1369
1464
  }
1370
- $$skipArray.forEach(function(name) {
1465
+ $$skipArray.forEach(function (name) {
1371
1466
  if (!accessors.hasOwnProperty(name)) {
1372
1467
  buffer.push("\tPublic [" + name + "]")
1373
1468
  }
@@ -1406,7 +1501,6 @@ if (!canHideOwn) {
1406
1501
  "End Function"
1407
1502
  ].join("\r\n"))
1408
1503
  }
1409
- // console.log(code)
1410
1504
  var ret = window[realClassName + "Factory"](accessors, VBMediator) //得到其产品
1411
1505
  return ret //得到其产品
1412
1506
  }
@@ -1426,7 +1520,7 @@ function Collection(model) {
1426
1520
  array._ = modelFactory({
1427
1521
  length: model.length
1428
1522
  })
1429
- array._.$watch("length", function(a, b) {
1523
+ array._.$watch("length", function (a, b) {
1430
1524
  array.$fire("length", a, b)
1431
1525
  })
1432
1526
  for (var i in EventBus) {
@@ -1441,13 +1535,15 @@ function mutateArray(method, pos, n, index, method2, pos2, n2) {
1441
1535
  while (--loop) {
1442
1536
  switch (method) {
1443
1537
  case "add":
1444
- var array = this.$model.slice(pos, pos + n).map(function(el) {
1538
+ /* jshint ignore:start */
1539
+ var array = this.$model.slice(pos, pos + n).map(function (el) {
1445
1540
  if (rcomplexType.test(avalon.type(el))) {
1446
1541
  return el.$id ? el : modelFactory(el, 0, el)
1447
1542
  } else {
1448
1543
  return el
1449
1544
  }
1450
1545
  })
1546
+ /* jshint ignore:end */
1451
1547
  _splice.apply(this, [pos, 0].concat(array))
1452
1548
  this._fire("add", pos, n)
1453
1549
  break
@@ -1474,30 +1570,30 @@ function mutateArray(method, pos, n, index, method2, pos2, n2) {
1474
1570
  var _splice = ap.splice
1475
1571
  var CollectionPrototype = {
1476
1572
  _splice: _splice,
1477
- _fire: function(method, a, b) {
1573
+ _fire: function (method, a, b) {
1478
1574
  notifySubscribers(this.$events[subscribers], method, a, b)
1479
1575
  },
1480
- size: function() { //取得数组长度,这个函数可以同步视图,length不能
1576
+ size: function () { //取得数组长度,这个函数可以同步视图,length不能
1481
1577
  return this._.length
1482
1578
  },
1483
- pushArray: function(array) {
1579
+ pushArray: function (array) {
1484
1580
  var m = array.length, n = this.length
1485
1581
  if (m) {
1486
1582
  ap.push.apply(this.$model, array)
1487
- mutateArray.call(this, "add", n, m, n)
1583
+ mutateArray.call(this, "add", n, m, Math.max(0, n - 1))
1488
1584
  }
1489
1585
  return m + n
1490
1586
  },
1491
- push: function() {
1587
+ push: function () {
1492
1588
  //http://jsperf.com/closure-with-arguments
1493
1589
  var array = []
1494
1590
  var i, n = arguments.length
1495
1591
  for (i = 0; i < n; i++) {
1496
1592
  array[i] = arguments[i]
1497
1593
  }
1498
- return this.pushArray(arguments)
1594
+ return this.pushArray(array)
1499
1595
  },
1500
- unshift: function() {
1596
+ unshift: function () {
1501
1597
  var m = arguments.length, n = this.length
1502
1598
  if (m) {
1503
1599
  ap.unshift.apply(this.$model, arguments)
@@ -1505,22 +1601,22 @@ var CollectionPrototype = {
1505
1601
  }
1506
1602
  return m + n //IE67的unshift不会返回长度
1507
1603
  },
1508
- shift: function() {
1604
+ shift: function () {
1509
1605
  if (this.length) {
1510
1606
  var el = this.$model.shift()
1511
1607
  mutateArray.call(this, "del", 0, 1, 0)
1512
1608
  return el //返回被移除的元素
1513
1609
  }
1514
1610
  },
1515
- pop: function() {
1516
- var m = this.length
1517
- if (m) {
1611
+ pop: function () {
1612
+ var n = this.length
1613
+ if (n) {
1518
1614
  var el = this.$model.pop()
1519
- mutateArray.call(this, "del", m - 1, 1, Math.max(0, m - 2))
1615
+ mutateArray.call(this, "del", n - 1, 1, Math.max(0, n - 2))
1520
1616
  return el //返回被移除的元素
1521
1617
  }
1522
1618
  },
1523
- splice: function(start) {
1619
+ splice: function (start) {
1524
1620
  var m = arguments.length, args = [], change
1525
1621
  var removed = _splice.apply(this.$model, arguments)
1526
1622
  if (removed.length) { //如果用户删掉了元素
@@ -1541,27 +1637,27 @@ var CollectionPrototype = {
1541
1637
  return []
1542
1638
  }
1543
1639
  },
1544
- contains: function(el) { //判定是否包含
1640
+ contains: function (el) { //判定是否包含
1545
1641
  return this.indexOf(el) !== -1
1546
1642
  },
1547
- remove: function(el) { //移除第一个等于给定值的元素
1643
+ remove: function (el) { //移除第一个等于给定值的元素
1548
1644
  return this.removeAt(this.indexOf(el))
1549
1645
  },
1550
- removeAt: function(index) { //移除指定索引上的元素
1646
+ removeAt: function (index) { //移除指定索引上的元素
1551
1647
  if (index >= 0) {
1552
1648
  this.$model.splice(index, 1)
1553
1649
  return mutateArray.call(this, "del", index, 1, 0)
1554
1650
  }
1555
1651
  return []
1556
1652
  },
1557
- clear: function() {
1653
+ clear: function () {
1558
1654
  this.$model.length = this.length = this._.length = 0 //清空数组
1559
1655
  this._fire("clear", 0)
1560
1656
  return this
1561
1657
  },
1562
- removeAll: function(all) { //移除N个元素
1658
+ removeAll: function (all) { //移除N个元素
1563
1659
  if (Array.isArray(all)) {
1564
- all.forEach(function(el) {
1660
+ all.forEach(function (el) {
1565
1661
  this.remove(el)
1566
1662
  }, this)
1567
1663
  } else if (typeof all === "function") {
@@ -1575,13 +1671,13 @@ var CollectionPrototype = {
1575
1671
  this.clear()
1576
1672
  }
1577
1673
  },
1578
- ensure: function(el) {
1674
+ ensure: function (el) {
1579
1675
  if (!this.contains(el)) { //只有不存在才push
1580
1676
  this.push(el)
1581
1677
  }
1582
1678
  return this
1583
1679
  },
1584
- set: function(index, val) {
1680
+ set: function (index, val) {
1585
1681
  if (index >= 0) {
1586
1682
  var valueType = avalon.type(val)
1587
1683
  if (val && val.$model) {
@@ -1620,8 +1716,8 @@ function sortByIndex(array, indexes) {
1620
1716
  }
1621
1717
  }
1622
1718
 
1623
- "sort,reverse".replace(rword, function(method) {
1624
- CollectionPrototype[method] = function() {
1719
+ "sort,reverse".replace(rword, function (method) {
1720
+ CollectionPrototype[method] = function () {
1625
1721
  var newArray = this.$model//这是要排序的新数组
1626
1722
  var oldArray = newArray.concat() //保持原来状态的旧数组
1627
1723
  var mask = Math.random()
@@ -1796,27 +1892,24 @@ function notifySubscribers(list) { //通知依赖于这个访问器的订阅者
1796
1892
  /************************************************************************
1797
1893
  * HTML处理(parseHTML, innerHTML, clearHTML) *
1798
1894
  ************************************************************************/
1799
- //parseHTML的辅助变量
1895
+ // We have to close these tags to support XHTML
1800
1896
  var tagHooks = {
1801
- area: [1, "<map>"],
1802
- param: [1, "<object>"],
1803
- col: [2, "<table><tbody></tbody><colgroup>", "</table>"],
1804
- legend: [1, "<fieldset>"],
1805
- option: [1, "<select multiple='multiple'>"],
1897
+ area: [1, "<map>", "</map>"],
1898
+ param: [1, "<object>", "</object>"],
1899
+ col: [2, "<table><colgroup>", "</colgroup></table>"],
1900
+ legend: [1, "<fieldset>", "</fieldset>"],
1901
+ option: [1, "<select multiple='multiple'>", "</select>"],
1806
1902
  thead: [1, "<table>", "</table>"],
1807
- //如果这里不写</tbody></table>,在IE6-9会在多出一个奇怪的caption标签
1808
- tr: [2, "<table><tbody>", "</tbody></table>"],
1809
- //如果这里不写</tr></tbody></table>,在IE6-9会在多出一个奇怪的caption标签
1810
- th: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
1811
- td: [3, "<table><tbody><tr>"],
1903
+ tr: [2, "<table>", "</table>"],
1904
+ td: [3, "<table><tr>", "</tr></table>"],
1812
1905
  g: [1, '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">', '</svg>'],
1813
1906
  //IE6-8在用innerHTML生成节点时,不能直接创建no-scope元素与HTML5的新标签
1814
- _default: W3C ? [0, ""] : [1, "X<div>"] //div可以不用闭合
1907
+ _default: W3C ? [0, "", ""] : [1, "X<div>", "</div>"] //div可以不用闭合
1815
1908
  }
1816
-
1909
+ tagHooks.th = tagHooks.td
1817
1910
  tagHooks.optgroup = tagHooks.option
1818
1911
  tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead
1819
- String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function(tag) {
1912
+ String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function (tag) {
1820
1913
  tagHooks[tag] = tagHooks.g //处理SVG
1821
1914
  })
1822
1915
  var rtagName = /<([\w:]+)/ //取得其tagName
@@ -1825,43 +1918,58 @@ var rcreate = W3C ? /[^\d\D]/ : /(<(?:script|link|style|meta|noscript))/ig
1825
1918
  var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"])
1826
1919
  var rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/ //需要处理套嵌关系的标签
1827
1920
  var script = DOC.createElement("script")
1828
- avalon.parseHTML = function(html) {
1829
- if (typeof html !== "string" ) {
1830
- return DOC.createDocumentFragment()
1921
+ var rhtml = /<|&#?\w+;/
1922
+ avalon.parseHTML = function (html) {
1923
+ var fragment = hyperspace.cloneNode(false)
1924
+ if (typeof html !== "string") {
1925
+ return fragment
1926
+ }
1927
+ if (!rhtml.test(html)) {
1928
+ fragment.appendChild(DOC.createTextNode(html))
1929
+ return fragment
1831
1930
  }
1832
1931
  html = html.replace(rxhtml, "<$1></$2>").trim()
1833
1932
  var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(),
1834
1933
  //取得其标签名
1835
1934
  wrap = tagHooks[tag] || tagHooks._default,
1836
- fragment = hyperspace.cloneNode(false),
1837
1935
  wrapper = cinerator,
1838
1936
  firstChild, neo
1839
1937
  if (!W3C) { //fix IE
1840
1938
  html = html.replace(rcreate, "<br class=msNoScope>$1") //在link style script等标签之前添加一个补丁
1841
1939
  }
1842
- wrapper.innerHTML = wrap[1] + html + (wrap[2] || "")
1940
+ wrapper.innerHTML = wrap[1] + html + wrap[2]
1843
1941
  var els = wrapper.getElementsByTagName("script")
1844
1942
  if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性
1845
1943
  for (var i = 0, el; el = els[i++]; ) {
1846
1944
  if (scriptTypes[el.type]) {
1847
1945
  //以偷龙转凤方式恢复执行脚本功能
1848
1946
  neo = script.cloneNode(false) //FF不能省略参数
1849
- ap.forEach.call(el.attributes, function(attr) {
1947
+ ap.forEach.call(el.attributes, function (attr) {
1850
1948
  if (attr && attr.specified) {
1851
1949
  neo[attr.name] = attr.value //复制其属性
1852
1950
  neo.setAttribute(attr.name, attr.value)
1853
1951
  }
1854
- })
1952
+ }) // jshint ignore:line
1855
1953
  neo.text = el.text
1856
1954
  el.parentNode.replaceChild(neo, el) //替换节点
1857
1955
  }
1858
1956
  }
1859
1957
  }
1860
- //移除我们为了符合套嵌关系而添加的标签
1861
- for (i = wrap[0]; i--; wrapper = wrapper.lastChild) {
1862
- }
1863
1958
  if (!W3C) { //fix IE
1864
- els = wrapper.getElementsByTagName("br"), n = els.length
1959
+ var target = wrap[1] === "X<div>" ? wrapper.lastChild.firstChild : wrapper.lastChild
1960
+ if (target && target.tagName === "TABLE" && tag !== "tbody") {
1961
+ //IE6-7处理 <thead> --> <thead>,<tbody>
1962
+ //<tfoot> --> <tfoot>,<tbody>
1963
+ //<table> --> <table><tbody></table>
1964
+ for (els = target.childNodes, i = 0; el = els[i++]; ) {
1965
+ if (el.tagName === "TBODY" && !el.innerHTML) {
1966
+ target.removeChild(el)
1967
+ break
1968
+ }
1969
+ }
1970
+ }
1971
+ els = wrapper.getElementsByTagName("br")
1972
+ var n = els.length
1865
1973
  while (el = els[--n]) {
1866
1974
  if (el.className === "msNoScope") {
1867
1975
  el.parentNode.removeChild(el)
@@ -1873,7 +1981,9 @@ avalon.parseHTML = function(html) {
1873
1981
  }
1874
1982
  }
1875
1983
  }
1876
-
1984
+ //移除我们为了符合套嵌关系而添加的标签
1985
+ for (i = wrap[0]; i--; wrapper = wrapper.lastChild) {
1986
+ }
1877
1987
  while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上!
1878
1988
  fragment.appendChild(firstChild)
1879
1989
  }
@@ -1892,7 +2002,7 @@ function fixVML(node) {
1892
2002
  node.style.zoom = 1 //hasLayout
1893
2003
  }
1894
2004
  }
1895
- avalon.innerHTML = function(node, html) {
2005
+ avalon.innerHTML = function (node, html) {
1896
2006
  if (!W3C && (!rcreate.test(html) && !rnest.test(html))) {
1897
2007
  try {
1898
2008
  node.innerHTML = html
@@ -1903,7 +2013,7 @@ avalon.innerHTML = function(node, html) {
1903
2013
  var a = this.parseHTML(html)
1904
2014
  this.clearHTML(node).appendChild(a)
1905
2015
  }
1906
- avalon.clearHTML = function(node) {
2016
+ avalon.clearHTML = function (node) {
1907
2017
  node.textContent = ""
1908
2018
  while (node.firstChild) {
1909
2019
  node.removeChild(node.firstChild)
@@ -2022,8 +2132,9 @@ function scanAttr(elem, vmodels) {
2022
2132
  param = type
2023
2133
  type = "on"
2024
2134
  } else if (obsoleteAttrs[type]) {
2025
- log("ms-" + type + "已经被废弃,请使用ms-attr-*代替")
2026
- if (type === "enabled") { //吃掉ms-enabled绑定,用ms-disabled代替
2135
+ log("warning!请改用ms-attr-" + type + "代替ms-" + type + "!")
2136
+ if (type === "enabled") {//吃掉ms-enabled绑定,用ms-disabled代替
2137
+ log("warning!ms-enabled或ms-attr-enabled已经被废弃")
2027
2138
  type = "disabled"
2028
2139
  value = "!(" + value + ")"
2029
2140
  }
@@ -2047,11 +2158,11 @@ function scanAttr(elem, vmodels) {
2047
2158
  if (type === "html" || type === "text") {
2048
2159
  var token = getToken(value)
2049
2160
  avalon.mix(binding, token)
2050
- binding.filters = binding.filters.replace(rhasHtml, function() {
2161
+ binding.filters = binding.filters.replace(rhasHtml, function () {
2051
2162
  binding.type = "html"
2052
2163
  binding.group = 1
2053
2164
  return ""
2054
- })
2165
+ })// jshint ignore:line
2055
2166
  }
2056
2167
  if (name === "ms-if-loop") {
2057
2168
  binding.priority += 100
@@ -2067,12 +2178,18 @@ function scanAttr(elem, vmodels) {
2067
2178
  }
2068
2179
  }
2069
2180
  bindings.sort(bindingSorter)
2070
- if (msData["ms-attr-checked"] && msData["ms-duplex"]) {
2071
- log("warning!一个元素上不能同时定义ms-attr-checked与ms-duplex")
2181
+ var control = elem.type
2182
+ if (control && msData["ms-duplex"]) {
2183
+ if (msData["ms-attr-checked"] && /radio|checkbox/.test(control)) {
2184
+ log("warning!" + control + "控件不能同时定义ms-attr-checked与ms-duplex")
2185
+ }
2186
+ if (msData["ms-attr-value"] && /text|password/.test(control)) {
2187
+ log("warning!" + control + "控件不能同时定义ms-attr-value与ms-duplex")
2188
+ }
2072
2189
  }
2073
2190
  var scanNode = true
2074
2191
  for (i = 0; binding = bindings[i]; i++) {
2075
- type = binding.type
2192
+ type = binding.type
2076
2193
  if (rnoscanAttrBinding.test(type)) {
2077
2194
  return executeBindings(bindings.slice(0, i + 1), vmodels)
2078
2195
  } else if (scanNode) {
@@ -2091,7 +2208,7 @@ var rnoscanNodeBinding = /^each|with|html|include$/
2091
2208
  //IE67下,在循环绑定中,一个节点如果是通过cloneNode得到,自定义属性的specified为false,无法进入里面的分支,
2092
2209
  //但如果我们去掉scanAttr中的attr.specified检测,一个元素会有80+个特性节点(因为它不区分固有属性与自定义属性),很容易卡死页面
2093
2210
  if (!"1" [0]) {
2094
- var cacheAttrs = createCache(512)
2211
+ var cacheAttrs = new Cache(512)
2095
2212
  var rattrs = /\s+(ms-[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g,
2096
2213
  rquote = /^['"]/,
2097
2214
  rtag = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/i,
@@ -2105,7 +2222,7 @@ if (!"1" [0]) {
2105
2222
  // }
2106
2223
  // }
2107
2224
  //依次输出<SECTION>, </SECTION>
2108
- var getAttributes = function(elem) {
2225
+ var getAttributes = function (elem) {
2109
2226
  var html = elem.outerHTML
2110
2227
  //处理IE6-8解析HTML5新标签的情况,及<br>等半闭合标签outerHTML为空的情况
2111
2228
  if (html.slice(0, 2) === "</" || !html.trim()) {
@@ -2114,9 +2231,10 @@ if (!"1" [0]) {
2114
2231
  var str = html.match(rtag)[0]
2115
2232
  var attributes = [],
2116
2233
  match,
2117
- k, v;
2118
- if (cacheAttrs[str]) {
2119
- return cacheAttrs[str]
2234
+ k, v
2235
+ var ret = cacheAttrs.get(str)
2236
+ if (ret) {
2237
+ return ret
2120
2238
  }
2121
2239
  while (k = rattrs.exec(str)) {
2122
2240
  v = k[2]
@@ -2132,7 +2250,7 @@ if (!"1" [0]) {
2132
2250
  }
2133
2251
  attributes.push(binding)
2134
2252
  }
2135
- return cacheAttrs(str, attributes)
2253
+ return cacheAttrs.put(str, attributes)
2136
2254
  }
2137
2255
  }
2138
2256
 
@@ -2193,7 +2311,7 @@ var rhasHtml = /\|\s*html\s*/,
2193
2311
  function getToken(value) {
2194
2312
  if (value.indexOf("|") > 0) {
2195
2313
  var scapegoat = value.replace( rstringLiteral, function(_){
2196
- return Math.pow(10,_.length)
2314
+ return Array(_.length+1).join("1")// jshint ignore:line
2197
2315
  })
2198
2316
  var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
2199
2317
  if (index > -1) {
@@ -2268,7 +2386,7 @@ function scanText(textNode, vmodels) {
2268
2386
  token.type = "html"
2269
2387
  token.group = 1
2270
2388
  return ""
2271
- })
2389
+ })// jshint ignore:line
2272
2390
  bindings.push(token) //收集带有插值表达式的文本
2273
2391
  }
2274
2392
  hyperspace.appendChild(node)
@@ -2445,7 +2563,7 @@ avalon.fn.mix({
2445
2563
  while (offsetParent && avalon.css(offsetParent, "position") === "static") {
2446
2564
  offsetParent = offsetParent.offsetParent;
2447
2565
  }
2448
- return avalon(offsetParent)
2566
+ return avalon(offsetParent || root)
2449
2567
  },
2450
2568
  bind: function(type, fn, phase) {
2451
2569
  if (this[0]) { //此方法不会链
@@ -2499,10 +2617,10 @@ avalon.parseJSON = window.JSON ? JSON.parse : function(data) {
2499
2617
  if (rvalidchars.test(data.replace(rvalidescape, "@")
2500
2618
  .replace(rvalidtokens, "]")
2501
2619
  .replace(rvalidbraces, ""))) {
2502
- return (new Function("return " + data))();
2620
+ return (new Function("return " + data))()// jshint ignore:line
2503
2621
  }
2504
2622
  }
2505
- avalon.error("Invalid JSON: " + data);
2623
+ avalon.error("Invalid JSON: " + data)
2506
2624
  }
2507
2625
  return data
2508
2626
  }
@@ -2844,28 +2962,26 @@ var quote = window.JSON && JSON.stringify || function(str) {
2844
2962
  }) + '"'
2845
2963
  }
2846
2964
 
2847
- var keywords =
2848
- // 关键字
2849
- "break,case,catch,continue,debugger,default,delete,do,else,false" +
2850
- ",finally,for,function,if,in,instanceof,new,null,return,switch,this" +
2851
- ",throw,true,try,typeof,var,void,while,with" +
2852
- // 保留字
2853
- ",abstract,boolean,byte,char,class,const,double,enum,export,extends" +
2854
- ",final,float,goto,implements,import,int,interface,long,native" +
2855
- ",package,private,protected,public,short,static,super,synchronized" +
2856
- ",throws,transient,volatile" +
2857
- // ECMA 5 - use strict
2858
- ",arguments,let,yield" + ",undefined"
2965
+ var keywords = [
2966
+ "break,case,catch,continue,debugger,default,delete,do,else,false",
2967
+ "finally,for,function,if,in,instanceof,new,null,return,switch,this",
2968
+ "throw,true,try,typeof,var,void,while,with", /* 关键字*/
2969
+ "abstract,boolean,byte,char,class,const,double,enum,export,extends",
2970
+ "final,float,goto,implements,import,int,interface,long,native",
2971
+ "package,private,protected,public,short,static,super,synchronized",
2972
+ "throws,transient,volatile", /*保留字*/
2973
+ "arguments,let,yield,undefined" /* ECMA 5 - use strict*/].join(",")
2859
2974
  var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g
2860
2975
  var rsplit = /[^\w$]+/g
2861
2976
  var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g')
2862
2977
  var rnumber = /\b\d[^,]*/g
2863
2978
  var rcomma = /^,+|,+$/g
2864
- var cacheVars = createCache(512)
2865
- var getVariables = function(code) {
2979
+ var cacheVars = new Cache(512)
2980
+ var getVariables = function (code) {
2866
2981
  var key = "," + code.trim()
2867
- if (cacheVars[key]) {
2868
- return cacheVars[key]
2982
+ var ret = cacheVars.get(key)
2983
+ if (ret) {
2984
+ return ret
2869
2985
  }
2870
2986
  var match = code
2871
2987
  .replace(rrexpstr, "")
@@ -2874,7 +2990,7 @@ var getVariables = function(code) {
2874
2990
  .replace(rnumber, "")
2875
2991
  .replace(rcomma, "")
2876
2992
  .split(/^$|,+/)
2877
- return cacheVars(key, uniqSet(match))
2993
+ return cacheVars.put(key, uniqSet(match))
2878
2994
  }
2879
2995
  /*添加赋值语句*/
2880
2996
 
@@ -2907,7 +3023,7 @@ function uniqSet(array) {
2907
3023
  return ret
2908
3024
  }
2909
3025
  //缓存求值函数,以便多次利用
2910
- var cacheExprs = createCache(128)
3026
+ var cacheExprs = new Cache(128)
2911
3027
  //取得求值函数及其传参
2912
3028
  var rduplex = /\w\[.*\]|\w\.\w/
2913
3029
  var rproxy = /(\$proxy\$[a-z]+)\d+$/
@@ -2919,16 +3035,16 @@ var rthimLeftParentheses = /"\s*\(/g
2919
3035
  function parseFilter(val, filters) {
2920
3036
  filters = filters
2921
3037
  .replace(rthimRightParentheses, "")//处理最后的小括号
2922
- .replace(rthimOtherParentheses, function() {//处理其他小括号
3038
+ .replace(rthimOtherParentheses, function () {//处理其他小括号
2923
3039
  return "],|"
2924
3040
  })
2925
- .replace(rquoteFilterName, function(a, b) { //处理|及它后面的过滤器的名字
3041
+ .replace(rquoteFilterName, function (a, b) { //处理|及它后面的过滤器的名字
2926
3042
  return "[" + quote(b)
2927
3043
  })
2928
- .replace(rpatchBracket, function() {
3044
+ .replace(rpatchBracket, function () {
2929
3045
  return '"],["'
2930
3046
  })
2931
- .replace(rthimLeftParentheses, function() {
3047
+ .replace(rthimLeftParentheses, function () {
2932
3048
  return '",'
2933
3049
  }) + "]"
2934
3050
  return "return avalon.filters.$filter(" + val + ", " + filters + ")"
@@ -2937,7 +3053,7 @@ function parseFilter(val, filters) {
2937
3053
  function parseExpr(code, scopes, data) {
2938
3054
  var dataType = data.type
2939
3055
  var filters = data.filters || ""
2940
- var exprId = scopes.map(function(el) {
3056
+ var exprId = scopes.map(function (el) {
2941
3057
  return String(el.$id).replace(rproxy, "$1")
2942
3058
  }) + code + dataType + filters
2943
3059
  var vars = getVariables(code).concat(),
@@ -2961,9 +3077,9 @@ function parseExpr(code, scopes, data) {
2961
3077
  }
2962
3078
  if (dataType !== "duplex" && (code.indexOf("||") > -1 || code.indexOf("&&") > -1)) {
2963
3079
  //https://github.com/RubyLouvre/avalon/issues/583
2964
- data.vars.forEach(function(v) {
3080
+ data.vars.forEach(function (v) {
2965
3081
  var reg = new RegExp("\\b" + v + "(?:\\.\\w+|\\[\\w+\\])+", "ig")
2966
- code = code.replace(reg, function(_) {
3082
+ code = code.replace(reg, function (_) {
2967
3083
  var c = _.charAt(v.length)
2968
3084
  var r = IEVersion ? code.slice(arguments[1] + _.length) : RegExp.rightContext
2969
3085
  var method = /^\s*\(/.test(r)
@@ -2990,7 +3106,7 @@ function parseExpr(code, scopes, data) {
2990
3106
  //---------------args----------------
2991
3107
  data.args = args
2992
3108
  //---------------cache----------------
2993
- var fn = cacheExprs[exprId] //直接从缓存,免得重复生成
3109
+ var fn = cacheExprs.get(exprId) //直接从缓存,免得重复生成
2994
3110
  if (fn) {
2995
3111
  data.evaluator = fn
2996
3112
  return
@@ -3014,7 +3130,7 @@ function parseExpr(code, scopes, data) {
3014
3130
  "= vvv;\n} "
3015
3131
  try {
3016
3132
  fn = Function.apply(noop, names.concat(_body))
3017
- data.evaluator = cacheExprs(exprId, fn)
3133
+ data.evaluator = cacheExprs.put(exprId, fn)
3018
3134
  } catch (e) {
3019
3135
  log("debug: parse error," + e.message)
3020
3136
  }
@@ -3036,11 +3152,11 @@ function parseExpr(code, scopes, data) {
3036
3152
  }
3037
3153
  try {
3038
3154
  fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code))
3039
- data.evaluator = cacheExprs(exprId, fn)
3155
+ data.evaluator = cacheExprs.put(exprId, fn)
3040
3156
  } catch (e) {
3041
3157
  log("debug: parse error," + e.message)
3042
3158
  } finally {
3043
- vars = textBuffer = names = null //释放内存
3159
+ vars = assigns = names = null //释放内存
3044
3160
  }
3045
3161
  }
3046
3162
 
@@ -3049,7 +3165,7 @@ function parseExpr(code, scopes, data) {
3049
3165
 
3050
3166
  function parseExprProxy(code, scopes, data, tokens, noregister) {
3051
3167
  if (Array.isArray(tokens)) {
3052
- code = tokens.map(function(el) {
3168
+ code = tokens.map(function (el) {
3053
3169
  return el.expr ? "(" + el.value + ")" : quote(el.value)
3054
3170
  }).join(" + ")
3055
3171
  }
@@ -3063,10 +3179,12 @@ function parseExprProxy(code, scopes, data, tokens, noregister) {
3063
3179
  }
3064
3180
  }
3065
3181
  avalon.parseExprProxy = parseExprProxy
3066
- var bools = "autofocus,autoplay,async,allowTransparency,checked,controls,declare,disabled,defer,defaultChecked,defaultSelected" +
3067
- "contentEditable,isMap,loop,multiple,noHref,noResize,noShade,open,readOnly,selected"
3182
+ var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls",
3183
+ "declare,disabled,defer,defaultChecked,defaultSelected",
3184
+ "contentEditable,isMap,loop,multiple,noHref,noResize,noShade",
3185
+ "open,readOnly,selected"].join(",")
3068
3186
  var boolMap = {}
3069
- bools.replace(rword, function(name) {
3187
+ bools.replace(rword, function (name) {
3070
3188
  boolMap[name.toLowerCase()] = name
3071
3189
  })
3072
3190
 
@@ -3079,21 +3197,23 @@ var propMap = {//属性名映射
3079
3197
  "http-equiv": "httpEquiv"
3080
3198
  }
3081
3199
 
3082
- var anomaly = "accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan," + "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight," + "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
3083
- anomaly.replace(rword, function(name) {
3200
+ var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan",
3201
+ "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight",
3202
+ "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"].join(",")
3203
+ anomaly.replace(rword, function (name) {
3084
3204
  propMap[name.toLowerCase()] = name
3085
3205
  })
3086
3206
 
3087
3207
  var rnoscripts = /<noscript.*?>(?:[\s\S]+?)<\/noscript>/img
3088
3208
  var rnoscriptText = /<noscript.*?>([\s\S]+?)<\/noscript>/im
3089
3209
 
3090
- var getXHR = function() {
3091
- return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")
3210
+ var getXHR = function () {
3211
+ return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")// jshint ignore:line
3092
3212
  }
3093
3213
 
3094
3214
  var cacheTmpls = avalon.templateCache = {}
3095
3215
 
3096
- bindingHandlers.attr = function(data, vmodels) {
3216
+ bindingHandlers.attr = function (data, vmodels) {
3097
3217
  var text = data.value.trim(),
3098
3218
  simple = true
3099
3219
  if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) {
@@ -3107,7 +3227,10 @@ bindingHandlers.attr = function(data, vmodels) {
3107
3227
  var elem = data.element
3108
3228
  data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels)
3109
3229
  data.includeLoaded = getBindingCallback(elem, "data-include-loaded", vmodels)
3110
- var outer = data.includeReplaced = !!avalon(elem).data("includeReplace")
3230
+ var outer = data.includeReplace = !!avalon(elem).data("includeReplace")
3231
+ if (avalon(elem).data("includeCache")) {
3232
+ data.templateCache = {}
3233
+ }
3111
3234
  data.startInclude = DOC.createComment("ms-include")
3112
3235
  data.endInclude = DOC.createComment("ms-include-end")
3113
3236
  if (outer) {
@@ -3123,7 +3246,7 @@ bindingHandlers.attr = function(data, vmodels) {
3123
3246
  parseExprProxy(text, vmodels, data, (simple ? 0 : scanExpr(data.value)))
3124
3247
  }
3125
3248
 
3126
- bindingExecutors.attr = function(val, elem, data) {
3249
+ bindingExecutors.attr = function (val, elem, data) {
3127
3250
  var method = data.type,
3128
3251
  attrName = data.param
3129
3252
  if (method === "css") {
@@ -3158,38 +3281,50 @@ bindingExecutors.attr = function(val, elem, data) {
3158
3281
  var vmodels = data.vmodels
3159
3282
  var rendered = data.includeRendered
3160
3283
  var loaded = data.includeLoaded
3161
- var replace = data.includeReplaced
3284
+ var replace = data.includeReplace
3162
3285
  var target = replace ? elem.parentNode : elem
3163
- var scanTemplate = function(text) {
3286
+ var scanTemplate = function (text) {
3164
3287
  if (loaded) {
3165
3288
  text = loaded.apply(target, [text].concat(vmodels))
3166
3289
  }
3167
3290
  if (rendered) {
3168
- checkScan(target, function() {
3291
+ checkScan(target, function () {
3169
3292
  rendered.call(target)
3170
3293
  }, NaN)
3171
3294
  }
3295
+ var lastID = data.includeLastID
3296
+ if (data.templateCache && lastID && lastID !== val) {
3297
+ var lastTemplate = data.templateCache[lastID]
3298
+ if (!lastTemplate) {
3299
+ lastTemplate = data.templateCache[lastID] = DOC.createElement("div")
3300
+ ifGroup.appendChild(lastTemplate)
3301
+ }
3302
+ }
3303
+ data.includeLastID = val
3172
3304
  while (true) {
3173
3305
  var node = data.startInclude.nextSibling
3174
3306
  if (node && node !== data.endInclude) {
3175
3307
  target.removeChild(node)
3308
+ if (lastTemplate)
3309
+ lastTemplate.appendChild(node)
3176
3310
  } else {
3177
3311
  break
3178
3312
  }
3179
3313
  }
3180
- var dom = avalon.parseHTML(text)
3314
+ var dom = getTemplateNodes(data, val, text)
3181
3315
  var nodes = avalon.slice(dom.childNodes)
3182
3316
  target.insertBefore(dom, data.endInclude)
3183
3317
  scanNodeArray(nodes, vmodels)
3184
3318
  }
3319
+
3185
3320
  if (data.param === "src") {
3186
3321
  if (cacheTmpls[val]) {
3187
- avalon.nextTick(function() {
3322
+ avalon.nextTick(function () {
3188
3323
  scanTemplate(cacheTmpls[val])
3189
3324
  })
3190
3325
  } else {
3191
3326
  var xhr = getXHR()
3192
- xhr.onreadystatechange = function() {
3327
+ xhr.onreadystatechange = function () {
3193
3328
  if (xhr.readyState === 4) {
3194
3329
  var s = xhr.status
3195
3330
  if (s >= 200 && s < 300 || s === 304 || s === 1223) {
@@ -3225,7 +3360,7 @@ bindingExecutors.attr = function(val, elem, data) {
3225
3360
  }
3226
3361
  }
3227
3362
  }
3228
- avalon.nextTick(function() {
3363
+ avalon.nextTick(function () {
3229
3364
  scanTemplate(el.fixIE78 || el.value || el.innerText || el.innerHTML)
3230
3365
  })
3231
3366
  }
@@ -3244,8 +3379,20 @@ bindingExecutors.attr = function(val, elem, data) {
3244
3379
  }
3245
3380
  }
3246
3381
 
3382
+ function getTemplateNodes(data, id, text) {
3383
+ var div = data.templateCache && data.templateCache[id]
3384
+ if (div) {
3385
+ var dom = DOC.createDocumentFragment(), firstChild
3386
+ while (firstChild = div.firstChild) {
3387
+ dom.appendChild(firstChild)
3388
+ }
3389
+ return dom
3390
+ }
3391
+ return avalon.parseHTML(text)
3392
+ }
3393
+
3247
3394
  //这几个指令都可以使用插值表达式,如ms-src="aaa/{{b}}/{{c}}.html"
3248
- "title,alt,src,value,css,include,href".replace(rword, function(name) {
3395
+ "title,alt,src,value,css,include,href".replace(rword, function (name) {
3249
3396
  bindingHandlers[name] = bindingHandlers.attr
3250
3397
  })
3251
3398
  //根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
@@ -3353,7 +3500,7 @@ bindingExecutors.data = function(val, elem, data) {
3353
3500
  }
3354
3501
 
3355
3502
  //双工绑定
3356
- var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
3503
+ var duplexBinding = bindingHandlers.duplex = function (data, vmodels) {
3357
3504
  var elem = data.element,
3358
3505
  hasCast
3359
3506
  parseExprProxy(data.value, vmodels, data, 0, 1)
@@ -3368,7 +3515,7 @@ var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
3368
3515
  if (elem.msData) {
3369
3516
  elem.msData["ms-duplex"] = data.value
3370
3517
  }
3371
- data.param.replace(/\w+/g, function(name) {
3518
+ data.param.replace(/\w+/g, function (name) {
3372
3519
  if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
3373
3520
  if (name === "radio")
3374
3521
  log("ms-duplex-radio已经更名为ms-duplex-checked")
@@ -3391,14 +3538,14 @@ var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
3391
3538
  params.push("string")
3392
3539
  }
3393
3540
  data.param = params.join("-")
3394
- data.bound = function(type, callback) {
3541
+ data.bound = function (type, callback) {
3395
3542
  if (elem.addEventListener) {
3396
3543
  elem.addEventListener(type, callback, false)
3397
3544
  } else {
3398
3545
  elem.attachEvent("on" + type, callback)
3399
3546
  }
3400
3547
  var old = data.rollback
3401
- data.rollback = function() {
3548
+ data.rollback = function () {
3402
3549
  elem.avalonSetter = null
3403
3550
  avalon.unbind(elem, type, callback)
3404
3551
  old && old()
@@ -3420,32 +3567,44 @@ function fixNull(val) {
3420
3567
  }
3421
3568
  avalon.duplexHooks = {
3422
3569
  checked: {
3423
- get: function(val, data) {
3570
+ get: function (val, data) {
3424
3571
  return !data.element.oldValue
3425
3572
  }
3426
3573
  },
3427
3574
  string: {
3428
- get: function(val) { //同步到VM
3575
+ get: function (val) { //同步到VM
3429
3576
  return val
3430
3577
  },
3431
3578
  set: fixNull
3432
3579
  },
3433
3580
  "boolean": {
3434
- get: function(val) {
3581
+ get: function (val) {
3435
3582
  return val === "true"
3436
3583
  },
3437
3584
  set: fixNull
3438
3585
  },
3439
3586
  number: {
3440
- get: function(val) {
3441
- return isFinite(val) ? parseFloat(val) || 0 : val
3587
+ get: function (val, data) {
3588
+ var number = parseFloat(val)
3589
+ if (-val === -number) {
3590
+ return number
3591
+ }
3592
+ var arr = /strong|medium|weak/.exec(data.element.getAttribute("data-duplex-number")) || ["medium"]
3593
+ switch (arr[0]) {
3594
+ case "strong":
3595
+ return 0
3596
+ case "medium":
3597
+ return val === "" ? "" : 0
3598
+ case "weak":
3599
+ return val
3600
+ }
3442
3601
  },
3443
3602
  set: fixNull
3444
3603
  }
3445
3604
  }
3446
3605
 
3447
3606
  function pipe(val, data, action, e) {
3448
- data.param.replace(/\w+/g, function(name) {
3607
+ data.param.replace(/\w+/g, function (name) {
3449
3608
  var hook = avalon.duplexHooks[name]
3450
3609
  if (hook && typeof hook[action] === "function") {
3451
3610
  val = hook[action](val, data)
@@ -3455,18 +3614,8 @@ function pipe(val, data, action, e) {
3455
3614
  }
3456
3615
 
3457
3616
  var TimerID, ribbon = []
3458
- function W3CFire(el, name, detail) {
3459
- var event = DOC.createEvent("Events")
3460
- event.initEvent(name, true, true)
3461
- event.fireByAvalon = true//签名,标记事件是由avalon触发
3462
- //event.isTrusted = false 设置这个opera会报错
3463
- if (detail)
3464
- event.detail = detail
3465
- el.dispatchEvent(event)
3466
- }
3467
-
3468
3617
 
3469
- avalon.tick = function(fn) {
3618
+ avalon.tick = function (fn) {
3470
3619
  if (ribbon.push(fn) === 1) {
3471
3620
  TimerID = setInterval(ticker, 60)
3472
3621
  }
@@ -3485,15 +3634,18 @@ function ticker() {
3485
3634
  }
3486
3635
 
3487
3636
  var watchValueInTimer = noop
3488
- new function() {
3637
+ var rmsinput = /text|password|hidden/
3638
+ new function () {// jshint ignore:line
3489
3639
  try {//#272 IE9-IE11, firefox
3490
3640
  var setters = {}
3491
3641
  var aproto = HTMLInputElement.prototype
3492
3642
  var bproto = HTMLTextAreaElement.prototype
3493
- function newSetter(value) {
3643
+ function newSetter(value) {// jshint ignore:line
3494
3644
  if (avalon.contains(root, this)) {
3495
3645
  setters[this.tagName].call(this, value)
3496
- if (this.avalonSetter) {
3646
+ if (!rmsinput.test(this.type))
3647
+ return
3648
+ if (!this.msFocus && this.avalonSetter) {
3497
3649
  this.avalonSetter()
3498
3650
  }
3499
3651
  }
@@ -3511,10 +3663,10 @@ new function() {
3511
3663
  } catch (e) {
3512
3664
  watchValueInTimer = avalon.tick
3513
3665
  }
3514
- }
3666
+ }// jshint ignore:line
3515
3667
 
3516
3668
  if (IEVersion) {
3517
- avalon.bind(DOC, "selectionchange", function(e) {
3669
+ avalon.bind(DOC, "selectionchange", function (e) {
3518
3670
  var el = DOC.activeElement
3519
3671
  if (el && typeof el.avalonSetter === "function") {
3520
3672
  el.avalonSetter()
@@ -3523,8 +3675,8 @@ if (IEVersion) {
3523
3675
  }
3524
3676
 
3525
3677
  //处理radio, checkbox, text, textarea, password
3526
- duplexBinding.INPUT = function(element, evaluator, data) {
3527
- var type = element.type,
3678
+ duplexBinding.INPUT = function (element, evaluator, data) {
3679
+ var $type = element.type,
3528
3680
  bound = data.bound,
3529
3681
  $elem = avalon(element),
3530
3682
  composing = false
@@ -3541,8 +3693,7 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3541
3693
  composing = false
3542
3694
  }
3543
3695
  //当value变化时改变model的值
3544
-
3545
- function updateVModel() {
3696
+ var updateVModel = function () {
3546
3697
  if (composing) //处理中文输入法在minlengh下引发的BUG
3547
3698
  return
3548
3699
  var val = element.oldValue = element.value //防止递归调用形成死循环
@@ -3551,34 +3702,34 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3551
3702
  evaluator(lastValue)
3552
3703
  callback.call(element, lastValue)
3553
3704
  if ($elem.data("duplex-focus")) {
3554
- avalon.nextTick(function() {
3705
+ avalon.nextTick(function () {
3555
3706
  element.focus()
3556
3707
  })
3557
3708
  }
3558
3709
  }
3559
3710
  }
3560
3711
  //当model变化时,它就会改变value的值
3561
- data.handler = function() {
3712
+ data.handler = function () {
3562
3713
  var val = data.pipe(evaluator(), data, "set") + ""//fix #673
3563
3714
  if (val !== element.oldValue) {
3564
3715
  element.value = val
3565
3716
  }
3566
3717
  }
3567
- if (data.isChecked || element.type === "radio") {
3718
+ if (data.isChecked || $type === "radio") {
3568
3719
  var IE6 = IEVersion === 6
3569
- updateVModel = function() {
3720
+ updateVModel = function () {
3570
3721
  if ($elem.data("duplex-observe") !== false) {
3571
3722
  var lastValue = data.pipe(element.value, data, "get")
3572
3723
  evaluator(lastValue)
3573
3724
  callback.call(element, lastValue)
3574
3725
  }
3575
3726
  }
3576
- data.handler = function() {
3727
+ data.handler = function () {
3577
3728
  var val = evaluator()
3578
3729
  var checked = data.isChecked ? !!val : val + "" === element.value
3579
3730
  element.oldValue = checked
3580
3731
  if (IE6) {
3581
- setTimeout(function() {
3732
+ setTimeout(function () {
3582
3733
  //IE8 checkbox, radio是使用defaultChecked控制选中状态,
3583
3734
  //并且要先设置defaultChecked后设置checked
3584
3735
  //并且必须设置延迟
@@ -3590,8 +3741,8 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3590
3741
  }
3591
3742
  }
3592
3743
  bound("click", updateVModel)
3593
- } else if (type === "checkbox") {
3594
- updateVModel = function() {
3744
+ } else if ($type === "checkbox") {
3745
+ updateVModel = function () {
3595
3746
  if ($elem.data("duplex-observe") !== false) {
3596
3747
  var method = element.checked ? "ensure" : "remove"
3597
3748
  var array = evaluator()
@@ -3604,22 +3755,22 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3604
3755
  }
3605
3756
  }
3606
3757
 
3607
- data.handler = function() {
3758
+ data.handler = function () {
3608
3759
  var array = [].concat(evaluator()) //强制转换为数组
3609
3760
  element.checked = array.indexOf(data.pipe(element.value, data, "get")) > -1
3610
3761
  }
3611
3762
  bound(W3C ? "change" : "click", updateVModel)
3612
3763
  } else {
3613
- var events = element.getAttribute("data-duplex-event") || element.getAttribute("data-event") || "input"
3764
+ var events = element.getAttribute("data-duplex-event") || "input"
3614
3765
  if (element.attributes["data-event"]) {
3615
3766
  log("data-event指令已经废弃,请改用data-duplex-event")
3616
3767
  }
3617
- function delay(e) {
3618
- setTimeout(function() {
3768
+ function delay(e) {// jshint ignore:line
3769
+ setTimeout(function () {
3619
3770
  updateVModel(e)
3620
3771
  })
3621
3772
  }
3622
- events.replace(rword, function(name) {
3773
+ events.replace(rword, function (name) {
3623
3774
  switch (name) {
3624
3775
  case "input":
3625
3776
  if (!IEVersion) { // W3C
@@ -3633,7 +3784,7 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3633
3784
  if (IEVersion > 8) {
3634
3785
  bound("input", updateVModel)//IE9使用propertychange无法监听中文输入改动
3635
3786
  } else {
3636
- bound("propertychange", function(e) {//IE6-8下第一次修改时不会触发,需要使用keydown或selectionchange修正
3787
+ bound("propertychange", function (e) {//IE6-8下第一次修改时不会触发,需要使用keydown或selectionchange修正
3637
3788
  if (e.propertyName === "value") {
3638
3789
  updateVModel()
3639
3790
  }
@@ -3649,19 +3800,28 @@ duplexBinding.INPUT = function(element, evaluator, data) {
3649
3800
  break
3650
3801
  }
3651
3802
  })
3652
- }
3653
- if (/text|password/.test(element.type)) {
3654
- watchValueInTimer(function() {
3655
- if (root.contains(element)) {
3656
- if (element.value !== element.oldValue) {
3657
- updateVModel()
3658
- }
3659
- } else if (!element.msRetain) {
3660
- return false
3661
- }
3803
+ bound("focus", function () {
3804
+ element.msFocus = true
3662
3805
  })
3806
+ bound("blur", function () {
3807
+ element.msFocus = false
3808
+ })
3809
+
3810
+ if (rmsinput.test($type)) {
3811
+ watchValueInTimer(function () {
3812
+ if (root.contains(element)) {
3813
+ if (!element.msFocus && element.oldValue !== element.value) {
3814
+ updateVModel()
3815
+ }
3816
+ } else if (!element.msRetain) {
3817
+ return false
3818
+ }
3819
+ })
3820
+ }
3821
+
3822
+ element.avalonSetter = updateVModel//#765
3663
3823
  }
3664
- element.avalonSetter = updateVModel
3824
+
3665
3825
  element.oldValue = element.value
3666
3826
  registerSubscriber(data)
3667
3827
  callback.call(element, element.value)
@@ -3853,11 +4013,10 @@ bindingHandlers.repeat = function(data, vmodels) {
3853
4013
  var xtype = avalon.type($repeat)
3854
4014
  if (xtype !== "object" && xtype !== "array") {
3855
4015
  freturn = true
3856
- avalon.log("warning:" + data.value + "对应类型不正确")
4016
+ avalon.log("warning:" + data.value + "只能是对象或数组")
3857
4017
  }
3858
4018
  } catch (e) {
3859
4019
  freturn = true
3860
- avalon.log("warning:" + data.value + "编译出错")
3861
4020
  }
3862
4021
 
3863
4022
  var arr = data.value.split(".") || []
@@ -4199,7 +4358,7 @@ function recycleProxies(proxies, type) {
4199
4358
  proxy.$events[i].forEach(function(data) {
4200
4359
  if (typeof data === "object")
4201
4360
  disposeData(data)
4202
- })
4361
+ })// jshint ignore:line
4203
4362
  proxy.$events[i].length = 0
4204
4363
  }
4205
4364
  }
@@ -4363,18 +4522,18 @@ var rsanitize = {
4363
4522
  var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g
4364
4523
  var rnoalphanumeric = /([^\#-~| |!])/g;
4365
4524
 
4366
- function numberFormat(number, decimals, dec_point, thousands_sep) {
4525
+ function numberFormat(number, decimals, point, thousands) {
4367
4526
  //form http://phpjs.org/functions/number_format/
4368
4527
  //number 必需,要格式化的数字
4369
4528
  //decimals 可选,规定多少个小数位。
4370
- //dec_point 可选,规定用作小数点的字符串(默认为 . )。
4371
- //thousands_sep 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。
4529
+ //point 可选,规定用作小数点的字符串(默认为 . )。
4530
+ //thousands 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。
4372
4531
  number = (number + '')
4373
4532
  .replace(/[^0-9+\-Ee.]/g, '')
4374
4533
  var n = !isFinite(+number) ? 0 : +number,
4375
- prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
4376
- sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
4377
- dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
4534
+ prec = !isFinite(+decimals) ? 3 : Math.abs(decimals),
4535
+ sep = thousands || ",",
4536
+ dec = point || ".",
4378
4537
  s = '',
4379
4538
  toFixedFix = function(n, prec) {
4380
4539
  var k = Math.pow(10, prec)
@@ -4436,7 +4595,7 @@ var filters = avalon.filters = {
4436
4595
  if (reg) {
4437
4596
  a = a.replace(reg, function(s, name, value) {
4438
4597
  var quote = value.charAt(0)
4439
- return name + "=" + quote + "javascript:void(0)" + quote
4598
+ return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line
4440
4599
  })
4441
4600
  }
4442
4601
  }
@@ -4461,9 +4620,7 @@ var filters = avalon.filters = {
4461
4620
  currency: function(amount, symbol, fractionSize) {
4462
4621
  return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2)
4463
4622
  },
4464
- number: function(number, fractionSize) {
4465
- return numberFormat(number, isFinite(fractionSize) ? fractionSize : 3)
4466
- }
4623
+ number: numberFormat
4467
4624
  }
4468
4625
  /*
4469
4626
  'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
@@ -4498,7 +4655,7 @@ var filters = avalon.filters = {
4498
4655
  'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm)
4499
4656
  'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm)
4500
4657
  */
4501
- new function() {
4658
+ new function() {// jshint ignore:line
4502
4659
  function toInt(str) {
4503
4660
  return parseInt(str, 10) || 0
4504
4661
  }
@@ -4698,7 +4855,7 @@ new function() {
4698
4855
  }
4699
4856
  locate.SHORTMONTH = locate.MONTH
4700
4857
  filters.date.locate = locate
4701
- }
4858
+ }// jshint ignore:line
4702
4859
  /*********************************************************************
4703
4860
  * AMD加载器 *
4704
4861
  **********************************************************************/
@@ -4722,15 +4879,14 @@ var modules = avalon.modules = {
4722
4879
  // 4(execute) 其依赖也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行
4723
4880
  modules.exports = modules.avalon
4724
4881
 
4725
- new function() {
4882
+ new function () {// jshint ignore:line
4726
4883
  var loadings = [] //正在加载中的模块列表
4727
4884
  var factorys = [] //放置define方法的factory函数
4728
4885
  var rjsext = /\.js$/i
4729
- var name2url = {}
4730
4886
  function makeRequest(name, config) {
4731
4887
  //1. 去掉资源前缀
4732
4888
  var res = "js"
4733
- name = name.replace(/^(\w+)\!/, function(a, b) {
4889
+ name = name.replace(/^(\w+)\!/, function (a, b) {
4734
4890
  res = b
4735
4891
  return ""
4736
4892
  })
@@ -4740,14 +4896,14 @@ new function() {
4740
4896
  }
4741
4897
  //2. 去掉querystring, hash
4742
4898
  var query = ""
4743
- name = name.replace(rquery, function(a) {
4899
+ name = name.replace(rquery, function (a) {
4744
4900
  query = a
4745
4901
  return ""
4746
4902
  })
4747
4903
  //3. 去掉扩展名
4748
4904
  var suffix = "." + res
4749
4905
  var ext = /js|css/.test(suffix) ? suffix : ""
4750
- name = name.replace(/\.[a-z0-9]+$/g, function(a) {
4906
+ name = name.replace(/\.[a-z0-9]+$/g, function (a) {
4751
4907
  if (a === suffix) {
4752
4908
  ext = a
4753
4909
  return ""
@@ -4772,7 +4928,7 @@ new function() {
4772
4928
  //1. 如果该模块已经发出请求,直接返回
4773
4929
  var module = modules[name]
4774
4930
  var urlNoQuery = name && req.urlNoQuery
4775
- if (module && module.state >= 3) {
4931
+ if (module && module.state >= 1) {
4776
4932
  return name
4777
4933
  }
4778
4934
  module = modules[urlNoQuery]
@@ -4785,9 +4941,9 @@ new function() {
4785
4941
  id: urlNoQuery,
4786
4942
  state: 1 //send
4787
4943
  }
4788
- var wrap = function(obj) {
4944
+ var wrap = function (obj) {
4789
4945
  resources[res] = obj
4790
- obj.load(name, req, function(a) {
4946
+ obj.load(name, req, function (a) {
4791
4947
  if (arguments.length && a !== void 0) {
4792
4948
  module.exports = a
4793
4949
  }
@@ -4808,7 +4964,7 @@ new function() {
4808
4964
  //核心API之一 require
4809
4965
  var requireQueue = []
4810
4966
  var isUserFirstRequire = false
4811
- innerRequire = avalon.require = function(array, factory, parentUrl, defineConfig) {
4967
+ innerRequire = avalon.require = function (array, factory, parentUrl, defineConfig) {
4812
4968
  if (!isUserFirstRequire) {
4813
4969
  requireQueue.push(avalon.slice(arguments))
4814
4970
  if (arguments.length <= 2) {
@@ -4826,7 +4982,7 @@ new function() {
4826
4982
  }
4827
4983
  var deps = [] // 放置所有依赖项的完整路径
4828
4984
  var uniq = {}
4829
- var id = parentUrl || "callback" + setTimeout("1")
4985
+ var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line
4830
4986
  defineConfig = defineConfig || {}
4831
4987
  defineConfig.baseUrl = kernel.baseUrl
4832
4988
  var isBuilt = !!defineConfig.built
@@ -4838,7 +4994,7 @@ new function() {
4838
4994
  var req = makeRequest(defineConfig.defineName, defineConfig)
4839
4995
  id = req.urlNoQuery
4840
4996
  } else {
4841
- array.forEach(function(name) {
4997
+ array.forEach(function (name) {
4842
4998
  var req = makeRequest(name, defineConfig)
4843
4999
  var url = fireRequest(req) //加载资源,并返回该资源的完整地址
4844
5000
  if (url) {
@@ -4867,7 +5023,7 @@ new function() {
4867
5023
  }
4868
5024
 
4869
5025
  //核心API之二 require
4870
- innerRequire.define = function(name, deps, factory) { //模块名,依赖列表,模块本身
5026
+ innerRequire.define = function (name, deps, factory) { //模块名,依赖列表,模块本身
4871
5027
  if (typeof name !== "string") {
4872
5028
  factory = deps
4873
5029
  deps = name
@@ -4882,7 +5038,7 @@ new function() {
4882
5038
  defineName: name
4883
5039
  }
4884
5040
  var args = [deps, factory, config]
4885
- factory.require = function(url) {
5041
+ factory.require = function (url) {
4886
5042
  args.splice(2, 0, url)
4887
5043
  if (modules[url]) {
4888
5044
  modules[url].state = 3 //loaded
@@ -4927,19 +5083,19 @@ new function() {
4927
5083
  var allpackages = kernel["packages"] = []
4928
5084
  var allargs = kernel["orig.args"] = {}
4929
5085
  avalon.mix(plugins, {
4930
- paths: function(hash) {
5086
+ paths: function (hash) {
4931
5087
  avalon.mix(allpaths, hash)
4932
5088
  kernel.paths = makeIndexArray(allpaths)
4933
5089
  },
4934
- map: function(hash) {
5090
+ map: function (hash) {
4935
5091
  avalon.mix(allmaps, hash)
4936
5092
  var list = makeIndexArray(allmaps, 1, 1)
4937
- avalon.each(list, function(_, item) {
5093
+ avalon.each(list, function (_, item) {
4938
5094
  item.val = makeIndexArray(item.val)
4939
5095
  })
4940
5096
  kernel.map = list
4941
5097
  },
4942
- packages: function(array) {
5098
+ packages: function (array) {
4943
5099
  array = array.concat(allpackages)
4944
5100
  var uniq = {}
4945
5101
  var ret = []
@@ -4956,14 +5112,14 @@ new function() {
4956
5112
  }
4957
5113
  kernel.packages = ret.sort()
4958
5114
  },
4959
- urlArgs: function(hash) {
5115
+ urlArgs: function (hash) {
4960
5116
  if (typeof hash === "string") {
4961
5117
  hash = {"*": hash}
4962
5118
  }
4963
5119
  avalon.mix(allargs, hash)
4964
5120
  kernel.urlArgs = makeIndexArray(allargs, 1)
4965
5121
  },
4966
- baseUrl: function(url) {
5122
+ baseUrl: function (url) {
4967
5123
  if (!isAbsUrl(url)) {
4968
5124
  var baseElement = head.getElementsByTagName("base")[0]
4969
5125
  if (baseElement) {
@@ -4979,7 +5135,7 @@ new function() {
4979
5135
  if (url.length > 3)
4980
5136
  kernel.baseUrl = url
4981
5137
  },
4982
- shim: function(obj) {
5138
+ shim: function (obj) {
4983
5139
  for (var i in obj) {
4984
5140
  var value = obj[i]
4985
5141
  if (Array.isArray(value)) {
@@ -5012,7 +5168,7 @@ new function() {
5012
5168
  var id = trimQuery(node.src) //检测是否死链
5013
5169
  node.onload = node.onreadystatechange = node.onerror = null
5014
5170
  if (onError || (fuckIE && modules[id] && !modules[id].state)) {
5015
- setTimeout(function() {
5171
+ setTimeout(function () {
5016
5172
  head.removeChild(node)
5017
5173
  node = null // 处理旧式IE下的循环引用问题
5018
5174
  })
@@ -5030,10 +5186,6 @@ new function() {
5030
5186
  if (!deps)
5031
5187
  continue
5032
5188
  for (var j = 0, key; key = deps[j]; j++) {
5033
- var k = name2url[key]
5034
- if (k) {
5035
- key = deps[j] = k
5036
- }
5037
5189
  if (Object(modules[key]).state !== 4) {
5038
5190
  continue loop
5039
5191
  }
@@ -5074,7 +5226,7 @@ new function() {
5074
5226
  }
5075
5227
  }
5076
5228
  node[onEvent] = onload
5077
- node.onerror = function() {
5229
+ node.onerror = function () {
5078
5230
  checkFail(node, true)
5079
5231
  }
5080
5232
 
@@ -5089,14 +5241,14 @@ new function() {
5089
5241
  load: noop
5090
5242
  },
5091
5243
  js: {
5092
- load: function(name, req, onLoad) {
5244
+ load: function (name, req, onLoad) {
5093
5245
  var url = req.url
5094
5246
  var id = req.urlNoQuery
5095
5247
  var shim = kernel.shim[name.replace(rjsext, "")]
5096
5248
  if (shim) { //shim机制
5097
- innerRequire(shim.deps || [], function() {
5249
+ innerRequire(shim.deps || [], function () {
5098
5250
  var args = avalon.slice(arguments)
5099
- loadJS(url, id, function() {
5251
+ loadJS(url, id, function () {
5100
5252
  onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0)
5101
5253
  })
5102
5254
  })
@@ -5106,7 +5258,7 @@ new function() {
5106
5258
  }
5107
5259
  },
5108
5260
  css: {
5109
- load: function(name, req, onLoad) {
5261
+ load: function (name, req, onLoad) {
5110
5262
  var url = req.url
5111
5263
  var node = DOC.createElement("link")
5112
5264
  node.rel = "stylesheet"
@@ -5117,10 +5269,10 @@ new function() {
5117
5269
  }
5118
5270
  },
5119
5271
  text: {
5120
- load: function(name, req, onLoad) {
5272
+ load: function (name, req, onLoad) {
5121
5273
  var url = req.url
5122
5274
  var xhr = getXHR()
5123
- xhr.onreadystatechange = function() {
5275
+ xhr.onreadystatechange = function () {
5124
5276
  if (xhr.readyState === 4) {
5125
5277
  var status = xhr.status;
5126
5278
  if (status > 399 && status < 600) {
@@ -5194,12 +5346,11 @@ new function() {
5194
5346
  }
5195
5347
  }
5196
5348
 
5197
-
5349
+ var rcallback = /^callback\d+$/
5198
5350
  function fireFactory(id, deps, factory) {
5199
5351
  var module = Object(modules[id])
5200
5352
  module.state = 4
5201
5353
  for (var i = 0, array = [], d; d = deps[i++]; ) {
5202
- d = name2url[d] || d
5203
5354
  if (d === "exports") {
5204
5355
  var obj = module.exports || (module.exports = {})
5205
5356
  array.push(obj)
@@ -5207,10 +5358,17 @@ new function() {
5207
5358
  array.push(modules[d].exports)
5208
5359
  }
5209
5360
  }
5210
- var ret = factory.apply(window, array)
5361
+ try {
5362
+ var ret = factory.apply(window, array)
5363
+ } catch (e) {
5364
+ log("执行["+id+"]模块的factory抛错: "+ e)
5365
+ }
5211
5366
  if (ret !== void 0) {
5212
5367
  module.exports = ret
5213
5368
  }
5369
+ if(rcallback.test(id)){
5370
+ delete modules[id]
5371
+ }
5214
5372
  delete module.factory
5215
5373
  return ret
5216
5374
  }
@@ -5223,20 +5381,20 @@ new function() {
5223
5381
  var usePath = 0
5224
5382
  var baseUrl = this.baseUrl
5225
5383
  var rootUrl = this.parentUrl || baseUrl
5226
- eachIndexArray(id, kernel.paths, function(value, key) {
5384
+ eachIndexArray(id, kernel.paths, function (value, key) {
5227
5385
  url = url.replace(key, value)
5228
5386
  usePath = 1
5229
5387
  })
5230
5388
  //2. 是否命中packages配置项
5231
5389
  if (!usePath) {
5232
- eachIndexArray(id, kernel.packages, function(value, key, item) {
5390
+ eachIndexArray(id, kernel.packages, function (value, key, item) {
5233
5391
  url = url.replace(item.name, item.location)
5234
5392
  })
5235
5393
  }
5236
5394
  //3. 是否命中map配置项
5237
5395
  if (this.mapUrl) {
5238
- eachIndexArray(this.mapUrl, kernel.map, function(array) {
5239
- eachIndexArray(url, array, function(mdValue, mdKey) {
5396
+ eachIndexArray(this.mapUrl, kernel.map, function (array) {
5397
+ eachIndexArray(url, array, function (mdValue, mdKey) {
5240
5398
  url = url.replace(mdKey, mdValue)
5241
5399
  rootUrl = baseUrl
5242
5400
  })
@@ -5255,7 +5413,7 @@ new function() {
5255
5413
  var urlNoQuery = url + ext
5256
5414
  url = urlNoQuery + this.query
5257
5415
  //6. 处理urlArgs
5258
- eachIndexArray(id, kernel.urlArgs, function(value) {
5416
+ eachIndexArray(id, kernel.urlArgs, function (value) {
5259
5417
  url += (url.indexOf("?") === -1 ? "?" : "&") + value;
5260
5418
  })
5261
5419
  this.url = url
@@ -5274,7 +5432,7 @@ new function() {
5274
5432
  }
5275
5433
 
5276
5434
  function makeExports(value) {
5277
- return function() {
5435
+ return function () {
5278
5436
  var ret
5279
5437
  if (value.init) {
5280
5438
  ret = value.init.apply(window, arguments)
@@ -5287,7 +5445,7 @@ new function() {
5287
5445
  function hash2array(hash, useStar, part) {
5288
5446
  var array = [];
5289
5447
  for (var key in hash) {
5290
- if (hash.hasOwnProperty(key)) {
5448
+ if (ohasOwn.call(hash, key)) {
5291
5449
  var item = {
5292
5450
  name: key,
5293
5451
  val: hash[key]
@@ -5350,13 +5508,13 @@ new function() {
5350
5508
  return value
5351
5509
  }
5352
5510
  var g = window
5353
- value.split(".").forEach(function(part) {
5511
+ value.split(".").forEach(function (part) {
5354
5512
  g = g[part]
5355
5513
  })
5356
5514
  return g
5357
5515
  }
5358
5516
 
5359
- var mainNode = DOC.scripts[DOC.scripts.length - 1]
5517
+ var mainNode = DOC.scripts[DOC.scripts.length - 1]
5360
5518
  var dataMain = mainNode.getAttribute("data-main")
5361
5519
  if (dataMain) {
5362
5520
  plugins.baseUrl(dataMain)
@@ -5367,23 +5525,21 @@ new function() {
5367
5525
  var loaderUrl = trimQuery(getFullUrl(mainNode, "src"))
5368
5526
  kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1)
5369
5527
  }
5370
- }
5528
+ }// jshint ignore:line
5371
5529
 
5372
5530
  /*********************************************************************
5373
5531
  * DOMReady *
5374
5532
  **********************************************************************/
5375
5533
 
5376
- var readyList = []
5377
- function fireReady() {
5378
- if (DOC.body) { // 在IE8 iframe中doScrollCheck可能不正确
5379
- if (innerRequire) {
5380
- modules["domReady!"].state = 4
5381
- innerRequire.checkDeps()
5382
- }
5383
- readyList.forEach(function(a) {
5384
- a(avalon)
5385
- })
5386
- fireReady = noop //隋性函数,防止IE9二次调用_checkDeps
5534
+ var readyList = [], isReady
5535
+ var fireReady = function(fn) {
5536
+ isReady = true
5537
+ if (innerRequire) {
5538
+ modules["domReady!"].state = 4
5539
+ innerRequire.checkDeps()
5540
+ }
5541
+ while(fn = readyList.shift()){
5542
+ fn(avalon)
5387
5543
  }
5388
5544
  }
5389
5545
 
@@ -5410,17 +5566,17 @@ if (DOC.readyState === "complete") {
5410
5566
  var isTop = window.frameElement === null
5411
5567
  } catch (e) {
5412
5568
  }
5413
- if (root.doScroll && isTop && window.external) {//只有不处于iframe时才用doScroll判断,否则可能会不准
5569
+ if (root.doScroll && isTop && window.external) {//fix IE iframe BUG
5414
5570
  doScrollCheck()
5415
5571
  }
5416
5572
  }
5417
5573
  avalon.bind(window, "load", fireReady)
5418
5574
 
5419
5575
  avalon.ready = function(fn) {
5420
- if (fireReady === noop) {
5421
- fn(avalon)
5422
- } else {
5576
+ if (!isReady) {
5423
5577
  readyList.push(fn)
5578
+ } else {
5579
+ fn(avalon)
5424
5580
  }
5425
5581
  }
5426
5582
 
@@ -5453,11 +5609,11 @@ avalon.ready(function() {
5453
5609
  var _avalon = window.avalon
5454
5610
  avalon.noConflict = function(deep) {
5455
5611
  if (deep && window.avalon === avalon) {
5456
- window.avalon = avalon
5612
+ window.avalon = _avalon
5457
5613
  }
5458
5614
  return avalon
5459
5615
  }
5460
- // Expose avalon and $ identifiers, even in AMD
5616
+ // Expose avalon identifiers, even in AMD
5461
5617
  // and CommonJS for browser emulators
5462
5618
  if (noGlobal === void 0) {
5463
5619
  window.avalon = avalon