avalon-rails 1.4.1.1.20150404164109 → 1.4.6.0.20150915133100
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 +13 -5
- data/lib/avalon-rails/version.rb +1 -1
- data/vendor/assets/javascripts/avalon.js +2066 -1877
- data/vendor/assets/javascripts/avalon.min.js +3 -3
- data/vendor/assets/javascripts/avalon.mobile.js +1653 -1535
- data/vendor/assets/javascripts/avalon.mobile.min.js +3 -3
- data/vendor/assets/javascripts/avalon.mobile.old.js +2030 -1928
- data/vendor/assets/javascripts/avalon.mobile.shim.js +1660 -1548
- data/vendor/assets/javascripts/avalon.modern.js +1481 -1276
- data/vendor/assets/javascripts/avalon.modern.min.js +2 -2
- data/vendor/assets/javascripts/avalon.modern.shim.js +1488 -1289
- data/vendor/assets/javascripts/avalon.shim.js +1863 -1684
- metadata +7 -7
@@ -5,7 +5,7 @@
|
|
5
5
|
http://weibo.com/jslouvre/
|
6
6
|
|
7
7
|
Released under the MIT license
|
8
|
-
avalon.mobile.shim.js 1.
|
8
|
+
avalon.mobile.shim.js 1.46 built in 2015.9.11
|
9
9
|
==================================================*/
|
10
10
|
(function(global, factory) {
|
11
11
|
|
@@ -75,10 +75,10 @@ var aslice = ap.slice
|
|
75
75
|
var Registry = {} //将函数曝光到此对象上,方便访问器收集依赖
|
76
76
|
var W3C = window.dispatchEvent
|
77
77
|
var root = DOC.documentElement
|
78
|
-
var
|
78
|
+
var avalonFragment = DOC.createDocumentFragment()
|
79
79
|
var cinerator = DOC.createElement("div")
|
80
80
|
var class2type = {}
|
81
|
-
"Boolean Number String Function Array Date RegExp Object Error".replace(rword, function(name) {
|
81
|
+
"Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) {
|
82
82
|
class2type["[object " + name + "]"] = name.toLowerCase()
|
83
83
|
})
|
84
84
|
|
@@ -100,30 +100,35 @@ function oneObject(array, val) {
|
|
100
100
|
}
|
101
101
|
|
102
102
|
//生成UUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
103
|
-
var generateID = function(prefix) {
|
103
|
+
var generateID = function (prefix) {
|
104
104
|
prefix = prefix || "avalon"
|
105
|
-
return (
|
105
|
+
return String(Math.random() + Math.random()).replace(/\d\.\d{4}/, prefix)
|
106
106
|
}
|
107
107
|
function IE() {
|
108
108
|
if (window.VBArray) {
|
109
109
|
var mode = document.documentMode
|
110
110
|
return mode ? mode : window.XMLHttpRequest ? 7 : 6
|
111
111
|
} else {
|
112
|
-
return
|
112
|
+
return NaN
|
113
113
|
}
|
114
114
|
}
|
115
115
|
var IEVersion = IE()
|
116
116
|
|
117
|
-
avalon = function(el) { //创建jQuery式的无new 实例化结构
|
117
|
+
avalon = function (el) { //创建jQuery式的无new 实例化结构
|
118
118
|
return new avalon.init(el)
|
119
119
|
}
|
120
120
|
|
121
|
+
avalon.profile = function () {
|
122
|
+
if (window.console && avalon.config.profile) {
|
123
|
+
Function.apply.call(console.log, console, arguments)
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
121
127
|
/*视浏览器情况采用最快的异步回调*/
|
122
|
-
avalon.nextTick = new function() {// jshint ignore:line
|
128
|
+
avalon.nextTick = new function () {// jshint ignore:line
|
123
129
|
var tickImmediate = window.setImmediate
|
124
130
|
var tickObserver = window.MutationObserver
|
125
|
-
|
126
|
-
if (tickImmediate) {
|
131
|
+
if (tickImmediate) {//IE10 \11 edage
|
127
132
|
return tickImmediate.bind(window)
|
128
133
|
}
|
129
134
|
|
@@ -136,32 +141,32 @@ avalon.nextTick = new function() {// jshint ignore:line
|
|
136
141
|
queue = queue.slice(n)
|
137
142
|
}
|
138
143
|
|
139
|
-
if (tickObserver) {
|
144
|
+
if (tickObserver) {// 支持MutationObserver
|
140
145
|
var node = document.createTextNode("avalon")
|
141
146
|
new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line
|
142
|
-
return function(fn) {
|
147
|
+
return function (fn) {
|
143
148
|
queue.push(fn)
|
144
149
|
node.data = Math.random()
|
145
150
|
}
|
146
151
|
}
|
147
152
|
|
148
|
-
if (
|
149
|
-
|
150
|
-
var source = e.source
|
151
|
-
if ((source === window || source === null) && e.data === "process-tick") {
|
152
|
-
e.stopPropagation()
|
153
|
-
callback()
|
154
|
-
}
|
155
|
-
})
|
156
|
-
|
157
|
-
return function(fn) {
|
153
|
+
if (window.VBArray) {
|
154
|
+
return function (fn) {
|
158
155
|
queue.push(fn)
|
159
|
-
|
156
|
+
var node = DOC.createElement("script")
|
157
|
+
node.onreadystatechange = function () {
|
158
|
+
callback() //在interactive阶段就触发
|
159
|
+
node.onreadystatechange = null
|
160
|
+
head.removeChild(node)
|
161
|
+
node = null
|
162
|
+
}
|
163
|
+
head.appendChild(node)
|
160
164
|
}
|
161
165
|
}
|
162
166
|
|
163
|
-
|
164
|
-
|
167
|
+
|
168
|
+
return function (fn) {
|
169
|
+
setTimeout(fn, 4)
|
165
170
|
}
|
166
171
|
}// jshint ignore:line
|
167
172
|
/*********************************************************************
|
@@ -262,7 +267,7 @@ function _number(a, len) { //用于模拟slice, splice的效果
|
|
262
267
|
avalon.mix({
|
263
268
|
rword: rword,
|
264
269
|
subscribers: subscribers,
|
265
|
-
version: 1.
|
270
|
+
version: 1.46,
|
266
271
|
ui: {},
|
267
272
|
log: log,
|
268
273
|
slice: function(nodes, start, end) {
|
@@ -465,6 +470,7 @@ var Cache = new function() {// jshint ignore:line
|
|
465
470
|
entry.newer =
|
466
471
|
entry.older =
|
467
472
|
this._keymap[entry.key] = void 0
|
473
|
+
delete this._keymap[entry.key] //#1029
|
468
474
|
}
|
469
475
|
}
|
470
476
|
p.get = function(key) {
|
@@ -641,7 +647,6 @@ if (DOC.onmousewheel === void 0) {
|
|
641
647
|
}
|
642
648
|
}
|
643
649
|
}
|
644
|
-
|
645
650
|
/*********************************************************************
|
646
651
|
* 配置系统 *
|
647
652
|
**********************************************************************/
|
@@ -679,15 +684,15 @@ var plugins = {
|
|
679
684
|
openTag = array[0]
|
680
685
|
closeTag = array[1]
|
681
686
|
if (openTag === closeTag) {
|
682
|
-
throw new SyntaxError("openTag
|
683
|
-
} else if (array + "" === "<!--,-->") {
|
684
|
-
kernel.commentInterpolate = true
|
687
|
+
throw new SyntaxError("openTag===closeTag")
|
685
688
|
} else {
|
686
689
|
var test = openTag + "test" + closeTag
|
687
690
|
cinerator.innerHTML = test
|
688
691
|
if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) {
|
689
692
|
throw new SyntaxError("此定界符不合法")
|
690
693
|
}
|
694
|
+
kernel.openTag = openTag
|
695
|
+
kernel.closeTag = closeTag
|
691
696
|
cinerator.innerHTML = ""
|
692
697
|
}
|
693
698
|
var o = escapeRegExp(openTag),
|
@@ -776,8 +781,8 @@ var EventBus = {
|
|
776
781
|
}
|
777
782
|
//循环两个vmodel中的节点,查找匹配(向上匹配或者向下匹配)的节点并设置标识
|
778
783
|
/* jshint ignore:start */
|
779
|
-
|
780
|
-
|
784
|
+
ap.forEach.call(eventNodes, function (node) {
|
785
|
+
ap.forEach.call(elements, function (element) {
|
781
786
|
var ok = special === "down" ? element.contains(node) : //向下捕获
|
782
787
|
node.contains(element) //向上冒泡
|
783
788
|
if (ok) {
|
@@ -791,7 +796,7 @@ var EventBus = {
|
|
791
796
|
}
|
792
797
|
var nodes = DOC.getElementsByTagName("*") //实现节点排序
|
793
798
|
var alls = []
|
794
|
-
|
799
|
+
ap.forEach.call(nodes, function (el) {
|
795
800
|
if (el._avalon) {
|
796
801
|
alls.push(el._avalon)
|
797
802
|
el._avalon = ""
|
@@ -820,12 +825,11 @@ var EventBus = {
|
|
820
825
|
}
|
821
826
|
}
|
822
827
|
}
|
823
|
-
|
824
828
|
/*********************************************************************
|
825
829
|
* modelFactory *
|
826
830
|
**********************************************************************/
|
827
831
|
//avalon最核心的方法的两个方法之一(另一个是avalon.scan),返回一个ViewModel(VM)
|
828
|
-
var VMODELS = avalon.vmodels =
|
832
|
+
var VMODELS = avalon.vmodels = {} //所有vmodel都储存在这里
|
829
833
|
avalon.define = function (id, factory) {
|
830
834
|
var $id = id.$id || id
|
831
835
|
if (!$id) {
|
@@ -851,194 +855,271 @@ avalon.define = function (id, factory) {
|
|
851
855
|
}
|
852
856
|
|
853
857
|
//一些不需要被监听的属性
|
854
|
-
var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray").match(rword)
|
855
|
-
|
856
|
-
function isObservable(name, value, $skipArray) {
|
857
|
-
if (isFunction(value) || value && value.nodeType) {
|
858
|
-
return false
|
859
|
-
}
|
860
|
-
if ($skipArray.indexOf(name) !== -1) {
|
861
|
-
return false
|
862
|
-
}
|
863
|
-
if ($$skipArray.indexOf(name) !== -1) {
|
864
|
-
return false
|
865
|
-
}
|
866
|
-
var $special = $skipArray.$special
|
867
|
-
if (name && name.charAt(0) === "$" && !$special[name]) {
|
868
|
-
return false
|
869
|
-
}
|
870
|
-
return true
|
871
|
-
}
|
872
|
-
//ms-with,ms-each, ms-repeat绑定生成的代理对象储存池
|
873
|
-
var midway = createMap()
|
874
|
-
function getNewValue(accessor, name, value, $vmodel) {
|
875
|
-
switch (accessor.type) {
|
876
|
-
case 0://计算属性
|
877
|
-
var getter = accessor.get
|
878
|
-
var setter = accessor.set
|
879
|
-
if (isFunction(setter)) {
|
880
|
-
var $events = $vmodel.$events
|
881
|
-
var lock = $events[name]
|
882
|
-
$events[name] = [] //清空回调,防止内部冒泡而触发多次$fire
|
883
|
-
setter.call($vmodel, value)
|
884
|
-
$events[name] = lock
|
885
|
-
}
|
886
|
-
return getter.call($vmodel) //同步$model
|
887
|
-
case 1://监控属性
|
888
|
-
return value
|
889
|
-
case 2://对象属性(包括数组与哈希)
|
890
|
-
if (value !== $vmodel.$model[name]) {
|
891
|
-
var svmodel = accessor.svmodel = objectFactory($vmodel, name, value, accessor.valueType)
|
892
|
-
value = svmodel.$model //同步$model
|
893
|
-
var fn = midway[svmodel.$id]
|
894
|
-
fn && fn() //同步视图
|
895
|
-
}
|
896
|
-
return value
|
897
|
-
}
|
898
|
-
}
|
858
|
+
var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray,$reinitialize").match(rword)
|
899
859
|
|
900
860
|
function modelFactory(source, $special, $model) {
|
901
861
|
if (Array.isArray(source)) {
|
902
862
|
var arr = source.concat()
|
903
863
|
source.length = 0
|
904
|
-
var collection =
|
864
|
+
var collection = arrayFactory(source)// jshint ignore:line
|
905
865
|
collection.pushArray(arr)
|
906
866
|
return collection
|
907
867
|
}
|
908
|
-
//0 null undefined || Node || VModel
|
868
|
+
//0 null undefined || Node || VModel(fix IE6-8 createWithProxy $val: val引发的BUG)
|
909
869
|
if (!source || source.nodeType > 0 || (source.$id && source.$events)) {
|
910
870
|
return source
|
911
871
|
}
|
912
|
-
|
913
|
-
|
914
|
-
}
|
915
|
-
source.$skipArray.$special = $special || createMap() //强制要监听的属性
|
872
|
+
var $skipArray = Array.isArray(source.$skipArray) ? source.$skipArray : []
|
873
|
+
$skipArray.$special = $special || createMap() //强制要监听的属性
|
916
874
|
var $vmodel = {} //要返回的对象, 它在IE6-8下可能被偷龙转凤
|
917
875
|
$model = $model || {} //vmodels.$model属性
|
918
876
|
var $events = createMap() //vmodel.$events属性
|
919
|
-
var
|
920
|
-
var
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
877
|
+
var accessors = createMap() //监控属性
|
878
|
+
var computed = []
|
879
|
+
$$skipArray.forEach(function (name) {
|
880
|
+
delete source[name]
|
881
|
+
})
|
882
|
+
|
883
|
+
var names = Object.keys(source)
|
884
|
+
/* jshint ignore:start */
|
885
|
+
names.forEach(function (name, accessor) {
|
886
|
+
var val = source[name]
|
887
|
+
$model[name] = val
|
888
|
+
if (isObservable(name, val, $skipArray)) {
|
927
889
|
//总共产生三种accessor
|
928
890
|
$events[name] = []
|
929
891
|
var valueType = avalon.type(val)
|
930
|
-
var accessor = function (newValue) {
|
931
|
-
var name = accessor._name
|
932
|
-
var $vmodel = this
|
933
|
-
var $model = $vmodel.$model
|
934
|
-
var oldValue = $model[name]
|
935
|
-
var $events = $vmodel.$events
|
936
|
-
|
937
|
-
if (arguments.length) {
|
938
|
-
if (stopRepeatAssign) {
|
939
|
-
return
|
940
|
-
}
|
941
|
-
//计算属性与对象属性需要重新计算newValue
|
942
|
-
if (accessor.type !== 1) {
|
943
|
-
newValue = getNewValue(accessor, name, newValue, $vmodel)
|
944
|
-
if (!accessor.type)
|
945
|
-
return
|
946
|
-
}
|
947
|
-
if (!isEqual(oldValue, newValue)) {
|
948
|
-
$model[name] = newValue
|
949
|
-
notifySubscribers($events[name]) //同步视图
|
950
|
-
safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
|
951
|
-
}
|
952
|
-
} else {
|
953
|
-
if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性
|
954
|
-
//计算属性不需要收集视图刷新函数,都是由其他监控属性代劳
|
955
|
-
newValue = accessor.get.call($vmodel)
|
956
|
-
if (oldValue !== newValue) {
|
957
|
-
$model[name] = newValue
|
958
|
-
//这里不用同步视图
|
959
|
-
safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
|
960
|
-
}
|
961
|
-
return newValue
|
962
|
-
} else {
|
963
|
-
collectSubscribers($events[name]) //收集视图函数
|
964
|
-
return accessor.svmodel || oldValue
|
965
|
-
}
|
966
|
-
}
|
967
|
-
}
|
968
892
|
//总共产生三种accessor
|
969
893
|
if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) {
|
970
|
-
|
971
|
-
accessor
|
972
|
-
accessor.get = val.get
|
973
|
-
accessor.type = 0
|
974
|
-
initCallbacks.push(function () {
|
975
|
-
var data = {
|
976
|
-
evaluator: function () {
|
977
|
-
data.type = Math.random(),
|
978
|
-
data.element = null
|
979
|
-
$model[name] = accessor.get.call($vmodel)
|
980
|
-
},
|
981
|
-
element: head,
|
982
|
-
type: Math.random(),
|
983
|
-
handler: noop,
|
984
|
-
args: []
|
985
|
-
}
|
986
|
-
Registry[expose] = data
|
987
|
-
accessor.call($vmodel)
|
988
|
-
delete Registry[expose]
|
989
|
-
})
|
894
|
+
accessor = makeComputedAccessor(name, val)
|
895
|
+
computed.push(accessor)
|
990
896
|
} else if (rcomplexType.test(valueType)) {
|
991
|
-
|
992
|
-
accessor
|
993
|
-
accessor.valueType = valueType
|
994
|
-
initCallbacks.push(function () {
|
995
|
-
var svmodel = modelFactory(val, 0, $model[name])
|
996
|
-
accessor.svmodel = svmodel
|
997
|
-
svmodel.$events[subscribers] = $events[name]
|
998
|
-
})
|
897
|
+
// issue #940 解决$model层次依赖丢失 https://github.com/RubyLouvre/avalon/issues/940
|
898
|
+
accessor = makeComplexAccessor(name, val, valueType, $events[name], $model)
|
999
899
|
} else {
|
1000
|
-
accessor
|
1001
|
-
//第3种为监控属性,对应简单的数据类型,自变量
|
900
|
+
accessor = makeSimpleAccessor(name, val)
|
1002
901
|
}
|
1003
|
-
|
1004
|
-
|
1005
|
-
})(i, source[i])// jshint ignore:line
|
1006
|
-
}
|
1007
|
-
|
1008
|
-
$$skipArray.forEach(function (name) {
|
1009
|
-
delete source[name]
|
1010
|
-
delete $model[name] //这些特殊属性不应该在$model中出现
|
902
|
+
accessors[name] = accessor
|
903
|
+
}
|
1011
904
|
})
|
1012
|
-
|
1013
|
-
$vmodel = Object.defineProperties($vmodel, descriptorFactory(
|
1014
|
-
for (var
|
1015
|
-
|
905
|
+
/* jshint ignore:end */
|
906
|
+
$vmodel = Object.defineProperties($vmodel, descriptorFactory(accessors)) //生成一个空的ViewModel
|
907
|
+
for (var i = 0; i < names.length; i++) {
|
908
|
+
var name = names[i]
|
909
|
+
if (!accessors[name]) {
|
1016
910
|
$vmodel[name] = source[name]
|
1017
911
|
}
|
1018
912
|
}
|
1019
913
|
//添加$id, $model, $events, $watch, $unwatch, $fire
|
1020
|
-
$vmodel
|
1021
|
-
$vmodel
|
1022
|
-
$vmodel
|
1023
|
-
|
1024
|
-
|
914
|
+
hideProperty($vmodel, "$id", generateID())
|
915
|
+
hideProperty($vmodel, "$model", $model)
|
916
|
+
hideProperty($vmodel, "$events", $events)
|
917
|
+
/* jshint ignore:start */
|
918
|
+
hideProperty($vmodel, "hasOwnProperty", function (name) {
|
919
|
+
return name in this.$model
|
920
|
+
})
|
921
|
+
/* jshint ignore:end */
|
922
|
+
for (var i in EventBus) {
|
923
|
+
hideProperty($vmodel, i, EventBus[i])
|
1025
924
|
}
|
1026
925
|
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
926
|
+
$vmodel.$reinitialize = function () {
|
927
|
+
computed.forEach(function (accessor) {
|
928
|
+
delete accessor._value
|
929
|
+
delete accessor.oldArgs
|
930
|
+
accessor.digest = function () {
|
931
|
+
accessor.call($vmodel)
|
932
|
+
}
|
933
|
+
dependencyDetection.begin({
|
934
|
+
callback: function (vm, dependency) {//dependency为一个accessor
|
935
|
+
var name = dependency._name
|
936
|
+
if (dependency !== accessor) {
|
937
|
+
var list = vm.$events[name]
|
938
|
+
accessor.vm = $vmodel
|
939
|
+
injectDependency(list, accessor.digest)
|
940
|
+
}
|
941
|
+
}
|
942
|
+
})
|
943
|
+
try {
|
944
|
+
accessor.get.call($vmodel)
|
945
|
+
} finally {
|
946
|
+
dependencyDetection.end()
|
947
|
+
}
|
948
|
+
})
|
949
|
+
}
|
950
|
+
$vmodel.$reinitialize()
|
951
|
+
return $vmodel
|
952
|
+
}
|
953
|
+
|
954
|
+
function hideProperty(host, name, value) {
|
955
|
+
Object.defineProperty(host, name, {
|
956
|
+
value: value,
|
957
|
+
writable: true,
|
1032
958
|
enumerable: false,
|
1033
959
|
configurable: true
|
1034
960
|
})
|
961
|
+
}
|
1035
962
|
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
963
|
+
function keysVM(obj) {
|
964
|
+
var arr = Object.keys(obj)
|
965
|
+
for (var i = 0; i < $$skipArray.length; i++) {
|
966
|
+
var index = arr.indexOf($$skipArray[i])
|
967
|
+
if (index !== -1) {
|
968
|
+
arr.splice(index, 1)
|
969
|
+
}
|
970
|
+
}
|
971
|
+
return arr
|
972
|
+
}
|
973
|
+
//创建一个简单访问器
|
974
|
+
function makeSimpleAccessor(name, value) {
|
975
|
+
function accessor(value) {
|
976
|
+
var oldValue = accessor._value
|
977
|
+
if (arguments.length > 0) {
|
978
|
+
if (!stopRepeatAssign && !isEqual(value, oldValue)) {
|
979
|
+
accessor.updateValue(this, value)
|
980
|
+
accessor.notify(this, value, oldValue)
|
981
|
+
}
|
982
|
+
return this
|
983
|
+
} else {
|
984
|
+
dependencyDetection.collectDependency(this, accessor)
|
985
|
+
return oldValue
|
986
|
+
}
|
987
|
+
}
|
988
|
+
accessorFactory(accessor, name)
|
989
|
+
accessor._value = value
|
990
|
+
return accessor;
|
991
|
+
}
|
992
|
+
|
993
|
+
///创建一个计算访问器
|
994
|
+
function makeComputedAccessor(name, options) {
|
995
|
+
function accessor(value) {//计算属性
|
996
|
+
var oldValue = accessor._value
|
997
|
+
var init = ("_value" in accessor)
|
998
|
+
if (arguments.length > 0) {
|
999
|
+
if (stopRepeatAssign) {
|
1000
|
+
return this
|
1001
|
+
}
|
1002
|
+
if (typeof accessor.set === "function") {
|
1003
|
+
if (accessor.oldArgs !== value) {
|
1004
|
+
accessor.oldArgs = value
|
1005
|
+
var $events = this.$events
|
1006
|
+
var lock = $events[name]
|
1007
|
+
$events[name] = [] //清空回调,防止内部冒泡而触发多次$fire
|
1008
|
+
accessor.set.call(this, value)
|
1009
|
+
$events[name] = lock
|
1010
|
+
value = accessor.get.call(this)
|
1011
|
+
if (value !== oldValue) {
|
1012
|
+
accessor.updateValue(this, value)
|
1013
|
+
accessor.notify(this, value, oldValue) //触发$watch回调
|
1014
|
+
}
|
1015
|
+
}
|
1016
|
+
}
|
1017
|
+
return this
|
1018
|
+
} else {
|
1019
|
+
//将依赖于自己的高层访问器或视图刷新函数(以绑定对象形式)放到自己的订阅数组中
|
1020
|
+
//将自己注入到低层访问器的订阅数组中
|
1021
|
+
value = accessor.get.call(this)
|
1022
|
+
accessor.updateValue(this, value)
|
1023
|
+
if (init && oldValue !== value) {
|
1024
|
+
accessor.notify(this, value, oldValue) //触发$watch回调
|
1025
|
+
}
|
1026
|
+
return value
|
1027
|
+
}
|
1028
|
+
}
|
1029
|
+
accessor.set = options.set
|
1030
|
+
accessor.get = options.get
|
1031
|
+
accessorFactory(accessor, name)
|
1032
|
+
return accessor
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
|
1036
|
+
//创建一个复杂访问器
|
1037
|
+
function makeComplexAccessor(name, initValue, valueType, list, parentModel) {
|
1038
|
+
function accessor(value) {
|
1039
|
+
var oldValue = accessor._value
|
1040
|
+
var son = accessor._vmodel
|
1041
|
+
if (arguments.length > 0) {
|
1042
|
+
if (stopRepeatAssign) {
|
1043
|
+
return this
|
1044
|
+
}
|
1045
|
+
if (valueType === "array") {
|
1046
|
+
var a = son, b = value,
|
1047
|
+
an = a.length,
|
1048
|
+
bn = b.length
|
1049
|
+
a.$lock = true
|
1050
|
+
if (an > bn) {
|
1051
|
+
a.splice(bn, an - bn)
|
1052
|
+
} else if (bn > an) {
|
1053
|
+
a.push.apply(a, b.slice(an))
|
1054
|
+
}
|
1055
|
+
var n = Math.min(an, bn)
|
1056
|
+
for (var i = 0; i < n; i++) {
|
1057
|
+
a.set(i, b[i])
|
1058
|
+
}
|
1059
|
+
delete a.$lock
|
1060
|
+
a._fire("set")
|
1061
|
+
} else if (valueType === "object") {
|
1062
|
+
var observes = this.$events[name] || []
|
1063
|
+
var newObject = avalon.mix(true, {}, value)
|
1064
|
+
for (i in son) {
|
1065
|
+
if (son.hasOwnProperty(i) && ohasOwn.call(newObject, i)) {
|
1066
|
+
son[i] = newObject[i]
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
son = accessor._vmodel = modelFactory(value)
|
1070
|
+
son.$events[subscribers] = observes
|
1071
|
+
if (observes.length) {
|
1072
|
+
observes.forEach(function (data) {
|
1073
|
+
if(!data.type) {
|
1074
|
+
return //防止模板先加载报错
|
1075
|
+
}
|
1076
|
+
if (data.rollback) {
|
1077
|
+
data.rollback() //还原 ms-with ms-on
|
1078
|
+
}
|
1079
|
+
bindingHandlers[data.type](data, data.vmodels)
|
1080
|
+
})
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
accessor.updateValue(this, son.$model)
|
1084
|
+
accessor.notify(this, this._value, oldValue)
|
1085
|
+
return this
|
1086
|
+
} else {
|
1087
|
+
dependencyDetection.collectDependency(this, accessor)
|
1088
|
+
return son
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
accessorFactory(accessor, name)
|
1092
|
+
if (Array.isArray(initValue)) {
|
1093
|
+
parentModel[name] = initValue
|
1094
|
+
} else {
|
1095
|
+
parentModel[name] = parentModel[name] || {}
|
1096
|
+
}
|
1097
|
+
var son = accessor._vmodel = modelFactory(initValue, 0, parentModel[name])
|
1098
|
+
son.$events[subscribers] = list
|
1099
|
+
return accessor
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
function globalUpdateValue(vmodel, value) {
|
1103
|
+
vmodel.$model[this._name] = this._value = value
|
1104
|
+
}
|
1105
|
+
function globalUpdateModelValue(vmodel, value) {
|
1106
|
+
vmodel.$model[this._name] = value
|
1107
|
+
}
|
1108
|
+
function globalNotify(vmodel, value, oldValue) {
|
1109
|
+
var name = this._name
|
1110
|
+
var array = vmodel.$events[name] //刷新值
|
1111
|
+
if (array) {
|
1112
|
+
fireDependencies(array) //同步视图
|
1113
|
+
EventBus.$fire.call(vmodel, name, value, oldValue) //触发$watch回调
|
1114
|
+
}
|
1040
1115
|
}
|
1041
1116
|
|
1117
|
+
function accessorFactory(accessor, name) {
|
1118
|
+
accessor._name = name
|
1119
|
+
//同时更新_value与model
|
1120
|
+
accessor.updateValue = globalUpdateValue
|
1121
|
+
accessor.notify = globalNotify
|
1122
|
+
}
|
1042
1123
|
//比较两个值是否相等
|
1043
1124
|
var isEqual = Object.is || function (v1, v2) {
|
1044
1125
|
if (v1 === 0 && v2 === 0) {
|
@@ -1050,14 +1131,22 @@ var isEqual = Object.is || function (v1, v2) {
|
|
1050
1131
|
}
|
1051
1132
|
}
|
1052
1133
|
|
1053
|
-
function
|
1054
|
-
if (
|
1055
|
-
|
1134
|
+
function isObservable(name, value, $skipArray) {
|
1135
|
+
if (isFunction(value) || value && value.nodeType) {
|
1136
|
+
return false
|
1137
|
+
}
|
1138
|
+
if ($skipArray.indexOf(name) !== -1) {
|
1139
|
+
return false
|
1140
|
+
}
|
1141
|
+
var $special = $skipArray.$special
|
1142
|
+
if (name && name.charAt(0) === "$" && !$special[name]) {
|
1143
|
+
return false
|
1056
1144
|
}
|
1145
|
+
return true
|
1057
1146
|
}
|
1058
1147
|
|
1059
1148
|
var descriptorFactory = function (obj) {
|
1060
|
-
var descriptors =
|
1149
|
+
var descriptors = {}
|
1061
1150
|
for (var i in obj) {
|
1062
1151
|
descriptors[i] = {
|
1063
1152
|
get: obj[i],
|
@@ -1069,50 +1158,12 @@ var descriptorFactory = function (obj) {
|
|
1069
1158
|
return descriptors
|
1070
1159
|
}
|
1071
1160
|
|
1072
|
-
|
1073
|
-
function objectFactory(parent, name, value, valueType) {
|
1074
|
-
//a为原来的VM, b为新数组或新对象
|
1075
|
-
var son = parent[name]
|
1076
|
-
if (valueType === "array") {
|
1077
|
-
if (!Array.isArray(value) || son === value) {
|
1078
|
-
return son //fix https://github.com/RubyLouvre/avalon/issues/261
|
1079
|
-
}
|
1080
|
-
son._.$unwatch()
|
1081
|
-
son.clear()
|
1082
|
-
son._.$watch()
|
1083
|
-
son.pushArray(value.concat())
|
1084
|
-
return son
|
1085
|
-
} else {
|
1086
|
-
var iterators = parent.$events[name]
|
1087
|
-
var pool = son.$events.$withProxyPool
|
1088
|
-
if (pool) {
|
1089
|
-
recycleProxies(pool, "with")
|
1090
|
-
son.$events.$withProxyPool = null
|
1091
|
-
}
|
1092
|
-
var ret = modelFactory(value)
|
1093
|
-
ret.$events[subscribers] = iterators
|
1094
|
-
midway[ret.$id] = function (data) {
|
1095
|
-
while (data = iterators.shift()) {
|
1096
|
-
(function (el) {
|
1097
|
-
avalon.nextTick(function () {
|
1098
|
-
var type = el.type
|
1099
|
-
if (type && bindingHandlers[type]) { //#753
|
1100
|
-
el.rollback && el.rollback() //还原 ms-with ms-on
|
1101
|
-
bindingHandlers[type](el, el.vmodels)
|
1102
|
-
}
|
1103
|
-
})
|
1104
|
-
})(data)// jshint ignore:line
|
1105
|
-
}
|
1106
|
-
delete midway[ret.$id]
|
1107
|
-
}
|
1108
|
-
return ret
|
1109
|
-
}
|
1110
|
-
}
|
1161
|
+
|
1111
1162
|
/*********************************************************************
|
1112
1163
|
* 监控数组(与ms-each, ms-repeat配合使用) *
|
1113
1164
|
**********************************************************************/
|
1114
1165
|
|
1115
|
-
function
|
1166
|
+
function arrayFactory(model) {
|
1116
1167
|
var array = []
|
1117
1168
|
array.$id = generateID()
|
1118
1169
|
array.$model = model //数据模型
|
@@ -1127,7 +1178,7 @@ function Collection(model) {
|
|
1127
1178
|
for (var i in EventBus) {
|
1128
1179
|
array[i] = EventBus[i]
|
1129
1180
|
}
|
1130
|
-
avalon.mix(array,
|
1181
|
+
avalon.mix(array, arrayPrototype)
|
1131
1182
|
return array
|
1132
1183
|
}
|
1133
1184
|
|
@@ -1135,7 +1186,7 @@ function mutateArray(method, pos, n, index, method2, pos2, n2) {
|
|
1135
1186
|
var oldLen = this.length, loop = 2
|
1136
1187
|
while (--loop) {
|
1137
1188
|
switch (method) {
|
1138
|
-
|
1189
|
+
case "add":
|
1139
1190
|
/* jshint ignore:start */
|
1140
1191
|
var array = this.$model.slice(pos, pos + n).map(function (el) {
|
1141
1192
|
if (rcomplexType.test(avalon.type(el))) {
|
@@ -1169,10 +1220,10 @@ function mutateArray(method, pos, n, index, method2, pos2, n2) {
|
|
1169
1220
|
}
|
1170
1221
|
|
1171
1222
|
var _splice = ap.splice
|
1172
|
-
var
|
1223
|
+
var arrayPrototype = {
|
1173
1224
|
_splice: _splice,
|
1174
1225
|
_fire: function (method, a, b) {
|
1175
|
-
|
1226
|
+
fireDependencies(this.$events[subscribers], method, a, b)
|
1176
1227
|
},
|
1177
1228
|
size: function () { //取得数组长度,这个函数可以同步视图,length不能
|
1178
1229
|
return this._.length
|
@@ -1258,11 +1309,13 @@ var CollectionPrototype = {
|
|
1258
1309
|
},
|
1259
1310
|
removeAll: function (all) { //移除N个元素
|
1260
1311
|
if (Array.isArray(all)) {
|
1261
|
-
all.forEach(function (el) {
|
1262
|
-
this.remove(el)
|
1263
|
-
}, this)
|
1264
|
-
} else if (typeof all === "function") {
|
1265
1312
|
for (var i = this.length - 1; i >= 0; i--) {
|
1313
|
+
if (all.indexOf(this[i]) !== -1) {
|
1314
|
+
this.removeAt(i)
|
1315
|
+
}
|
1316
|
+
}
|
1317
|
+
} else if (typeof all === "function") {
|
1318
|
+
for ( i = this.length - 1; i >= 0; i--) {
|
1266
1319
|
var el = this[i]
|
1267
1320
|
if (all(el, i)) {
|
1268
1321
|
this.removeAt(i)
|
@@ -1279,7 +1332,7 @@ var CollectionPrototype = {
|
|
1279
1332
|
return this
|
1280
1333
|
},
|
1281
1334
|
set: function (index, val) {
|
1282
|
-
if (index
|
1335
|
+
if (index < this.length && index > -1) {
|
1283
1336
|
var valueType = avalon.type(val)
|
1284
1337
|
if (val && val.$model) {
|
1285
1338
|
val = val.$model
|
@@ -1302,6 +1355,15 @@ var CollectionPrototype = {
|
|
1302
1355
|
return this
|
1303
1356
|
}
|
1304
1357
|
}
|
1358
|
+
//相当于原来bindingExecutors.repeat 的index分支
|
1359
|
+
function resetIndex(array, pos) {
|
1360
|
+
var last = array.length - 1
|
1361
|
+
for (var el; el = array[pos]; pos++) {
|
1362
|
+
el.$index = pos
|
1363
|
+
el.$first = pos === 0
|
1364
|
+
el.$last = pos === last
|
1365
|
+
}
|
1366
|
+
}
|
1305
1367
|
|
1306
1368
|
function sortByIndex(array, indexes) {
|
1307
1369
|
var map = {};
|
@@ -1318,7 +1380,7 @@ function sortByIndex(array, indexes) {
|
|
1318
1380
|
}
|
1319
1381
|
|
1320
1382
|
"sort,reverse".replace(rword, function (method) {
|
1321
|
-
|
1383
|
+
arrayPrototype[method] = function () {
|
1322
1384
|
var newArray = this.$model//这是要排序的新数组
|
1323
1385
|
var oldArray = newArray.concat() //保持原来状态的旧数组
|
1324
1386
|
var mask = Math.random()
|
@@ -1339,28 +1401,57 @@ function sortByIndex(array, indexes) {
|
|
1339
1401
|
}
|
1340
1402
|
if (hasSort) {
|
1341
1403
|
sortByIndex(this, indexes)
|
1404
|
+
// sortByIndex(this.$proxy, indexes)
|
1342
1405
|
this._fire("move", indexes)
|
1343
|
-
|
1406
|
+
this._fire("index", 0)
|
1344
1407
|
}
|
1345
1408
|
return this
|
1346
1409
|
}
|
1347
1410
|
})
|
1348
1411
|
|
1412
|
+
|
1349
1413
|
/*********************************************************************
|
1350
1414
|
* 依赖调度系统 *
|
1351
1415
|
**********************************************************************/
|
1416
|
+
//检测两个对象间的依赖关系
|
1417
|
+
var dependencyDetection = (function () {
|
1418
|
+
var outerFrames = []
|
1419
|
+
var currentFrame
|
1420
|
+
return {
|
1421
|
+
begin: function (accessorObject) {
|
1422
|
+
//accessorObject为一个拥有callback的对象
|
1423
|
+
outerFrames.push(currentFrame)
|
1424
|
+
currentFrame = accessorObject
|
1425
|
+
},
|
1426
|
+
end: function () {
|
1427
|
+
currentFrame = outerFrames.pop()
|
1428
|
+
},
|
1429
|
+
collectDependency: function (vmodel, accessor) {
|
1430
|
+
if (currentFrame) {
|
1431
|
+
//被dependencyDetection.begin调用
|
1432
|
+
currentFrame.callback(vmodel, accessor);
|
1433
|
+
}
|
1434
|
+
}
|
1435
|
+
};
|
1436
|
+
})()
|
1437
|
+
//将绑定对象注入到其依赖项的订阅数组中
|
1352
1438
|
var ronduplex = /^(duplex|on)$/
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1439
|
+
avalon.injectBinding = function (data) {
|
1440
|
+
var valueFn = data.evaluator
|
1441
|
+
if (valueFn) { //如果是求值函数
|
1442
|
+
dependencyDetection.begin({
|
1443
|
+
callback: function (vmodel, dependency) {
|
1444
|
+
injectDependency(vmodel.$events[dependency._name], data)
|
1445
|
+
}
|
1446
|
+
})
|
1359
1447
|
try {
|
1360
|
-
var
|
1361
|
-
|
1448
|
+
var value = ronduplex.test(data.type) ? data : valueFn.apply(0, data.args)
|
1449
|
+
if(value === void 0){
|
1450
|
+
delete data.evaluator
|
1451
|
+
}
|
1452
|
+
data.handler(value, data.element, data)
|
1362
1453
|
} catch (e) {
|
1363
|
-
|
1454
|
+
log("warning:exception throwed in [avalon.injectBinding] " , e)
|
1364
1455
|
delete data.evaluator
|
1365
1456
|
var node = data.element
|
1366
1457
|
if (node.nodeType === 3) {
|
@@ -1368,126 +1459,160 @@ function registerSubscriber(data) {
|
|
1368
1459
|
if (kernel.commentInterpolate) {
|
1369
1460
|
parent.replaceChild(DOC.createComment(data.value), node)
|
1370
1461
|
} else {
|
1371
|
-
node.data = openTag + data.value + closeTag
|
1462
|
+
node.data = openTag + (data.oneTime ? "::" : "") + data.value + closeTag
|
1372
1463
|
}
|
1373
1464
|
}
|
1465
|
+
} finally {
|
1466
|
+
dependencyDetection.end()
|
1374
1467
|
}
|
1375
1468
|
}
|
1376
|
-
avalon.openComputedCollect = false
|
1377
|
-
delete Registry[expose]
|
1378
1469
|
}
|
1379
1470
|
|
1380
|
-
|
1381
|
-
|
1382
|
-
if (
|
1383
|
-
|
1471
|
+
//将依赖项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组
|
1472
|
+
function injectDependency(list, data) {
|
1473
|
+
if (data.oneTime)
|
1474
|
+
return
|
1475
|
+
if (list && avalon.Array.ensure(list, data) && data.element) {
|
1476
|
+
injectDisposeQueue(data, list)
|
1477
|
+
if (new Date() - beginTime > 444 ) {
|
1478
|
+
rejectDisposeQueue()
|
1479
|
+
}
|
1384
1480
|
}
|
1385
1481
|
}
|
1386
1482
|
|
1387
|
-
|
1388
|
-
function
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1483
|
+
//通知依赖于这个访问器的订阅者更新自身
|
1484
|
+
function fireDependencies(list) {
|
1485
|
+
if (list && list.length) {
|
1486
|
+
if (new Date() - beginTime > 444 && typeof list[0] === "object") {
|
1487
|
+
rejectDisposeQueue()
|
1488
|
+
}
|
1489
|
+
var args = aslice.call(arguments, 1)
|
1490
|
+
for (var i = list.length, fn; fn = list[--i]; ) {
|
1491
|
+
var el = fn.element
|
1492
|
+
if (el && el.parentNode) {
|
1493
|
+
try {
|
1494
|
+
var valueFn = fn.evaluator
|
1495
|
+
if (fn.$repeat) {
|
1496
|
+
fn.handler.apply(fn, args) //处理监控数组的方法
|
1497
|
+
}else if("$repeat" in fn || !valueFn ){//如果没有eval,先eval
|
1498
|
+
bindingHandlers[fn.type](fn, fn.vmodels)
|
1499
|
+
} else if (fn.type !== "on") { //事件绑定只能由用户触发,不能由程序触发
|
1500
|
+
var value = valueFn.apply(0, fn.args || [])
|
1501
|
+
fn.handler(value, el, fn)
|
1502
|
+
}
|
1503
|
+
} catch (e) {
|
1504
|
+
console.log(e)
|
1505
|
+
}
|
1506
|
+
}
|
1507
|
+
}
|
1399
1508
|
}
|
1400
1509
|
}
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1510
|
+
/*********************************************************************
|
1511
|
+
* 定时GC回收机制 *
|
1512
|
+
**********************************************************************/
|
1513
|
+
var disposeCount = 0
|
1514
|
+
var disposeQueue = avalon.$$subscribers = []
|
1515
|
+
var beginTime = new Date()
|
1516
|
+
var oldInfo = {}
|
1517
|
+
//var uuid2Node = {}
|
1518
|
+
function getUid(elem, makeID) { //IE9+,标准浏览器
|
1519
|
+
if (!elem.uuid && !makeID) {
|
1520
|
+
elem.uuid = ++disposeCount
|
1407
1521
|
}
|
1522
|
+
return elem.uuid
|
1408
1523
|
}
|
1409
1524
|
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1525
|
+
//添加到回收列队中
|
1526
|
+
function injectDisposeQueue(data, list) {
|
1527
|
+
var elem = data.element
|
1528
|
+
if (!data.uuid) {
|
1529
|
+
if (elem.nodeType !== 1) {
|
1530
|
+
data.uuid = data.type + (data.pos || 0) + "-" + getUid(elem.parentNode)
|
1531
|
+
} else {
|
1532
|
+
data.uuid = data.name + "-" + getUid(elem)
|
1414
1533
|
}
|
1415
|
-
} catch (e) {
|
1416
|
-
return true
|
1417
1534
|
}
|
1418
|
-
|
1419
|
-
|
1535
|
+
var lists = data.lists || (data.lists = [])
|
1536
|
+
avalon.Array.ensure(lists, list)
|
1537
|
+
list.$uuid = list.$uuid || generateID()
|
1538
|
+
if (!disposeQueue[data.uuid]) {
|
1539
|
+
disposeQueue[data.uuid] = 1
|
1540
|
+
disposeQueue.push(data)
|
1541
|
+
}
|
1420
1542
|
}
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
var i =
|
1543
|
+
|
1544
|
+
function rejectDisposeQueue(data) {
|
1545
|
+
if (avalon.optimize)
|
1546
|
+
return
|
1547
|
+
var i = disposeQueue.length
|
1426
1548
|
var n = i
|
1427
|
-
var
|
1428
|
-
var
|
1429
|
-
var types = []
|
1549
|
+
var allTypes = []
|
1550
|
+
var iffishTypes = {}
|
1430
1551
|
var newInfo = {}
|
1431
|
-
|
1432
|
-
while (
|
1433
|
-
var data = obj.data
|
1552
|
+
//对页面上所有绑定对象进行分门别类, 只检测个数发生变化的类型
|
1553
|
+
while (data = disposeQueue[--i]) {
|
1434
1554
|
var type = data.type
|
1435
1555
|
if (newInfo[type]) {
|
1436
1556
|
newInfo[type]++
|
1437
1557
|
} else {
|
1438
1558
|
newInfo[type] = 1
|
1439
|
-
|
1559
|
+
allTypes.push(type)
|
1440
1560
|
}
|
1441
1561
|
}
|
1442
1562
|
var diff = false
|
1443
|
-
|
1563
|
+
allTypes.forEach(function (type) {
|
1444
1564
|
if (oldInfo[type] !== newInfo[type]) {
|
1445
|
-
|
1565
|
+
iffishTypes[type] = 1
|
1446
1566
|
diff = true
|
1447
1567
|
}
|
1448
1568
|
})
|
1449
1569
|
i = n
|
1450
|
-
//avalon.log("需要检测的个数 " + i)
|
1451
1570
|
if (diff) {
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
if (data.element === void 0)
|
1571
|
+
while (data = disposeQueue[--i]) {
|
1572
|
+
if (data.element === null) {
|
1573
|
+
disposeQueue.splice(i, 1)
|
1456
1574
|
continue
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
delete
|
1461
|
-
|
1462
|
-
|
1575
|
+
}
|
1576
|
+
if (iffishTypes[data.type] && shouldDispose(data.element)) { //如果它没有在DOM树
|
1577
|
+
disposeQueue.splice(i, 1)
|
1578
|
+
delete disposeQueue[data.uuid]
|
1579
|
+
//delete uuid2Node[data.element.uuid]
|
1580
|
+
var lists = data.lists
|
1581
|
+
for (var k = 0, list; list = lists[k++]; ) {
|
1582
|
+
avalon.Array.remove(lists, list)
|
1583
|
+
avalon.Array.remove(list, data)
|
1584
|
+
}
|
1463
1585
|
disposeData(data)
|
1464
|
-
obj.data = obj.list = null
|
1465
1586
|
}
|
1466
1587
|
}
|
1467
1588
|
}
|
1468
1589
|
oldInfo = newInfo
|
1469
|
-
// avalon.log("已经移除的个数 " + k)
|
1470
1590
|
beginTime = new Date()
|
1471
1591
|
}
|
1472
1592
|
|
1473
|
-
function
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1593
|
+
function disposeData(data) {
|
1594
|
+
delete disposeQueue[data.uuid] // 先清除,不然无法回收了
|
1595
|
+
data.element = null
|
1596
|
+
data.rollback && data.rollback()
|
1597
|
+
for (var key in data) {
|
1598
|
+
data[key] = null
|
1599
|
+
}
|
1600
|
+
}
|
1601
|
+
|
1602
|
+
function shouldDispose(el) {
|
1603
|
+
try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错
|
1604
|
+
var fireError = el.parentNode.nodeType
|
1605
|
+
} catch (e) {
|
1606
|
+
return true
|
1607
|
+
}
|
1608
|
+
if (el.ifRemove) {
|
1609
|
+
// 如果节点被放到ifGroup,才移除
|
1610
|
+
if (!root.contains(el.ifRemove) && (ifGroup === el.parentNode)) {
|
1611
|
+
el.parentNode && el.parentNode.removeChild(el)
|
1612
|
+
return true
|
1489
1613
|
}
|
1490
1614
|
}
|
1615
|
+
return el.msRetain ? 0 : (el.nodeType === 1 ? !root.contains(el) : !avalon.contains(root, el))
|
1491
1616
|
}
|
1492
1617
|
|
1493
1618
|
/************************************************************************
|
@@ -1520,7 +1645,7 @@ var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "applicat
|
|
1520
1645
|
var script = DOC.createElement("script")
|
1521
1646
|
var rhtml = /<|&#?\w+;/
|
1522
1647
|
avalon.parseHTML = function(html) {
|
1523
|
-
var fragment =
|
1648
|
+
var fragment = avalonFragment.cloneNode(false)
|
1524
1649
|
if (typeof html !== "string" ) {
|
1525
1650
|
return fragment
|
1526
1651
|
}
|
@@ -1568,351 +1693,30 @@ avalon.clearHTML = function(node) {
|
|
1568
1693
|
}
|
1569
1694
|
|
1570
1695
|
/*********************************************************************
|
1571
|
-
*
|
1696
|
+
* avalon的原型方法定义区 *
|
1572
1697
|
**********************************************************************/
|
1573
1698
|
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
scanTag(elem, vmodels)
|
1699
|
+
function hyphen(target) {
|
1700
|
+
//转换为连字符线风格
|
1701
|
+
return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase()
|
1578
1702
|
}
|
1579
1703
|
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
if (currHTML === innerHTML) {
|
1588
|
-
callback()
|
1589
|
-
} else {
|
1590
|
-
checkScan(elem, callback, currHTML)
|
1591
|
-
}
|
1704
|
+
function camelize(target) {
|
1705
|
+
//转换为驼峰风格
|
1706
|
+
if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
|
1707
|
+
return target //提前判断,提高getStyle等的效率
|
1708
|
+
}
|
1709
|
+
return target.replace(/[-_][^-_]/g, function(match) {
|
1710
|
+
return match.charAt(1).toUpperCase()
|
1592
1711
|
})
|
1593
1712
|
}
|
1594
1713
|
|
1595
|
-
|
1596
|
-
function
|
1597
|
-
var id = elem.getAttribute("avalonctrl") || vmodel.$id
|
1598
|
-
elem.setAttribute("avalonctrl", id)
|
1599
|
-
vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]'
|
1600
|
-
}
|
1601
|
-
|
1602
|
-
var getBindingCallback = function(elem, name, vmodels) {
|
1603
|
-
var callback = elem.getAttribute(name)
|
1604
|
-
if (callback) {
|
1605
|
-
for (var i = 0, vm; vm = vmodels[i++]; ) {
|
1606
|
-
if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") {
|
1607
|
-
return vm[callback]
|
1608
|
-
}
|
1609
|
-
}
|
1610
|
-
}
|
1611
|
-
}
|
1612
|
-
|
1613
|
-
function executeBindings(bindings, vmodels) {
|
1614
|
-
for (var i = 0, data; data = bindings[i++]; ) {
|
1615
|
-
data.vmodels = vmodels
|
1616
|
-
bindingHandlers[data.type](data, vmodels)
|
1617
|
-
if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数据绑定,防止被二次解析
|
1618
|
-
//chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99
|
1619
|
-
data.element.removeAttribute(data.name)
|
1620
|
-
}
|
1621
|
-
}
|
1622
|
-
bindings.length = 0
|
1623
|
-
}
|
1624
|
-
|
1625
|
-
//https://github.com/RubyLouvre/avalon/issues/636
|
1626
|
-
var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) {
|
1627
|
-
var node = elem.firstChild, text
|
1628
|
-
while (node) {
|
1629
|
-
var aaa = node.nextSibling
|
1630
|
-
if (node.nodeType === 3) {
|
1631
|
-
if (text) {
|
1632
|
-
text.nodeValue += node.nodeValue
|
1633
|
-
elem.removeChild(node)
|
1634
|
-
} else {
|
1635
|
-
text = node
|
1636
|
-
}
|
1637
|
-
} else {
|
1638
|
-
text = null
|
1639
|
-
}
|
1640
|
-
node = aaa
|
1641
|
-
}
|
1642
|
-
} : 0
|
1643
|
-
|
1644
|
-
var rmsAttr = /ms-(\w+)-?(.*)/
|
1645
|
-
var priorityMap = {
|
1646
|
-
"if": 10,
|
1647
|
-
"repeat": 90,
|
1648
|
-
"data": 100,
|
1649
|
-
"widget": 110,
|
1650
|
-
"each": 1400,
|
1651
|
-
"with": 1500,
|
1652
|
-
"duplex": 2000,
|
1653
|
-
"on": 3000
|
1654
|
-
}
|
1655
|
-
|
1656
|
-
var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit")
|
1657
|
-
var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled")
|
1658
|
-
function bindingSorter(a, b) {
|
1659
|
-
return a.priority - b.priority
|
1660
|
-
}
|
1661
|
-
|
1662
|
-
function scanAttr(elem, vmodels) {
|
1663
|
-
//防止setAttribute, removeAttribute时 attributes自动被同步,导致for循环出错
|
1664
|
-
var attributes = elem.hasAttributes() ? avalon.slice(elem.attributes) : []
|
1665
|
-
var bindings = [],
|
1666
|
-
msData = createMap(),
|
1667
|
-
match
|
1668
|
-
for (var i = 0, attr; attr = attributes[i++]; ) {
|
1669
|
-
if (attr.specified) {
|
1670
|
-
if (match = attr.name.match(rmsAttr)) {
|
1671
|
-
//如果是以指定前缀命名的
|
1672
|
-
var type = match[1]
|
1673
|
-
var param = match[2] || ""
|
1674
|
-
var value = attr.value
|
1675
|
-
var name = attr.name
|
1676
|
-
msData[name] = value
|
1677
|
-
if (events[type]) {
|
1678
|
-
param = type
|
1679
|
-
type = "on"
|
1680
|
-
} else if (obsoleteAttrs[type]) {
|
1681
|
-
log("warning!请改用ms-attr-" + type + "代替ms-" + type + "!")
|
1682
|
-
if (type === "enabled") {//吃掉ms-enabled绑定,用ms-disabled代替
|
1683
|
-
log("warning!ms-enabled或ms-attr-enabled已经被废弃")
|
1684
|
-
type = "disabled"
|
1685
|
-
value = "!(" + value + ")"
|
1686
|
-
}
|
1687
|
-
param = type
|
1688
|
-
type = "attr"
|
1689
|
-
elem.removeAttribute(name)
|
1690
|
-
name = "ms-attr-" + param
|
1691
|
-
elem.setAttribute(name, value)
|
1692
|
-
match = [name]
|
1693
|
-
msData[name] = value
|
1694
|
-
}
|
1695
|
-
if (typeof bindingHandlers[type] === "function") {
|
1696
|
-
var binding = {
|
1697
|
-
type: type,
|
1698
|
-
param: param,
|
1699
|
-
element: elem,
|
1700
|
-
name: match[0],
|
1701
|
-
value: value,
|
1702
|
-
priority: type in priorityMap ? priorityMap[type] : type.charCodeAt(0) * 10 + (Number(param) || 0)
|
1703
|
-
}
|
1704
|
-
if (type === "html" || type === "text") {
|
1705
|
-
var token = getToken(value)
|
1706
|
-
avalon.mix(binding, token)
|
1707
|
-
binding.filters = binding.filters.replace(rhasHtml, function () {
|
1708
|
-
binding.type = "html"
|
1709
|
-
binding.group = 1
|
1710
|
-
return ""
|
1711
|
-
})// jshint ignore:line
|
1712
|
-
}
|
1713
|
-
if (name === "ms-if-loop") {
|
1714
|
-
binding.priority += 100
|
1715
|
-
}
|
1716
|
-
if (vmodels.length) {
|
1717
|
-
bindings.push(binding)
|
1718
|
-
if (type === "widget") {
|
1719
|
-
elem.msData = elem.msData || msData
|
1720
|
-
}
|
1721
|
-
}
|
1722
|
-
}
|
1723
|
-
}
|
1724
|
-
}
|
1725
|
-
}
|
1726
|
-
var control = elem.type
|
1727
|
-
if (control && msData["ms-duplex"]) {
|
1728
|
-
if (msData["ms-attr-checked"] && /radio|checkbox/.test(control)) {
|
1729
|
-
log("warning!" + control + "控件不能同时定义ms-attr-checked与ms-duplex")
|
1730
|
-
}
|
1731
|
-
if (msData["ms-attr-value"] && /text|password/.test(control)) {
|
1732
|
-
log("warning!" + control + "控件不能同时定义ms-attr-value与ms-duplex")
|
1733
|
-
}
|
1734
|
-
}
|
1735
|
-
bindings.sort(bindingSorter)
|
1736
|
-
var scanNode = true
|
1737
|
-
for (i = 0; binding = bindings[i]; i++) {
|
1738
|
-
type = binding.type
|
1739
|
-
if (rnoscanAttrBinding.test(type)) {
|
1740
|
-
return executeBindings(bindings.slice(0, i + 1), vmodels)
|
1741
|
-
} else if (scanNode) {
|
1742
|
-
scanNode = !rnoscanNodeBinding.test(type)
|
1743
|
-
}
|
1744
|
-
}
|
1745
|
-
executeBindings(bindings, vmodels)
|
1746
|
-
if (scanNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML + elem.textContent)) {
|
1747
|
-
mergeTextNodes && mergeTextNodes(elem)
|
1748
|
-
scanNodeList(elem, vmodels) //扫描子孙元素
|
1749
|
-
}
|
1750
|
-
}
|
1751
|
-
|
1752
|
-
var rnoscanAttrBinding = /^if|widget|repeat$/
|
1753
|
-
var rnoscanNodeBinding = /^each|with|html|include$/
|
1754
|
-
function scanNodeList(parent, vmodels) {
|
1755
|
-
var node = parent.firstChild
|
1756
|
-
while (node) {
|
1757
|
-
var nextNode = node.nextSibling
|
1758
|
-
scanNode(node, node.nodeType, vmodels)
|
1759
|
-
node = nextNode
|
1760
|
-
}
|
1761
|
-
}
|
1762
|
-
|
1763
|
-
function scanNodeArray(nodes, vmodels) {
|
1764
|
-
for (var i = 0, node; node = nodes[i++]; ) {
|
1765
|
-
scanNode(node, node.nodeType, vmodels)
|
1766
|
-
}
|
1767
|
-
}
|
1768
|
-
function scanNode(node, nodeType, vmodels) {
|
1769
|
-
if (nodeType === 1) {
|
1770
|
-
scanTag(node, vmodels) //扫描元素节点
|
1771
|
-
} else if (nodeType === 3 && rexpr.test(node.data)){
|
1772
|
-
scanText(node, vmodels) //扫描文本节点
|
1773
|
-
} else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) {
|
1774
|
-
scanText(node, vmodels) //扫描注释节点
|
1775
|
-
}
|
1776
|
-
}
|
1777
|
-
function scanTag(elem, vmodels, node) {
|
1778
|
-
//扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
|
1779
|
-
//--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
|
1780
|
-
var a = elem.getAttribute("ms-skip")
|
1781
|
-
var b = elem.getAttributeNode("ms-important")
|
1782
|
-
var c = elem.getAttributeNode("ms-controller")
|
1783
|
-
if (typeof a === "string") {
|
1784
|
-
return
|
1785
|
-
} else if (node = b || c) {
|
1786
|
-
var newVmodel = avalon.vmodels[node.value]
|
1787
|
-
if (!newVmodel) {
|
1788
|
-
return
|
1789
|
-
}
|
1790
|
-
//ms-important不包含父VM,ms-controller相反
|
1791
|
-
vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
|
1792
|
-
elem.removeAttribute(node.name) //removeAttributeNode不会刷新[ms-controller]样式规则
|
1793
|
-
elem.classList.remove(node.name)
|
1794
|
-
createSignalTower(elem, newVmodel)
|
1795
|
-
}
|
1796
|
-
scanAttr(elem, vmodels) //扫描特性节点
|
1797
|
-
}
|
1798
|
-
var rhasHtml = /\|\s*html\s*/,
|
1799
|
-
r11a = /\|\|/g,
|
1800
|
-
rlt = /</g,
|
1801
|
-
rgt = />/g
|
1802
|
-
rstringLiteral = /(['"])(\\\1|.)+?\1/g
|
1803
|
-
function getToken(value) {
|
1804
|
-
if (value.indexOf("|") > 0) {
|
1805
|
-
var scapegoat = value.replace( rstringLiteral, function(_){
|
1806
|
-
return Array(_.length+1).join("1")// jshint ignore:line
|
1807
|
-
})
|
1808
|
-
var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
|
1809
|
-
if (index > -1) {
|
1810
|
-
return {
|
1811
|
-
filters: value.slice(index),
|
1812
|
-
value: value.slice(0, index),
|
1813
|
-
expr: true
|
1814
|
-
}
|
1815
|
-
}
|
1816
|
-
}
|
1817
|
-
return {
|
1818
|
-
value: value,
|
1819
|
-
filters: "",
|
1820
|
-
expr: true
|
1821
|
-
}
|
1822
|
-
}
|
1823
|
-
|
1824
|
-
function scanExpr(str) {
|
1825
|
-
var tokens = [],
|
1826
|
-
value, start = 0,
|
1827
|
-
stop
|
1828
|
-
do {
|
1829
|
-
stop = str.indexOf(openTag, start)
|
1830
|
-
if (stop === -1) {
|
1831
|
-
break
|
1832
|
-
}
|
1833
|
-
value = str.slice(start, stop)
|
1834
|
-
if (value) { // {{ 左边的文本
|
1835
|
-
tokens.push({
|
1836
|
-
value: value,
|
1837
|
-
filters: "",
|
1838
|
-
expr: false
|
1839
|
-
})
|
1840
|
-
}
|
1841
|
-
start = stop + openTag.length
|
1842
|
-
stop = str.indexOf(closeTag, start)
|
1843
|
-
if (stop === -1) {
|
1844
|
-
break
|
1845
|
-
}
|
1846
|
-
value = str.slice(start, stop)
|
1847
|
-
if (value) { //处理{{ }}插值表达式
|
1848
|
-
tokens.push(getToken(value))
|
1849
|
-
}
|
1850
|
-
start = stop + closeTag.length
|
1851
|
-
} while (1)
|
1852
|
-
value = str.slice(start)
|
1853
|
-
if (value) { //}} 右边的文本
|
1854
|
-
tokens.push({
|
1855
|
-
value: value,
|
1856
|
-
expr: false,
|
1857
|
-
filters: ""
|
1858
|
-
})
|
1859
|
-
}
|
1860
|
-
return tokens
|
1861
|
-
}
|
1862
|
-
|
1863
|
-
function scanText(textNode, vmodels) {
|
1864
|
-
var bindings = []
|
1865
|
-
if (textNode.nodeType === 8) {
|
1866
|
-
var token = getToken(textNode.nodeValue)
|
1867
|
-
var tokens = [token]
|
1868
|
-
} else {
|
1869
|
-
tokens = scanExpr(textNode.data)
|
1870
|
-
}
|
1871
|
-
if (tokens.length) {
|
1872
|
-
for (var i = 0; token = tokens[i++]; ) {
|
1873
|
-
var node = DOC.createTextNode(token.value) //将文本转换为文本节点,并替换原来的文本节点
|
1874
|
-
if (token.expr) {
|
1875
|
-
token.type = "text"
|
1876
|
-
token.element = node
|
1877
|
-
token.filters = token.filters.replace(rhasHtml, function() {
|
1878
|
-
token.type = "html"
|
1879
|
-
token.group = 1
|
1880
|
-
return ""
|
1881
|
-
})// jshint ignore:line
|
1882
|
-
bindings.push(token) //收集带有插值表达式的文本
|
1883
|
-
}
|
1884
|
-
hyperspace.appendChild(node)
|
1885
|
-
}
|
1886
|
-
textNode.parentNode.replaceChild(hyperspace, textNode)
|
1887
|
-
if (bindings.length)
|
1888
|
-
executeBindings(bindings, vmodels)
|
1889
|
-
}
|
1890
|
-
}
|
1891
|
-
|
1892
|
-
|
1893
|
-
/*********************************************************************
|
1894
|
-
* avalon的原型方法定义区 *
|
1895
|
-
**********************************************************************/
|
1896
|
-
function hyphen(target) {
|
1897
|
-
//转换为连字符线风格
|
1898
|
-
return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase()
|
1899
|
-
}
|
1900
|
-
function camelize(target) {
|
1901
|
-
//转换为驼峰风格
|
1902
|
-
if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
|
1903
|
-
return target //提前判断,提高getStyle等的效率
|
1904
|
-
}
|
1905
|
-
return target.replace(/[-_][^-_]/g, function (match) {
|
1906
|
-
return match.charAt(1).toUpperCase()
|
1907
|
-
})
|
1908
|
-
}
|
1909
|
-
|
1910
|
-
"add,remove".replace(rword, function (method) {
|
1911
|
-
avalon.fn[method + "Class"] = function (cls) {
|
1714
|
+
"add,remove".replace(rword, function(method) {
|
1715
|
+
avalon.fn[method + "Class"] = function(cls) {
|
1912
1716
|
var el = this[0]
|
1913
1717
|
//https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
|
1914
1718
|
if (cls && typeof cls === "string" && el && el.nodeType === 1) {
|
1915
|
-
cls.replace(/\S+/g, function
|
1719
|
+
cls.replace(/\S+/g, function(c) {
|
1916
1720
|
el.classList[method](c)
|
1917
1721
|
})
|
1918
1722
|
}
|
@@ -1921,13 +1725,13 @@ function camelize(target) {
|
|
1921
1725
|
})
|
1922
1726
|
|
1923
1727
|
avalon.fn.mix({
|
1924
|
-
hasClass: function
|
1728
|
+
hasClass: function(cls) {
|
1925
1729
|
var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0
|
1926
1730
|
return el.nodeType === 1 && el.classList.contains(cls)
|
1927
1731
|
},
|
1928
|
-
toggleClass: function
|
1732
|
+
toggleClass: function(value, stateVal) {
|
1929
1733
|
var className, i = 0
|
1930
|
-
var classNames = value.split(/\s+/)
|
1734
|
+
var classNames = String(value).split(/\s+/)
|
1931
1735
|
var isBool = typeof stateVal === "boolean"
|
1932
1736
|
while ((className = classNames[i++])) {
|
1933
1737
|
var state = isBool ? stateVal : !this.hasClass(className)
|
@@ -1935,7 +1739,7 @@ avalon.fn.mix({
|
|
1935
1739
|
}
|
1936
1740
|
return this
|
1937
1741
|
},
|
1938
|
-
attr: function
|
1742
|
+
attr: function(name, value) {
|
1939
1743
|
if (arguments.length === 2) {
|
1940
1744
|
this[0].setAttribute(name, value)
|
1941
1745
|
return this
|
@@ -1943,7 +1747,7 @@ avalon.fn.mix({
|
|
1943
1747
|
return this[0].getAttribute(name)
|
1944
1748
|
}
|
1945
1749
|
},
|
1946
|
-
data: function
|
1750
|
+
data: function(name, value) {
|
1947
1751
|
name = "data-" + hyphen(name || "")
|
1948
1752
|
switch (arguments.length) {
|
1949
1753
|
case 2:
|
@@ -1954,7 +1758,7 @@ avalon.fn.mix({
|
|
1954
1758
|
return parseData(val)
|
1955
1759
|
case 0:
|
1956
1760
|
var ret = {}
|
1957
|
-
ap.forEach.call(this[0].attributes, function
|
1761
|
+
ap.forEach.call(this[0].attributes, function(attr) {
|
1958
1762
|
if (attr) {
|
1959
1763
|
name = attr.name
|
1960
1764
|
if (!name.indexOf("data-")) {
|
@@ -1966,12 +1770,12 @@ avalon.fn.mix({
|
|
1966
1770
|
return ret
|
1967
1771
|
}
|
1968
1772
|
},
|
1969
|
-
removeData: function
|
1773
|
+
removeData: function(name) {
|
1970
1774
|
name = "data-" + hyphen(name)
|
1971
1775
|
this[0].removeAttribute(name)
|
1972
1776
|
return this
|
1973
1777
|
},
|
1974
|
-
css: function
|
1778
|
+
css: function(name, value) {
|
1975
1779
|
if (avalon.isPlainObject(name)) {
|
1976
1780
|
for (var i in name) {
|
1977
1781
|
avalon.css(this, i, name[i])
|
@@ -1981,13 +1785,13 @@ avalon.fn.mix({
|
|
1981
1785
|
}
|
1982
1786
|
return ret !== void 0 ? ret : this
|
1983
1787
|
},
|
1984
|
-
position: function
|
1788
|
+
position: function() {
|
1985
1789
|
var offsetParent, offset,
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1790
|
+
elem = this[0],
|
1791
|
+
parentOffset = {
|
1792
|
+
top: 0,
|
1793
|
+
left: 0
|
1794
|
+
};
|
1991
1795
|
if (!elem) {
|
1992
1796
|
return
|
1993
1797
|
}
|
@@ -2001,31 +1805,34 @@ avalon.fn.mix({
|
|
2001
1805
|
}
|
2002
1806
|
parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true)
|
2003
1807
|
parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true)
|
1808
|
+
// Subtract offsetParent scroll positions
|
1809
|
+
parentOffset.top -= offsetParent.scrollTop()
|
1810
|
+
parentOffset.left -= offsetParent.scrollLeft()
|
2004
1811
|
}
|
2005
1812
|
return {
|
2006
1813
|
top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true),
|
2007
1814
|
left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true)
|
2008
1815
|
}
|
2009
1816
|
},
|
2010
|
-
offsetParent: function
|
1817
|
+
offsetParent: function() {
|
2011
1818
|
var offsetParent = this[0].offsetParent
|
2012
1819
|
while (offsetParent && avalon.css(offsetParent, "position") === "static") {
|
2013
1820
|
offsetParent = offsetParent.offsetParent;
|
2014
1821
|
}
|
2015
1822
|
return avalon(offsetParent || root)
|
2016
1823
|
},
|
2017
|
-
bind: function
|
1824
|
+
bind: function(type, fn, phase) {
|
2018
1825
|
if (this[0]) { //此方法不会链
|
2019
1826
|
return avalon.bind(this[0], type, fn, phase)
|
2020
1827
|
}
|
2021
1828
|
},
|
2022
|
-
unbind: function
|
1829
|
+
unbind: function(type, fn, phase) {
|
2023
1830
|
if (this[0]) {
|
2024
1831
|
avalon.unbind(this[0], type, fn, phase)
|
2025
1832
|
}
|
2026
1833
|
return this
|
2027
1834
|
},
|
2028
|
-
val: function
|
1835
|
+
val: function(value) {
|
2029
1836
|
var node = this[0]
|
2030
1837
|
if (node && node.nodeType === 1) {
|
2031
1838
|
var get = arguments.length === 0
|
@@ -2044,7 +1851,8 @@ avalon.fn.mix({
|
|
2044
1851
|
})
|
2045
1852
|
|
2046
1853
|
if (root.dataset) {
|
2047
|
-
avalon.fn.data = function
|
1854
|
+
avalon.fn.data = function(name, val) {
|
1855
|
+
name = name && camelize(name)
|
2048
1856
|
var dataset = this[0].dataset
|
2049
1857
|
switch (arguments.length) {
|
2050
1858
|
case 2:
|
@@ -2070,19 +1878,18 @@ function parseData(data) {
|
|
2070
1878
|
if (typeof data === "object")
|
2071
1879
|
return data
|
2072
1880
|
data = data === "true" ? true :
|
2073
|
-
|
2074
|
-
|
2075
|
-
} catch (e) {
|
2076
|
-
}
|
1881
|
+
data === "false" ? false :
|
1882
|
+
data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data
|
1883
|
+
} catch (e) {}
|
2077
1884
|
return data
|
2078
1885
|
}
|
2079
1886
|
avalon.each({
|
2080
1887
|
scrollLeft: "pageXOffset",
|
2081
1888
|
scrollTop: "pageYOffset"
|
2082
|
-
}, function
|
2083
|
-
avalon.fn[method] = function
|
1889
|
+
}, function(method, prop) {
|
1890
|
+
avalon.fn[method] = function(val) {
|
2084
1891
|
var node = this[0] || {}, win = getWindow(node),
|
2085
|
-
|
1892
|
+
top = method === "scrollTop"
|
2086
1893
|
if (!arguments.length) {
|
2087
1894
|
return win ? win[prop] : node[method]
|
2088
1895
|
} else {
|
@@ -2101,13 +1908,13 @@ function getWindow(node) {
|
|
2101
1908
|
|
2102
1909
|
//=============================css相关==================================
|
2103
1910
|
var cssHooks = avalon.cssHooks = createMap()
|
2104
|
-
var prefixes = ["", "-webkit-", "-moz-", "-ms-"]//去掉opera-15的支持
|
1911
|
+
var prefixes = ["", "-webkit-", "-moz-", "-ms-"] //去掉opera-15的支持
|
2105
1912
|
var cssMap = {
|
2106
1913
|
"float": "cssFloat"
|
2107
1914
|
}
|
2108
|
-
avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
|
1915
|
+
avalon.cssNumber = oneObject("animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
|
2109
1916
|
|
2110
|
-
avalon.cssName = function
|
1917
|
+
avalon.cssName = function(name, host, camelCase) {
|
2111
1918
|
if (cssMap[name]) {
|
2112
1919
|
return cssMap[name]
|
2113
1920
|
}
|
@@ -2120,33 +1927,33 @@ avalon.cssName = function (name, host, camelCase) {
|
|
2120
1927
|
}
|
2121
1928
|
return null
|
2122
1929
|
}
|
2123
|
-
cssHooks["@:set"] = function
|
1930
|
+
cssHooks["@:set"] = function(node, name, value) {
|
2124
1931
|
node.style[name] = value
|
2125
1932
|
}
|
2126
1933
|
|
2127
|
-
cssHooks["@:get"] = function
|
1934
|
+
cssHooks["@:get"] = function(node, name) {
|
2128
1935
|
if (!node || !node.style) {
|
2129
1936
|
throw new Error("getComputedStyle要求传入一个节点 " + node)
|
2130
1937
|
}
|
2131
1938
|
var ret, computed = getComputedStyle(node)
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
1939
|
+
if (computed) {
|
1940
|
+
ret = name === "filter" ? computed.getPropertyValue(name) : computed[name]
|
1941
|
+
if (ret === "") {
|
1942
|
+
ret = node.style[name] //其他浏览器需要我们手动取内联样式
|
1943
|
+
}
|
2136
1944
|
}
|
2137
|
-
}
|
2138
1945
|
return ret
|
2139
1946
|
}
|
2140
|
-
cssHooks["opacity:get"] = function
|
1947
|
+
cssHooks["opacity:get"] = function(node) {
|
2141
1948
|
var ret = cssHooks["@:get"](node, "opacity")
|
2142
1949
|
return ret === "" ? "1" : ret
|
2143
1950
|
}
|
2144
1951
|
|
2145
|
-
"top,left".replace(rword, function
|
2146
|
-
cssHooks[name + ":get"] = function
|
1952
|
+
"top,left".replace(rword, function(name) {
|
1953
|
+
cssHooks[name + ":get"] = function(node) {
|
2147
1954
|
var computed = cssHooks["@:get"](node, name)
|
2148
1955
|
return /px$/.test(computed) ? computed :
|
2149
|
-
|
1956
|
+
avalon(node).position()[name] + "px"
|
2150
1957
|
}
|
2151
1958
|
})
|
2152
1959
|
var cssShow = {
|
@@ -2156,125 +1963,125 @@ var cssShow = {
|
|
2156
1963
|
}
|
2157
1964
|
var rdisplayswap = /^(none|table(?!-c[ea]).+)/
|
2158
1965
|
|
2159
|
-
function showHidden(node, array) {
|
2160
|
-
|
2161
|
-
|
2162
|
-
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
1966
|
+
function showHidden(node, array) {
|
1967
|
+
//http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
|
1968
|
+
if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
|
1969
|
+
var styles = getComputedStyle(node, null)
|
1970
|
+
if (rdisplayswap.test(styles["display"])) {
|
1971
|
+
var obj = {
|
1972
|
+
node: node
|
1973
|
+
}
|
1974
|
+
for (var name in cssShow) {
|
1975
|
+
obj[name] = styles[name]
|
1976
|
+
node.style[name] = cssShow[name]
|
1977
|
+
}
|
1978
|
+
array.push(obj)
|
2166
1979
|
}
|
2167
|
-
|
2168
|
-
|
2169
|
-
|
1980
|
+
var parent = node.parentNode
|
1981
|
+
if (parent && parent.nodeType === 1) {
|
1982
|
+
showHidden(parent, array)
|
2170
1983
|
}
|
2171
|
-
array.push(obj)
|
2172
|
-
}
|
2173
|
-
var parent = node.parentNode
|
2174
|
-
if (parent && parent.nodeType === 1) {
|
2175
|
-
showHidden(parent, array)
|
2176
1984
|
}
|
2177
1985
|
}
|
2178
|
-
}
|
2179
1986
|
|
2180
|
-
"Width,Height".replace(rword, function
|
2181
|
-
|
1987
|
+
"Width,Height".replace(rword, function(name) { //fix 481
|
1988
|
+
var method = name.toLowerCase(),
|
2182
1989
|
clientProp = "client" + name,
|
2183
1990
|
scrollProp = "scroll" + name,
|
2184
1991
|
offsetProp = "offset" + name
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2199
|
-
|
1992
|
+
cssHooks[method + ":get"] = function(node, which, override) {
|
1993
|
+
var boxSizing = -4
|
1994
|
+
if (typeof override === "number") {
|
1995
|
+
boxSizing = override
|
1996
|
+
}
|
1997
|
+
which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
|
1998
|
+
var ret = node[offsetProp] // border-box 0
|
1999
|
+
if (boxSizing === 2) { // margin-box 2
|
2000
|
+
return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true)
|
2001
|
+
}
|
2002
|
+
if (boxSizing < 0) { // padding-box -2
|
2003
|
+
ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true)
|
2004
|
+
}
|
2005
|
+
if (boxSizing === -4) { // content-box -4
|
2006
|
+
ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true)
|
2007
|
+
}
|
2008
|
+
return ret
|
2009
|
+
}
|
2010
|
+
cssHooks[method + "&get"] = function(node) {
|
2011
|
+
var hidden = [];
|
2012
|
+
showHidden(node, hidden);
|
2013
|
+
var val = cssHooks[method + ":get"](node)
|
2014
|
+
for (var i = 0, obj; obj = hidden[i++];) {
|
2015
|
+
node = obj.node
|
2016
|
+
for (var n in obj) {
|
2017
|
+
if (typeof obj[n] === "string") {
|
2018
|
+
node.style[n] = obj[n]
|
2019
|
+
}
|
2020
|
+
}
|
2021
|
+
}
|
2022
|
+
return val;
|
2200
2023
|
}
|
2201
|
-
|
2202
|
-
|
2203
|
-
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2024
|
+
avalon.fn[method] = function(value) { //会忽视其display
|
2025
|
+
var node = this[0]
|
2026
|
+
if (arguments.length === 0) {
|
2027
|
+
if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
|
2028
|
+
return node["inner" + name]
|
2029
|
+
}
|
2030
|
+
if (node.nodeType === 9) { //取得页面尺寸
|
2031
|
+
var doc = node.documentElement
|
2032
|
+
//FF chrome html.scrollHeight< body.scrollHeight
|
2033
|
+
//IE 标准模式 : html.scrollHeight> body.scrollHeight
|
2034
|
+
//IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
|
2035
|
+
return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
|
2212
2036
|
}
|
2037
|
+
return cssHooks[method + "&get"](node)
|
2038
|
+
} else {
|
2039
|
+
return this.css(method, value)
|
2213
2040
|
}
|
2214
2041
|
}
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2042
|
+
avalon.fn["inner" + name] = function() {
|
2043
|
+
return cssHooks[method + ":get"](this[0], void 0, -2)
|
2044
|
+
}
|
2045
|
+
avalon.fn["outer" + name] = function(includeMargin) {
|
2046
|
+
return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
|
2047
|
+
}
|
2048
|
+
})
|
2049
|
+
avalon.fn.offset = function() { //取得距离页面左右角的坐标
|
2218
2050
|
var node = this[0]
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
if (
|
2224
|
-
var doc = node.
|
2225
|
-
|
2226
|
-
|
2227
|
-
|
2228
|
-
|
2051
|
+
try {
|
2052
|
+
var rect = node.getBoundingClientRect()
|
2053
|
+
// Make sure element is not hidden (display: none) or disconnected
|
2054
|
+
// https://github.com/jquery/jquery/pull/2043/files#r23981494
|
2055
|
+
if (rect.width || rect.height || node.getClientRects().length) {
|
2056
|
+
var doc = node.ownerDocument
|
2057
|
+
var root = doc.documentElement
|
2058
|
+
var win = doc.defaultView
|
2059
|
+
return {
|
2060
|
+
top: rect.top + win.pageYOffset - root.clientTop,
|
2061
|
+
left: rect.left + win.pageXOffset - root.clientLeft
|
2062
|
+
}
|
2229
2063
|
}
|
2230
|
-
|
2231
|
-
} else {
|
2232
|
-
return this.css(method, value)
|
2233
|
-
}
|
2234
|
-
}
|
2235
|
-
avalon.fn["inner" + name] = function () {
|
2236
|
-
return cssHooks[method + ":get"](this[0], void 0, -2)
|
2237
|
-
}
|
2238
|
-
avalon.fn["outer" + name] = function (includeMargin) {
|
2239
|
-
return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
|
2240
|
-
}
|
2241
|
-
})
|
2242
|
-
avalon.fn.offset = function () { //取得距离页面左右角的坐标
|
2243
|
-
var node = this[0]
|
2244
|
-
try {
|
2245
|
-
var rect = node.getBoundingClientRect()
|
2246
|
-
// Make sure element is not hidden (display: none) or disconnected
|
2247
|
-
// https://github.com/jquery/jquery/pull/2043/files#r23981494
|
2248
|
-
if (rect.width || rect.height || node.getClientRects().length) {
|
2249
|
-
var doc = node.ownerDocument
|
2250
|
-
var root = doc.documentElement
|
2251
|
-
var win = doc.defaultView
|
2064
|
+
} catch (e) {
|
2252
2065
|
return {
|
2253
|
-
|
2254
|
-
|
2066
|
+
left: 0,
|
2067
|
+
top: 0
|
2255
2068
|
}
|
2256
2069
|
}
|
2257
|
-
} catch (e) {
|
2258
|
-
return {
|
2259
|
-
left: 0,
|
2260
|
-
top: 0
|
2261
|
-
}
|
2262
2070
|
}
|
2263
|
-
|
2264
|
-
//=============================val相关=======================
|
2071
|
+
//=============================val相关=======================
|
2265
2072
|
|
2266
|
-
function getValType(
|
2267
|
-
|
2268
|
-
|
2269
|
-
}
|
2073
|
+
function getValType(elem) {
|
2074
|
+
var ret = elem.tagName.toLowerCase()
|
2075
|
+
return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret
|
2076
|
+
}
|
2270
2077
|
var valHooks = {
|
2271
|
-
"select:get": function
|
2078
|
+
"select:get": function(node, value) {
|
2272
2079
|
var option, options = node.options,
|
2273
|
-
|
2274
|
-
|
2275
|
-
|
2276
|
-
|
2277
|
-
|
2080
|
+
index = node.selectedIndex,
|
2081
|
+
one = node.type === "select-one" || index < 0,
|
2082
|
+
values = one ? null : [],
|
2083
|
+
max = one ? index + 1 : options.length,
|
2084
|
+
i = index < 0 ? max : one ? index : 0
|
2278
2085
|
for (; i < max; i++) {
|
2279
2086
|
option = options[i]
|
2280
2087
|
//旧式IE在reset后不会改变selected,需要改用i === index判定
|
@@ -2291,9 +2098,9 @@ var valHooks = {
|
|
2291
2098
|
}
|
2292
2099
|
return values
|
2293
2100
|
},
|
2294
|
-
"select:set": function
|
2101
|
+
"select:set": function(node, values, optionSet) {
|
2295
2102
|
values = [].concat(values) //强制转换为数组
|
2296
|
-
for (var i = 0, el; el = node.options[i++];
|
2103
|
+
for (var i = 0, el; el = node.options[i++];) {
|
2297
2104
|
if ((el.selected = values.indexOf(el.value) > -1)) {
|
2298
2105
|
optionSet = true
|
2299
2106
|
}
|
@@ -2303,7 +2110,6 @@ var valHooks = {
|
|
2303
2110
|
}
|
2304
2111
|
}
|
2305
2112
|
}
|
2306
|
-
|
2307
2113
|
/*********************************************************************
|
2308
2114
|
* 编译系统 *
|
2309
2115
|
**********************************************************************/
|
@@ -2323,10 +2129,10 @@ var rsplit = /[^\w$]+/g
|
|
2323
2129
|
var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g')
|
2324
2130
|
var rnumber = /\b\d[^,]*/g
|
2325
2131
|
var rcomma = /^,+|,+$/g
|
2326
|
-
var
|
2132
|
+
var variablePool = new Cache(512)
|
2327
2133
|
var getVariables = function (code) {
|
2328
2134
|
var key = "," + code.trim()
|
2329
|
-
var ret =
|
2135
|
+
var ret = variablePool.get(key)
|
2330
2136
|
if (ret) {
|
2331
2137
|
return ret
|
2332
2138
|
}
|
@@ -2337,7 +2143,7 @@ var getVariables = function (code) {
|
|
2337
2143
|
.replace(rnumber, "")
|
2338
2144
|
.replace(rcomma, "")
|
2339
2145
|
.split(/^$|,+/)
|
2340
|
-
return
|
2146
|
+
return variablePool.put(key, uniqSet(match))
|
2341
2147
|
}
|
2342
2148
|
/*添加赋值语句*/
|
2343
2149
|
|
@@ -2370,7 +2176,7 @@ function uniqSet(array) {
|
|
2370
2176
|
return ret
|
2371
2177
|
}
|
2372
2178
|
//缓存求值函数,以便多次利用
|
2373
|
-
var
|
2179
|
+
var evaluatorPool = new Cache(128)
|
2374
2180
|
//取得求值函数及其传参
|
2375
2181
|
var rduplex = /\w\[.*\]|\w\.\w/
|
2376
2182
|
var rproxy = /(\$proxy\$[a-z]+)\d+$/
|
@@ -2394,142 +2200,496 @@ function parseFilter(val, filters) {
|
|
2394
2200
|
.replace(rthimLeftParentheses, function () {
|
2395
2201
|
return '",'
|
2396
2202
|
}) + "]"
|
2397
|
-
return "return
|
2203
|
+
return "return this.filters.$filter(" + val + ", " + filters + ")"
|
2204
|
+
}
|
2205
|
+
|
2206
|
+
function parseExpr(code, scopes, data) {
|
2207
|
+
var dataType = data.type
|
2208
|
+
var filters = data.filters || ""
|
2209
|
+
var exprId = scopes.map(function (el) {
|
2210
|
+
return String(el.$id).replace(rproxy, "$1")
|
2211
|
+
}) + code + dataType + filters
|
2212
|
+
var vars = getVariables(code).concat(),
|
2213
|
+
assigns = [],
|
2214
|
+
names = [],
|
2215
|
+
args = [],
|
2216
|
+
prefix = ""
|
2217
|
+
//args 是一个对象数组, names 是将要生成的求值函数的参数
|
2218
|
+
scopes = uniqSet(scopes)
|
2219
|
+
data.vars = []
|
2220
|
+
for (var i = 0, sn = scopes.length; i < sn; i++) {
|
2221
|
+
if (vars.length) {
|
2222
|
+
var name = "vm" + expose + "_" + i
|
2223
|
+
names.push(name)
|
2224
|
+
args.push(scopes[i])
|
2225
|
+
assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data))
|
2226
|
+
}
|
2227
|
+
}
|
2228
|
+
if (!assigns.length && dataType === "duplex") {
|
2229
|
+
return
|
2230
|
+
}
|
2231
|
+
if (dataType !== "duplex" && (code.indexOf("||") > -1 || code.indexOf("&&") > -1)) {
|
2232
|
+
//https://github.com/RubyLouvre/avalon/issues/583
|
2233
|
+
data.vars.forEach(function (v) {
|
2234
|
+
var reg = new RegExp("\\b" + v + "(?:\\.\\w+|\\[\\w+\\])+", "ig")
|
2235
|
+
code = code.replace(reg, function (_, cap) {
|
2236
|
+
var c = _.charAt(v.length)
|
2237
|
+
//var r = IEVersion ? code.slice(arguments[1] + _.length) : RegExp.rightContext
|
2238
|
+
//https://github.com/RubyLouvre/avalon/issues/966
|
2239
|
+
var r = code.slice(cap + _.length)
|
2240
|
+
var method = /^\s*\(/.test(r)
|
2241
|
+
if (c === "." || c === "[" || method) {//比如v为aa,我们只匹配aa.bb,aa[cc],不匹配aaa.xxx
|
2242
|
+
var name = "var" + String(Math.random()).replace(/^0\./, "")
|
2243
|
+
if (method) {//array.size()
|
2244
|
+
var array = _.split(".")
|
2245
|
+
if (array.length > 2) {
|
2246
|
+
var last = array.pop()
|
2247
|
+
assigns.push(name + " = " + array.join("."))
|
2248
|
+
return name + "." + last
|
2249
|
+
} else {
|
2250
|
+
return _
|
2251
|
+
}
|
2252
|
+
}
|
2253
|
+
assigns.push(name + " = " + _)
|
2254
|
+
return name
|
2255
|
+
} else {
|
2256
|
+
return _
|
2257
|
+
}
|
2258
|
+
})
|
2259
|
+
})
|
2260
|
+
}
|
2261
|
+
//---------------args----------------
|
2262
|
+
data.args = args
|
2263
|
+
//---------------cache----------------
|
2264
|
+
delete data.vars
|
2265
|
+
var fn = evaluatorPool.get(exprId) //直接从缓存,免得重复生成
|
2266
|
+
if (fn) {
|
2267
|
+
data.evaluator = fn
|
2268
|
+
return
|
2269
|
+
}
|
2270
|
+
prefix = assigns.join(", ")
|
2271
|
+
if (prefix) {
|
2272
|
+
prefix = "var " + prefix
|
2273
|
+
}
|
2274
|
+
if (/\S/.test(filters)) { //文本绑定,双工绑定才有过滤器
|
2275
|
+
if (!/text|html/.test(data.type)) {
|
2276
|
+
throw Error("ms-" + data.type + "不支持过滤器")
|
2277
|
+
}
|
2278
|
+
code = "\nvar ret" + expose + " = " + code + ";\r\n"
|
2279
|
+
code += parseFilter("ret" + expose, filters)
|
2280
|
+
try {
|
2281
|
+
fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code))
|
2282
|
+
data.evaluator = evaluatorPool.put(exprId, function() {
|
2283
|
+
return fn.apply(avalon, arguments)//确保可以在编译代码中使用this获取avalon对象
|
2284
|
+
})
|
2285
|
+
} catch (e) {
|
2286
|
+
log("debug: parse error," + e.message)
|
2287
|
+
}
|
2288
|
+
vars = assigns = names = null //释放内存
|
2289
|
+
return
|
2290
|
+
} else if (dataType === "duplex") { //双工绑定
|
2291
|
+
var _body = "'use strict';\nreturn function(vvv){\n\t" +
|
2292
|
+
prefix +
|
2293
|
+
";\n\tif(!arguments.length){\n\t\treturn " +
|
2294
|
+
code +
|
2295
|
+
"\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) +
|
2296
|
+
"= vvv;\n} "
|
2297
|
+
try {
|
2298
|
+
fn = Function.apply(noop, names.concat(_body))
|
2299
|
+
data.evaluator = evaluatorPool.put(exprId, fn)
|
2300
|
+
} catch (e) {
|
2301
|
+
log("debug: parse error," + e.message)
|
2302
|
+
}
|
2303
|
+
vars = assigns = names = null //释放内存
|
2304
|
+
return
|
2305
|
+
} else if (dataType === "on") { //事件绑定
|
2306
|
+
if (code.indexOf("(") === -1) {
|
2307
|
+
code += ".call(this, $event)"
|
2308
|
+
} else {
|
2309
|
+
code = code.replace("(", ".call(this,")
|
2310
|
+
}
|
2311
|
+
names.push("$event")
|
2312
|
+
code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需要Function("return ;")
|
2313
|
+
var lastIndex = code.lastIndexOf("\nreturn")
|
2314
|
+
var header = code.slice(0, lastIndex)
|
2315
|
+
var footer = code.slice(lastIndex)
|
2316
|
+
code = header + "\n" + footer
|
2317
|
+
} else { //其他绑定
|
2318
|
+
code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需要Function("return ;")
|
2319
|
+
}
|
2320
|
+
try {
|
2321
|
+
fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code))
|
2322
|
+
data.evaluator = evaluatorPool.put(exprId, fn)
|
2323
|
+
} catch (e) {
|
2324
|
+
log("debug: parse error," + e.message)
|
2325
|
+
}
|
2326
|
+
vars = assigns = names = null //释放内存
|
2327
|
+
}
|
2328
|
+
function stringifyExpr(code) {
|
2329
|
+
var hasExpr = rexpr.test(code) //比如ms-class="width{{w}}"的情况
|
2330
|
+
if (hasExpr) {
|
2331
|
+
var array = scanExpr(code)
|
2332
|
+
if (array.length === 1) {
|
2333
|
+
return array[0].value
|
2334
|
+
}
|
2335
|
+
return array.map(function (el) {
|
2336
|
+
return el.expr ? "(" + el.value + ")" : quote(el.value)
|
2337
|
+
}).join(" + ")
|
2338
|
+
} else {
|
2339
|
+
return code
|
2340
|
+
}
|
2341
|
+
}
|
2342
|
+
//parseExpr的智能引用代理
|
2343
|
+
|
2344
|
+
function parseExprProxy(code, scopes, data, noRegister) {
|
2345
|
+
code = code || "" //code 可能未定义
|
2346
|
+
parseExpr(code, scopes, data)
|
2347
|
+
if (data.evaluator && !noRegister) {
|
2348
|
+
data.handler = bindingExecutors[data.handlerName || data.type]
|
2349
|
+
//方便调试
|
2350
|
+
//这里非常重要,我们通过判定视图刷新函数的element是否在DOM树决定
|
2351
|
+
//将它移出订阅者列表
|
2352
|
+
avalon.injectBinding(data)
|
2353
|
+
}
|
2354
|
+
}
|
2355
|
+
avalon.parseExprProxy = parseExprProxy
|
2356
|
+
/*********************************************************************
|
2357
|
+
* 扫描系统 *
|
2358
|
+
**********************************************************************/
|
2359
|
+
|
2360
|
+
avalon.scan = function(elem, vmodel) {
|
2361
|
+
elem = elem || root
|
2362
|
+
var vmodels = vmodel ? [].concat(vmodel) : []
|
2363
|
+
scanTag(elem, vmodels)
|
2364
|
+
}
|
2365
|
+
|
2366
|
+
//http://www.w3.org/TR/html5/syntax.html#void-elements
|
2367
|
+
var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase())
|
2368
|
+
|
2369
|
+
function checkScan(elem, callback, innerHTML) {
|
2370
|
+
var id = setTimeout(function() {
|
2371
|
+
var currHTML = elem.innerHTML
|
2372
|
+
clearTimeout(id)
|
2373
|
+
if (currHTML === innerHTML) {
|
2374
|
+
callback()
|
2375
|
+
} else {
|
2376
|
+
checkScan(elem, callback, currHTML)
|
2377
|
+
}
|
2378
|
+
})
|
2379
|
+
}
|
2380
|
+
|
2381
|
+
|
2382
|
+
function createSignalTower(elem, vmodel) {
|
2383
|
+
var id = elem.getAttribute("avalonctrl") || vmodel.$id
|
2384
|
+
elem.setAttribute("avalonctrl", id)
|
2385
|
+
vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]'
|
2386
|
+
}
|
2387
|
+
|
2388
|
+
var getBindingCallback = function(elem, name, vmodels) {
|
2389
|
+
var callback = elem.getAttribute(name)
|
2390
|
+
if (callback) {
|
2391
|
+
for (var i = 0, vm; vm = vmodels[i++]; ) {
|
2392
|
+
if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") {
|
2393
|
+
return vm[callback]
|
2394
|
+
}
|
2395
|
+
}
|
2396
|
+
}
|
2397
|
+
}
|
2398
|
+
|
2399
|
+
function executeBindings(bindings, vmodels) {
|
2400
|
+
for (var i = 0, data; data = bindings[i++]; ) {
|
2401
|
+
data.vmodels = vmodels
|
2402
|
+
bindingHandlers[data.type](data, vmodels)
|
2403
|
+
if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数据绑定,防止被二次解析
|
2404
|
+
//chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99
|
2405
|
+
data.element.removeAttribute(data.name)
|
2406
|
+
}
|
2407
|
+
}
|
2408
|
+
bindings.length = 0
|
2409
|
+
}
|
2410
|
+
|
2411
|
+
//https://github.com/RubyLouvre/avalon/issues/636
|
2412
|
+
var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) {
|
2413
|
+
var node = elem.firstChild, text
|
2414
|
+
while (node) {
|
2415
|
+
var aaa = node.nextSibling
|
2416
|
+
if (node.nodeType === 3) {
|
2417
|
+
if (text) {
|
2418
|
+
text.nodeValue += node.nodeValue
|
2419
|
+
elem.removeChild(node)
|
2420
|
+
} else {
|
2421
|
+
text = node
|
2422
|
+
}
|
2423
|
+
} else {
|
2424
|
+
text = null
|
2425
|
+
}
|
2426
|
+
node = aaa
|
2427
|
+
}
|
2428
|
+
} : 0
|
2429
|
+
var roneTime = /^\s*::/
|
2430
|
+
var rmsAttr = /ms-(\w+)-?(.*)/
|
2431
|
+
var priorityMap = {
|
2432
|
+
"if": 10,
|
2433
|
+
"repeat": 90,
|
2434
|
+
"data": 100,
|
2435
|
+
"widget": 110,
|
2436
|
+
"each": 1400,
|
2437
|
+
"with": 1500,
|
2438
|
+
"duplex": 2000,
|
2439
|
+
"on": 3000
|
2440
|
+
}
|
2441
|
+
|
2442
|
+
var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit")
|
2443
|
+
var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled")
|
2444
|
+
function bindingSorter(a, b) {
|
2445
|
+
return a.priority - b.priority
|
2446
|
+
}
|
2447
|
+
|
2448
|
+
function scanAttr(elem, vmodels, match) {
|
2449
|
+
var scanNode = true
|
2450
|
+
if (vmodels.length) {
|
2451
|
+
var attributes = elem.attributes
|
2452
|
+
var bindings = []
|
2453
|
+
var fixAttrs = []
|
2454
|
+
var uniq = {}
|
2455
|
+
var msData = createMap()
|
2456
|
+
for (var i = 0, attr; attr = attributes[i++]; ) {
|
2457
|
+
if (attr.specified) {
|
2458
|
+
if (match = attr.name.match(rmsAttr)) {
|
2459
|
+
//如果是以指定前缀命名的
|
2460
|
+
var type = match[1]
|
2461
|
+
var param = match[2] || ""
|
2462
|
+
var value = attr.value
|
2463
|
+
var name = attr.name
|
2464
|
+
if (uniq[name]) {//IE8下ms-repeat,ms-with BUG
|
2465
|
+
continue
|
2466
|
+
}
|
2467
|
+
uniq[name] = 1
|
2468
|
+
if (events[type]) {
|
2469
|
+
param = type
|
2470
|
+
type = "on"
|
2471
|
+
} else if (obsoleteAttrs[type]) {
|
2472
|
+
if (type === "enabled") {//吃掉ms-enabled绑定,用ms-disabled代替
|
2473
|
+
log("warning!ms-enabled或ms-attr-enabled已经被废弃")
|
2474
|
+
type = "disabled"
|
2475
|
+
value = "!(" + value + ")"
|
2476
|
+
}
|
2477
|
+
param = type
|
2478
|
+
type = "attr"
|
2479
|
+
name = "ms-" + type + "-" + param
|
2480
|
+
fixAttrs.push([attr.name, name, value])
|
2481
|
+
}
|
2482
|
+
msData[name] = value
|
2483
|
+
if (typeof bindingHandlers[type] === "function") {
|
2484
|
+
var newValue = value.replace(roneTime, "")
|
2485
|
+
var oneTime = value !== newValue
|
2486
|
+
var binding = {
|
2487
|
+
type: type,
|
2488
|
+
param: param,
|
2489
|
+
element: elem,
|
2490
|
+
name: name,
|
2491
|
+
value: newValue,
|
2492
|
+
oneTime: oneTime,
|
2493
|
+
priority: (priorityMap[type] || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, "")) || 0)
|
2494
|
+
}
|
2495
|
+
if (type === "html" || type === "text") {
|
2496
|
+
var token = getToken(value)
|
2497
|
+
avalon.mix(binding, token)
|
2498
|
+
binding.filters = binding.filters.replace(rhasHtml, function () {
|
2499
|
+
binding.type = "html"
|
2500
|
+
binding.group = 1
|
2501
|
+
return ""
|
2502
|
+
})// jshint ignore:line
|
2503
|
+
} else if (type === "duplex") {
|
2504
|
+
var hasDuplex = name
|
2505
|
+
} else if (name === "ms-if-loop") {
|
2506
|
+
binding.priority += 100
|
2507
|
+
}
|
2508
|
+
bindings.push(binding)
|
2509
|
+
if (type === "widget") {
|
2510
|
+
elem.msData = elem.msData || msData
|
2511
|
+
}
|
2512
|
+
}
|
2513
|
+
}
|
2514
|
+
}
|
2515
|
+
}
|
2516
|
+
if (bindings.length) {
|
2517
|
+
bindings.sort(bindingSorter)
|
2518
|
+
fixAttrs.forEach(function (arr) {
|
2519
|
+
log("warning!请改用" + arr[1] + "代替" + arr[0] + "!")
|
2520
|
+
elem.removeAttribute(arr[0])
|
2521
|
+
elem.setAttribute(arr[1], arr[2])
|
2522
|
+
})
|
2523
|
+
var control = elem.type
|
2524
|
+
if (control && hasDuplex) {
|
2525
|
+
if (msData["ms-attr-value"] && elem.type === "text") {
|
2526
|
+
log("warning!" + control + "控件不能同时定义ms-attr-value与" + hasDuplex)
|
2527
|
+
}
|
2528
|
+
}
|
2529
|
+
|
2530
|
+
for (i = 0; binding = bindings[i]; i++) {
|
2531
|
+
type = binding.type
|
2532
|
+
if (rnoscanAttrBinding.test(type)) {
|
2533
|
+
return executeBindings(bindings.slice(0, i + 1), vmodels)
|
2534
|
+
} else if (scanNode) {
|
2535
|
+
scanNode = !rnoscanNodeBinding.test(type)
|
2536
|
+
}
|
2537
|
+
}
|
2538
|
+
executeBindings(bindings, vmodels)
|
2539
|
+
}
|
2540
|
+
}
|
2541
|
+
if (scanNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML + elem.textContent)) {
|
2542
|
+
mergeTextNodes && mergeTextNodes(elem)
|
2543
|
+
scanNodeList(elem, vmodels) //扫描子孙元素
|
2544
|
+
}
|
2545
|
+
}
|
2546
|
+
|
2547
|
+
var rnoscanAttrBinding = /^if|widget|repeat$/
|
2548
|
+
var rnoscanNodeBinding = /^each|with|html|include$/
|
2549
|
+
function scanNodeList(parent, vmodels) {
|
2550
|
+
var nodes = avalon.slice(parent.childNodes)
|
2551
|
+
scanNodeArray(nodes, vmodels)
|
2398
2552
|
}
|
2399
2553
|
|
2400
|
-
function
|
2401
|
-
var
|
2402
|
-
|
2403
|
-
|
2404
|
-
|
2405
|
-
|
2406
|
-
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
2414
|
-
|
2415
|
-
if (vars.length) {
|
2416
|
-
var name = "vm" + expose + "_" + i
|
2417
|
-
names.push(name)
|
2418
|
-
args.push(scopes[i])
|
2419
|
-
assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data))
|
2554
|
+
function scanNodeArray(nodes, vmodels) {
|
2555
|
+
for (var i = 0, node; node = nodes[i++];) {
|
2556
|
+
switch (node.nodeType) {
|
2557
|
+
case 1:
|
2558
|
+
scanTag(node, vmodels) //扫描元素节点
|
2559
|
+
if (node.msCallback) {
|
2560
|
+
node.msCallback()
|
2561
|
+
node.msCallback = void 0
|
2562
|
+
}
|
2563
|
+
break
|
2564
|
+
case 3:
|
2565
|
+
if(rexpr.test(node.nodeValue)){
|
2566
|
+
scanText(node, vmodels, i) //扫描文本节点
|
2567
|
+
}
|
2568
|
+
break
|
2420
2569
|
}
|
2421
2570
|
}
|
2422
|
-
|
2571
|
+
}
|
2572
|
+
|
2573
|
+
|
2574
|
+
function scanTag(elem, vmodels, node) {
|
2575
|
+
//扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
|
2576
|
+
//--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
|
2577
|
+
var a = elem.getAttribute("ms-skip")
|
2578
|
+
var b = elem.getAttributeNode("ms-important")
|
2579
|
+
var c = elem.getAttributeNode("ms-controller")
|
2580
|
+
if (typeof a === "string") {
|
2423
2581
|
return
|
2582
|
+
} else if (node = b || c) {
|
2583
|
+
var newVmodel = avalon.vmodels[node.value]
|
2584
|
+
if (!newVmodel) {
|
2585
|
+
return
|
2586
|
+
}
|
2587
|
+
//ms-important不包含父VM,ms-controller相反
|
2588
|
+
vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
|
2589
|
+
elem.removeAttribute(node.name) //removeAttributeNode不会刷新[ms-controller]样式规则
|
2590
|
+
elem.classList.remove(node.name)
|
2591
|
+
createSignalTower(elem, newVmodel)
|
2424
2592
|
}
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2435
|
-
|
2436
|
-
var array = _.split(".")
|
2437
|
-
if (array.length > 2) {
|
2438
|
-
var last = array.pop()
|
2439
|
-
assigns.push(name + " = " + array.join("."))
|
2440
|
-
return name + "." + last
|
2441
|
-
} else {
|
2442
|
-
return _
|
2443
|
-
}
|
2444
|
-
}
|
2445
|
-
assigns.push(name + " = " + _)
|
2446
|
-
return name
|
2447
|
-
} else {
|
2448
|
-
return _
|
2449
|
-
}
|
2450
|
-
})
|
2593
|
+
scanAttr(elem, vmodels) //扫描特性节点
|
2594
|
+
}
|
2595
|
+
var rhasHtml = /\|\s*html(?:\b|$)/,
|
2596
|
+
r11a = /\|\|/g,
|
2597
|
+
rlt = /</g,
|
2598
|
+
rgt = />/g,
|
2599
|
+
rstringLiteral = /(['"])(\\\1|.)+?\1/g
|
2600
|
+
function getToken(value) {
|
2601
|
+
if (value.indexOf("|") > 0) {
|
2602
|
+
var scapegoat = value.replace(rstringLiteral, function (_) {
|
2603
|
+
return Array(_.length + 1).join("1")// jshint ignore:line
|
2451
2604
|
})
|
2605
|
+
var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
|
2606
|
+
if (index > -1) {
|
2607
|
+
return {
|
2608
|
+
filters: value.slice(index),
|
2609
|
+
value: value.slice(0, index),
|
2610
|
+
expr: true
|
2611
|
+
}
|
2612
|
+
}
|
2452
2613
|
}
|
2453
|
-
|
2454
|
-
|
2455
|
-
|
2456
|
-
|
2457
|
-
if (fn) {
|
2458
|
-
data.evaluator = fn
|
2459
|
-
return
|
2460
|
-
}
|
2461
|
-
prefix = assigns.join(", ")
|
2462
|
-
if (prefix) {
|
2463
|
-
prefix = "var " + prefix
|
2614
|
+
return {
|
2615
|
+
value: value,
|
2616
|
+
filters: "",
|
2617
|
+
expr: true
|
2464
2618
|
}
|
2465
|
-
|
2466
|
-
|
2467
|
-
|
2619
|
+
}
|
2620
|
+
|
2621
|
+
function scanExpr(str) {
|
2622
|
+
var tokens = [],
|
2623
|
+
value, start = 0,
|
2624
|
+
stop
|
2625
|
+
do {
|
2626
|
+
stop = str.indexOf(openTag, start)
|
2627
|
+
if (stop === -1) {
|
2628
|
+
break
|
2468
2629
|
}
|
2469
|
-
|
2470
|
-
|
2471
|
-
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2476
|
-
"\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) +
|
2477
|
-
"= vvv;\n} "
|
2478
|
-
try {
|
2479
|
-
fn = Function.apply(noop, names.concat(_body))
|
2480
|
-
data.evaluator = cacheExprs.put(exprId, fn)
|
2481
|
-
} catch (e) {
|
2482
|
-
log("debug: parse error," + e.message)
|
2630
|
+
value = str.slice(start, stop)
|
2631
|
+
if (value) { // {{ 左边的文本
|
2632
|
+
tokens.push({
|
2633
|
+
value: value,
|
2634
|
+
filters: "",
|
2635
|
+
expr: false
|
2636
|
+
})
|
2483
2637
|
}
|
2484
|
-
|
2485
|
-
|
2486
|
-
if (
|
2487
|
-
|
2488
|
-
} else {
|
2489
|
-
code = code.replace("(", ".call(this,")
|
2638
|
+
start = stop + openTag.length
|
2639
|
+
stop = str.indexOf(closeTag, start)
|
2640
|
+
if (stop === -1) {
|
2641
|
+
break
|
2490
2642
|
}
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
2504
|
-
log("debug: parse error," + e.message)
|
2505
|
-
} finally {
|
2506
|
-
vars = assigns = names = null //释放内存
|
2643
|
+
value = str.slice(start, stop)
|
2644
|
+
if (value) { //处理{{ }}插值表达式
|
2645
|
+
tokens.push(getToken(value, start))
|
2646
|
+
}
|
2647
|
+
start = stop + closeTag.length
|
2648
|
+
} while (1)
|
2649
|
+
value = str.slice(start)
|
2650
|
+
if (value) { //}} 右边的文本
|
2651
|
+
tokens.push({
|
2652
|
+
value: value,
|
2653
|
+
expr: false,
|
2654
|
+
filters: ""
|
2655
|
+
})
|
2507
2656
|
}
|
2657
|
+
return tokens
|
2508
2658
|
}
|
2509
2659
|
|
2510
|
-
|
2511
|
-
|
2512
|
-
|
2513
|
-
|
2514
|
-
|
2515
|
-
|
2516
|
-
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2660
|
+
function scanText(textNode, vmodels, index) {
|
2661
|
+
var bindings = []
|
2662
|
+
tokens = scanExpr(textNode.data)
|
2663
|
+
if (tokens.length) {
|
2664
|
+
for (var i = 0; token = tokens[i++]; ) {
|
2665
|
+
var node = DOC.createTextNode(token.value) //将文本转换为文本节点,并替换原来的文本节点
|
2666
|
+
if (token.expr) {
|
2667
|
+
token.value = token.value.replace(roneTime, function () {
|
2668
|
+
token.oneTime = true
|
2669
|
+
return ""
|
2670
|
+
})// jshint ignore:line
|
2671
|
+
token.type = "text"
|
2672
|
+
token.element = node
|
2673
|
+
token.filters = token.filters.replace(rhasHtml, function (a, b,c) {
|
2674
|
+
token.type = "html"
|
2675
|
+
return ""
|
2676
|
+
})// jshint ignore:line
|
2677
|
+
token.pos = index * 1000 + i
|
2678
|
+
bindings.push(token) //收集带有插值表达式的文本
|
2679
|
+
}
|
2680
|
+
avalonFragment.appendChild(node)
|
2681
|
+
}
|
2682
|
+
textNode.parentNode.replaceChild(avalonFragment, textNode)
|
2683
|
+
if (bindings.length)
|
2684
|
+
executeBindings(bindings, vmodels)
|
2526
2685
|
}
|
2527
2686
|
}
|
2528
|
-
|
2687
|
+
|
2529
2688
|
var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls",
|
2530
2689
|
"declare,disabled,defer,defaultChecked,defaultSelected",
|
2531
2690
|
"contentEditable,isMap,loop,multiple,noHref,noResize,noShade",
|
2532
|
-
"open,readOnly,selected"
|
2691
|
+
"open,readOnly,selected"
|
2692
|
+
].join(",")
|
2533
2693
|
var boolMap = {}
|
2534
2694
|
bools.replace(rword, function (name) {
|
2535
2695
|
boolMap[name.toLowerCase()] = name
|
@@ -2546,7 +2706,8 @@ var propMap = {//属性名映射
|
|
2546
2706
|
|
2547
2707
|
var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan",
|
2548
2708
|
"dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight",
|
2549
|
-
"rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
|
2709
|
+
"rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
|
2710
|
+
].join(",")
|
2550
2711
|
anomaly.replace(rword, function (name) {
|
2551
2712
|
propMap[name.toLowerCase()] = name
|
2552
2713
|
})
|
@@ -2555,21 +2716,13 @@ var rnoscripts = /<noscript.*?>(?:[\s\S]+?)<\/noscript>/img
|
|
2555
2716
|
var rnoscriptText = /<noscript.*?>([\s\S]+?)<\/noscript>/im
|
2556
2717
|
|
2557
2718
|
var getXHR = function () {
|
2558
|
-
return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")// jshint ignore:line
|
2719
|
+
return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP") // jshint ignore:line
|
2559
2720
|
}
|
2560
2721
|
|
2561
|
-
var
|
2722
|
+
var templatePool = avalon.templateCache = {}
|
2562
2723
|
|
2563
2724
|
bindingHandlers.attr = function (data, vmodels) {
|
2564
|
-
var
|
2565
|
-
simple = true
|
2566
|
-
if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) {
|
2567
|
-
simple = false
|
2568
|
-
if (rexpr.test(text) && RegExp.rightContext === "" && RegExp.leftContext === "") {
|
2569
|
-
simple = true
|
2570
|
-
text = RegExp.$1
|
2571
|
-
}
|
2572
|
-
}
|
2725
|
+
var value = stringifyExpr(data.value.trim())
|
2573
2726
|
if (data.type === "include") {
|
2574
2727
|
var elem = data.element
|
2575
2728
|
data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels)
|
@@ -2590,7 +2743,7 @@ bindingHandlers.attr = function (data, vmodels) {
|
|
2590
2743
|
}
|
2591
2744
|
}
|
2592
2745
|
data.handlerName = "attr" //handleName用于处理多种绑定共用同一种bindingExecutor的情况
|
2593
|
-
parseExprProxy(
|
2746
|
+
parseExprProxy(value, vmodels, data)
|
2594
2747
|
}
|
2595
2748
|
|
2596
2749
|
bindingExecutors.attr = function (val, elem, data) {
|
@@ -2599,28 +2752,29 @@ bindingExecutors.attr = function (val, elem, data) {
|
|
2599
2752
|
if (method === "css") {
|
2600
2753
|
avalon(elem).css(attrName, val)
|
2601
2754
|
} else if (method === "attr") {
|
2755
|
+
|
2602
2756
|
// ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc
|
2603
2757
|
// ms-attr-class="xxx" vm.xxx=false 清空元素的所有类名
|
2604
2758
|
// ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性
|
2605
|
-
if (boolMap[attrName]) {
|
2606
|
-
var bool = boolMap[attrName]
|
2607
|
-
if (typeof elem[bool] === "boolean") {
|
2608
|
-
// IE6-11不支持动态设置fieldset的disabled属性,IE11下样式是生效了,但无法阻止用户对其底下的input元素进行设值……
|
2609
|
-
return elem[bool] = !!val
|
2610
|
-
}
|
2611
|
-
}
|
2612
2759
|
var toRemove = (val === false) || (val === null) || (val === void 0)
|
2613
2760
|
|
2614
2761
|
if (!W3C && propMap[attrName]) { //旧式IE下需要进行名字映射
|
2615
2762
|
attrName = propMap[attrName]
|
2616
2763
|
}
|
2764
|
+
var bool = boolMap[attrName]
|
2765
|
+
if (typeof elem[bool] === "boolean") {
|
2766
|
+
elem[bool] = !!val //布尔属性必须使用el.xxx = true|false方式设值
|
2767
|
+
if (!val) { //如果为false, IE全系列下相当于setAttribute(xxx,''),会影响到样式,需要进一步处理
|
2768
|
+
toRemove = true
|
2769
|
+
}
|
2770
|
+
}
|
2617
2771
|
if (toRemove) {
|
2618
2772
|
return elem.removeAttribute(attrName)
|
2619
2773
|
}
|
2620
2774
|
//SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy
|
2621
2775
|
var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false)
|
2622
2776
|
if (isInnate) {
|
2623
|
-
elem[attrName] = val
|
2777
|
+
elem[attrName] = val + ""
|
2624
2778
|
} else {
|
2625
2779
|
elem.setAttribute(attrName, val)
|
2626
2780
|
}
|
@@ -2632,7 +2786,9 @@ bindingExecutors.attr = function (val, elem, data) {
|
|
2632
2786
|
var target = replace ? elem.parentNode : elem
|
2633
2787
|
var scanTemplate = function (text) {
|
2634
2788
|
if (loaded) {
|
2635
|
-
|
2789
|
+
var newText = loaded.apply(target, [text].concat(vmodels))
|
2790
|
+
if (typeof newText === "string")
|
2791
|
+
text = newText
|
2636
2792
|
}
|
2637
2793
|
if (rendered) {
|
2638
2794
|
checkScan(target, function () {
|
@@ -2665,20 +2821,27 @@ bindingExecutors.attr = function (val, elem, data) {
|
|
2665
2821
|
}
|
2666
2822
|
|
2667
2823
|
if (data.param === "src") {
|
2668
|
-
if (
|
2824
|
+
if (typeof templatePool[val] === "string") {
|
2669
2825
|
avalon.nextTick(function () {
|
2670
|
-
scanTemplate(
|
2826
|
+
scanTemplate(templatePool[val])
|
2671
2827
|
})
|
2828
|
+
} else if (Array.isArray(templatePool[val])) { //#805 防止在循环绑定中发出许多相同的请求
|
2829
|
+
templatePool[val].push(scanTemplate)
|
2672
2830
|
} else {
|
2673
2831
|
var xhr = getXHR()
|
2674
2832
|
xhr.onreadystatechange = function () {
|
2675
2833
|
if (xhr.readyState === 4) {
|
2676
2834
|
var s = xhr.status
|
2677
2835
|
if (s >= 200 && s < 300 || s === 304 || s === 1223) {
|
2678
|
-
|
2836
|
+
var text = xhr.responseText
|
2837
|
+
for (var f = 0, fn; fn = templatePool[val][f++]; ) {
|
2838
|
+
fn(text)
|
2839
|
+
}
|
2840
|
+
templatePool[val] = text
|
2679
2841
|
}
|
2680
2842
|
}
|
2681
2843
|
}
|
2844
|
+
templatePool[val] = [scanTemplate]
|
2682
2845
|
xhr.open("GET", val, true)
|
2683
2846
|
if ("withCredentials" in xhr) {
|
2684
2847
|
xhr.withCredentials = true
|
@@ -2729,13 +2892,14 @@ bindingExecutors.attr = function (val, elem, data) {
|
|
2729
2892
|
function getTemplateNodes(data, id, text) {
|
2730
2893
|
var div = data.templateCache && data.templateCache[id]
|
2731
2894
|
if (div) {
|
2732
|
-
var dom = DOC.createDocumentFragment(),
|
2895
|
+
var dom = DOC.createDocumentFragment(),
|
2896
|
+
firstChild
|
2733
2897
|
while (firstChild = div.firstChild) {
|
2734
2898
|
dom.appendChild(firstChild)
|
2735
2899
|
}
|
2736
2900
|
return dom
|
2737
2901
|
}
|
2738
|
-
return
|
2902
|
+
return avalon.parseHTML(text)
|
2739
2903
|
}
|
2740
2904
|
|
2741
2905
|
//这几个指令都可以使用插值表达式,如ms-src="aaa/{{b}}/{{c}}.html"
|
@@ -2744,92 +2908,85 @@ function getTemplateNodes(data, id, text) {
|
|
2744
2908
|
})
|
2745
2909
|
//根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
|
2746
2910
|
//http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
|
2747
|
-
bindingHandlers["class"] = function(
|
2748
|
-
var oldStyle =
|
2749
|
-
text =
|
2911
|
+
bindingHandlers["class"] = function (binding, vmodels) {
|
2912
|
+
var oldStyle = binding.param,
|
2913
|
+
text = binding.value,
|
2750
2914
|
rightExpr
|
2751
|
-
|
2915
|
+
binding.handlerName = "class"
|
2752
2916
|
if (!oldStyle || isFinite(oldStyle)) {
|
2753
|
-
|
2754
|
-
var
|
2917
|
+
binding.param = "" //去掉数字
|
2918
|
+
var colonIndex = text.replace(rexprg, function (a) {
|
2755
2919
|
return a.replace(/./g, "0")
|
2756
|
-
|
2757
|
-
})
|
2758
|
-
var colonIndex = noExpr.indexOf(":") //取得第一个冒号的位置
|
2920
|
+
}).indexOf(":") //取得第一个冒号的位置
|
2759
2921
|
if (colonIndex === -1) { // 比如 ms-class="aaa bbb ccc" 的情况
|
2760
2922
|
var className = text
|
2761
|
-
|
2923
|
+
rightExpr = true
|
2924
|
+
} else { // 比如 ms-class-1="ui-state-active:checked" 的情况
|
2762
2925
|
className = text.slice(0, colonIndex)
|
2763
2926
|
rightExpr = text.slice(colonIndex + 1)
|
2764
|
-
parseExpr(rightExpr, vmodels, data) //决定是添加还是删除
|
2765
|
-
if (!data.evaluator) {
|
2766
|
-
log("debug: ms-class '" + (rightExpr || "").trim() + "' 不存在于VM中")
|
2767
|
-
return false
|
2768
|
-
} else {
|
2769
|
-
data._evaluator = data.evaluator
|
2770
|
-
data._args = data.args
|
2771
|
-
}
|
2772
2927
|
}
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2928
|
+
if (!rexpr.test(text)) {
|
2929
|
+
className = quote(className)
|
2930
|
+
} else {
|
2931
|
+
className = stringifyExpr(className)
|
2776
2932
|
}
|
2777
|
-
|
2933
|
+
binding.expr = "[" + className + "," + rightExpr + "]"
|
2778
2934
|
} else {
|
2779
|
-
|
2780
|
-
|
2935
|
+
binding.expr = '[' + quote(oldStyle) + "," + text + "]"
|
2936
|
+
binding.oldStyle = oldStyle
|
2937
|
+
}
|
2938
|
+
var method = binding.type
|
2939
|
+
if (method === "hover" || method === "active") { //确保只绑定一次
|
2940
|
+
if (!binding.hasBindEvent) {
|
2941
|
+
var elem = binding.element
|
2942
|
+
var $elem = avalon(elem)
|
2943
|
+
var activate = "mouseenter" //在移出移入时切换类名
|
2944
|
+
var abandon = "mouseleave"
|
2945
|
+
if (method === "active") { //在聚焦失焦中切换类名
|
2946
|
+
elem.tabIndex = elem.tabIndex || -1
|
2947
|
+
activate = "mousedown"
|
2948
|
+
abandon = "mouseup"
|
2949
|
+
var fn0 = $elem.bind("mouseleave", function () {
|
2950
|
+
binding.toggleClass && $elem.removeClass(binding.newClass)
|
2951
|
+
})
|
2952
|
+
}
|
2953
|
+
}
|
2954
|
+
|
2955
|
+
var fn1 = $elem.bind(activate, function () {
|
2956
|
+
binding.toggleClass && $elem.addClass(binding.newClass)
|
2957
|
+
})
|
2958
|
+
var fn2 = $elem.bind(abandon, function () {
|
2959
|
+
binding.toggleClass && $elem.removeClass(binding.newClass)
|
2960
|
+
})
|
2961
|
+
binding.rollback = function () {
|
2962
|
+
$elem.unbind("mouseleave", fn0)
|
2963
|
+
$elem.unbind(activate, fn1)
|
2964
|
+
$elem.unbind(abandon, fn2)
|
2965
|
+
}
|
2966
|
+
binding.hasBindEvent = true
|
2781
2967
|
}
|
2968
|
+
parseExprProxy(binding.expr, vmodels, binding)
|
2782
2969
|
}
|
2783
2970
|
|
2784
|
-
bindingExecutors
|
2785
|
-
var $elem = avalon(elem)
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
if (
|
2794
|
-
$elem.
|
2795
|
-
}
|
2796
|
-
|
2797
|
-
switch (method) {
|
2798
|
-
case "class":
|
2799
|
-
$elem.toggleClass(data.newClass, data.toggleClass)
|
2800
|
-
break
|
2801
|
-
case "hover":
|
2802
|
-
case "active":
|
2803
|
-
if (!data.hasBindEvent) { //确保只绑定一次
|
2804
|
-
var activate = "mouseenter" //在移出移入时切换类名
|
2805
|
-
var abandon = "mouseleave"
|
2806
|
-
if (method === "active") { //在聚焦失焦中切换类名
|
2807
|
-
elem.tabIndex = elem.tabIndex || -1
|
2808
|
-
activate = "mousedown"
|
2809
|
-
abandon = "mouseup"
|
2810
|
-
var fn0 = $elem.bind("mouseleave", function() {
|
2811
|
-
data.toggleClass && $elem.removeClass(data.newClass)
|
2812
|
-
})
|
2813
|
-
}
|
2814
|
-
var fn1 = $elem.bind(activate, function() {
|
2815
|
-
data.toggleClass && $elem.addClass(data.newClass)
|
2816
|
-
})
|
2817
|
-
var fn2 = $elem.bind(abandon, function() {
|
2818
|
-
data.toggleClass && $elem.removeClass(data.newClass)
|
2819
|
-
})
|
2820
|
-
data.rollback = function() {
|
2821
|
-
$elem.unbind("mouseleave", fn0)
|
2822
|
-
$elem.unbind(activate, fn1)
|
2823
|
-
$elem.unbind(abandon, fn2)
|
2824
|
-
}
|
2825
|
-
data.hasBindEvent = true
|
2826
|
-
}
|
2827
|
-
break;
|
2971
|
+
bindingExecutors["class"] = function (arr, elem, binding) {
|
2972
|
+
var $elem = avalon(elem)
|
2973
|
+
binding.newClass = arr[0]
|
2974
|
+
binding.toggleClass = !!arr[1]
|
2975
|
+
if (binding.oldClass && binding.newClass !== binding.oldClass) {
|
2976
|
+
$elem.removeClass(binding.oldClass)
|
2977
|
+
}
|
2978
|
+
binding.oldClass = binding.newClass
|
2979
|
+
if (binding.type === "class") {
|
2980
|
+
if (binding.oldStyle) {
|
2981
|
+
$elem.toggleClass(binding.oldStyle, !!arr[1])
|
2982
|
+
} else {
|
2983
|
+
$elem.toggleClass(binding.newClass, binding.toggleClass)
|
2828
2984
|
}
|
2829
2985
|
}
|
2986
|
+
|
2830
2987
|
}
|
2831
2988
|
|
2832
|
-
"hover,active".replace(rword, function(method) {
|
2989
|
+
"hover,active".replace(rword, function (method) {
|
2833
2990
|
bindingHandlers[method] = bindingHandlers["class"]
|
2834
2991
|
})
|
2835
2992
|
//ms-controller绑定已经在scanTag 方法中实现
|
@@ -2838,21 +2995,20 @@ bindingExecutors ["class"] = function(val, elem, data) {
|
|
2838
2995
|
|
2839
2996
|
// bindingHandlers.data 定义在if.js
|
2840
2997
|
bindingExecutors.data = function(val, elem, data) {
|
2841
|
-
|
2842
|
-
|
2843
|
-
|
2844
|
-
|
2845
|
-
|
2846
|
-
|
2998
|
+
var key = "data-" + data.param
|
2999
|
+
if (val && typeof val === "object") {
|
3000
|
+
elem[key] = val
|
3001
|
+
} else {
|
3002
|
+
elem.setAttribute(key, String(val))
|
3003
|
+
}
|
2847
3004
|
}
|
2848
|
-
|
2849
3005
|
//双工绑定
|
2850
|
-
var duplexBinding = bindingHandlers.duplex = function
|
3006
|
+
var duplexBinding = bindingHandlers.duplex = function(data, vmodels) {
|
2851
3007
|
var elem = data.element,
|
2852
|
-
|
2853
|
-
|
3008
|
+
hasCast
|
3009
|
+
parseExprProxy(data.value, vmodels, data, 1)
|
2854
3010
|
|
2855
|
-
|
3011
|
+
data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
|
2856
3012
|
if (data.evaluator && data.args) {
|
2857
3013
|
var params = []
|
2858
3014
|
var casting = oneObject("string,number,boolean,checked")
|
@@ -2862,7 +3018,7 @@ var duplexBinding = bindingHandlers.duplex = function (data, vmodels) {
|
|
2862
3018
|
if (elem.msData) {
|
2863
3019
|
elem.msData["ms-duplex"] = data.value
|
2864
3020
|
}
|
2865
|
-
data.param.replace(/\w+/g, function
|
3021
|
+
data.param.replace(/\w+/g, function(name) {
|
2866
3022
|
if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
|
2867
3023
|
if (name === "radio")
|
2868
3024
|
log("ms-duplex-radio已经更名为ms-duplex-checked")
|
@@ -2885,14 +3041,14 @@ var duplexBinding = bindingHandlers.duplex = function (data, vmodels) {
|
|
2885
3041
|
params.push("string")
|
2886
3042
|
}
|
2887
3043
|
data.param = params.join("-")
|
2888
|
-
data.bound = function
|
3044
|
+
data.bound = function(type, callback) {
|
2889
3045
|
if (elem.addEventListener) {
|
2890
3046
|
elem.addEventListener(type, callback, false)
|
2891
3047
|
} else {
|
2892
3048
|
elem.attachEvent("on" + type, callback)
|
2893
3049
|
}
|
2894
3050
|
var old = data.rollback
|
2895
|
-
data.rollback = function
|
3051
|
+
data.rollback = function() {
|
2896
3052
|
elem.avalonSetter = null
|
2897
3053
|
avalon.unbind(elem, type, callback)
|
2898
3054
|
old && old()
|
@@ -2909,29 +3065,30 @@ var duplexBinding = bindingHandlers.duplex = function (data, vmodels) {
|
|
2909
3065
|
}
|
2910
3066
|
}
|
2911
3067
|
//不存在 bindingExecutors.duplex
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
3068
|
+
|
3069
|
+
function fixNull(val) {
|
3070
|
+
return val == null ? "" : val
|
3071
|
+
}
|
2915
3072
|
avalon.duplexHooks = {
|
2916
3073
|
checked: {
|
2917
|
-
get: function
|
3074
|
+
get: function(val, data) {
|
2918
3075
|
return !data.element.oldValue
|
2919
3076
|
}
|
2920
3077
|
},
|
2921
3078
|
string: {
|
2922
|
-
get: function
|
3079
|
+
get: function(val) { //同步到VM
|
2923
3080
|
return val
|
2924
3081
|
},
|
2925
3082
|
set: fixNull
|
2926
3083
|
},
|
2927
3084
|
"boolean": {
|
2928
|
-
get: function
|
3085
|
+
get: function(val) {
|
2929
3086
|
return val === "true"
|
2930
3087
|
},
|
2931
3088
|
set: fixNull
|
2932
3089
|
},
|
2933
3090
|
number: {
|
2934
|
-
get: function
|
3091
|
+
get: function(val, data) {
|
2935
3092
|
var number = parseFloat(val)
|
2936
3093
|
if (-val === -number) {
|
2937
3094
|
return number
|
@@ -2951,7 +3108,7 @@ avalon.duplexHooks = {
|
|
2951
3108
|
}
|
2952
3109
|
|
2953
3110
|
function pipe(val, data, action, e) {
|
2954
|
-
data.param.replace(/\w+/g, function
|
3111
|
+
data.param.replace(/\w+/g, function(name) {
|
2955
3112
|
var hook = avalon.duplexHooks[name]
|
2956
3113
|
if (hook && typeof hook[action] === "function") {
|
2957
3114
|
val = hook[action](val, data)
|
@@ -2962,44 +3119,41 @@ function pipe(val, data, action, e) {
|
|
2962
3119
|
|
2963
3120
|
var TimerID, ribbon = []
|
2964
3121
|
|
2965
|
-
avalon.tick = function
|
2966
|
-
|
2967
|
-
|
3122
|
+
avalon.tick = function(fn) {
|
3123
|
+
if (ribbon.push(fn) === 1) {
|
3124
|
+
TimerID = setInterval(ticker, 60)
|
3125
|
+
}
|
2968
3126
|
}
|
2969
|
-
}
|
2970
3127
|
|
2971
|
-
function ticker() {
|
2972
|
-
|
2973
|
-
|
2974
|
-
|
2975
|
-
|
3128
|
+
function ticker() {
|
3129
|
+
for (var n = ribbon.length - 1; n >= 0; n--) {
|
3130
|
+
var el = ribbon[n]
|
3131
|
+
if (el() === false) {
|
3132
|
+
ribbon.splice(n, 1)
|
3133
|
+
}
|
3134
|
+
}
|
3135
|
+
if (!ribbon.length) {
|
3136
|
+
clearInterval(TimerID)
|
2976
3137
|
}
|
2977
3138
|
}
|
2978
|
-
if (!ribbon.length) {
|
2979
|
-
clearInterval(TimerID)
|
2980
|
-
}
|
2981
|
-
}
|
2982
3139
|
|
2983
3140
|
var watchValueInTimer = noop
|
2984
3141
|
var rmsinput = /text|password|hidden/
|
2985
|
-
new function
|
2986
|
-
try {//#272 IE9-IE11, firefox
|
3142
|
+
new function() { // jshint ignore:line
|
3143
|
+
try { //#272 IE9-IE11, firefox
|
2987
3144
|
var setters = {}
|
2988
3145
|
var aproto = HTMLInputElement.prototype
|
2989
3146
|
var bproto = HTMLTextAreaElement.prototype
|
2990
|
-
function newSetter(value) {// jshint ignore:line
|
2991
|
-
if (avalon.contains(root, this)) {
|
3147
|
+
function newSetter(value) { // jshint ignore:line
|
2992
3148
|
setters[this.tagName].call(this, value)
|
2993
|
-
if (
|
2994
|
-
return
|
2995
|
-
if (!this.msFocus && this.avalonSetter) {
|
3149
|
+
if (rmsinput.test(this.type) && !this.msFocus && this.avalonSetter) {
|
2996
3150
|
this.avalonSetter()
|
2997
3151
|
}
|
2998
|
-
}
|
2999
3152
|
}
|
3000
3153
|
var inputProto = HTMLInputElement.prototype
|
3001
3154
|
Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错
|
3002
3155
|
setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set
|
3156
|
+
|
3003
3157
|
Object.defineProperty(aproto, "value", {
|
3004
3158
|
set: newSetter
|
3005
3159
|
})
|
@@ -3008,67 +3162,66 @@ new function () {// jshint ignore:line
|
|
3008
3162
|
set: newSetter
|
3009
3163
|
})
|
3010
3164
|
} catch (e) {
|
3165
|
+
//在chrome 43中 ms-duplex终于不需要使用定时器实现双向绑定了
|
3166
|
+
// http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype
|
3167
|
+
// https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1
|
3011
3168
|
watchValueInTimer = avalon.tick
|
3012
3169
|
}
|
3013
|
-
}// jshint ignore:line
|
3014
|
-
|
3015
|
-
|
3170
|
+
} // jshint ignore:line
|
3016
3171
|
//处理radio, checkbox, text, textarea, password
|
3017
|
-
duplexBinding.INPUT = function
|
3172
|
+
duplexBinding.INPUT = function(element, evaluator, data) {
|
3018
3173
|
var $type = element.type,
|
3019
|
-
|
3020
|
-
|
3021
|
-
composing = false
|
3022
|
-
function callback(value) {
|
3023
|
-
data.changed.call(this, value, data)
|
3024
|
-
}
|
3025
|
-
function compositionStart() {
|
3026
|
-
composing = true
|
3027
|
-
}
|
3028
|
-
function compositionEnd() {
|
3174
|
+
bound = data.bound,
|
3175
|
+
$elem = avalon(element),
|
3029
3176
|
composing = false
|
3030
|
-
}
|
3031
|
-
//当value变化时改变model的值
|
3032
3177
|
|
3033
|
-
|
3034
|
-
|
3178
|
+
function callback(value) {
|
3179
|
+
data.changed.call(this, value, data)
|
3180
|
+
}
|
3181
|
+
|
3182
|
+
function compositionStart() {
|
3183
|
+
composing = true
|
3184
|
+
}
|
3185
|
+
|
3186
|
+
function compositionEnd() {
|
3187
|
+
composing = false
|
3188
|
+
}
|
3189
|
+
//当value变化时改变model的值
|
3190
|
+
|
3191
|
+
var updateVModel = function() {
|
3192
|
+
var val = element.value //防止递归调用形成死循环
|
3193
|
+
if (composing || val === element.oldValue) //处理中文输入法在minlengh下引发的BUG
|
3035
3194
|
return
|
3036
|
-
var val = element.oldValue = element.value //防止递归调用形成死循环
|
3037
3195
|
var lastValue = data.pipe(val, data, "get")
|
3038
|
-
if ($elem.data("
|
3196
|
+
if ($elem.data("duplexObserve") !== false) {
|
3039
3197
|
evaluator(lastValue)
|
3040
3198
|
callback.call(element, lastValue)
|
3041
|
-
if ($elem.data("duplex-focus")) {
|
3042
|
-
avalon.nextTick(function () {
|
3043
|
-
element.focus()
|
3044
|
-
})
|
3045
|
-
}
|
3046
3199
|
}
|
3047
3200
|
}
|
3048
3201
|
//当model变化时,它就会改变value的值
|
3049
|
-
data.handler = function
|
3202
|
+
data.handler = function() {
|
3050
3203
|
var val = data.pipe(evaluator(), data, "set") + ""
|
3051
3204
|
if (val !== element.oldValue) {
|
3052
|
-
element.value = val
|
3205
|
+
element.value = element.oldValue = val
|
3053
3206
|
}
|
3054
3207
|
}
|
3055
3208
|
if (data.isChecked || $type === "radio") {
|
3056
|
-
updateVModel = function
|
3057
|
-
if ($elem.data("
|
3209
|
+
updateVModel = function() {
|
3210
|
+
if ($elem.data("duplexObserve") !== false) {
|
3058
3211
|
var lastValue = data.pipe(element.value, data, "get")
|
3059
3212
|
evaluator(lastValue)
|
3060
3213
|
callback.call(element, lastValue)
|
3061
3214
|
}
|
3062
3215
|
}
|
3063
|
-
data.handler = function
|
3216
|
+
data.handler = function() {
|
3064
3217
|
var val = evaluator()
|
3065
|
-
var checked = data.isChecked ? !!val : val + "" === element.value
|
3218
|
+
var checked = data.isChecked ? !! val : val + "" === element.value
|
3066
3219
|
element.checked = element.oldValue = checked
|
3067
3220
|
}
|
3068
3221
|
bound("click", updateVModel)
|
3069
3222
|
} else if ($type === "checkbox") {
|
3070
|
-
updateVModel = function
|
3071
|
-
if ($elem.data("
|
3223
|
+
updateVModel = function() {
|
3224
|
+
if ($elem.data("duplexObserve") !== false) {
|
3072
3225
|
var method = element.checked ? "ensure" : "remove"
|
3073
3226
|
var array = evaluator()
|
3074
3227
|
if (!Array.isArray(array)) {
|
@@ -3079,7 +3232,7 @@ duplexBinding.INPUT = function (element, evaluator, data) {
|
|
3079
3232
|
callback.call(element, array)
|
3080
3233
|
}
|
3081
3234
|
}
|
3082
|
-
data.handler = function
|
3235
|
+
data.handler = function() {
|
3083
3236
|
var array = [].concat(evaluator()) //强制转换为数组
|
3084
3237
|
element.checked = array.indexOf(data.pipe(element.value, data, "get")) > -1
|
3085
3238
|
}
|
@@ -3089,7 +3242,7 @@ duplexBinding.INPUT = function (element, evaluator, data) {
|
|
3089
3242
|
if (element.attributes["data-event"]) {
|
3090
3243
|
log("data-event指令已经废弃,请改用data-duplex-event")
|
3091
3244
|
}
|
3092
|
-
events.replace(rword, function
|
3245
|
+
events.replace(rword, function(name) {
|
3093
3246
|
switch (name) {
|
3094
3247
|
case "input":
|
3095
3248
|
bound("input", updateVModel)
|
@@ -3104,14 +3257,14 @@ duplexBinding.INPUT = function (element, evaluator, data) {
|
|
3104
3257
|
break
|
3105
3258
|
}
|
3106
3259
|
})
|
3107
|
-
bound("focus", function
|
3260
|
+
bound("focus", function() {
|
3108
3261
|
element.msFocus = true
|
3109
3262
|
})
|
3110
|
-
bound("blur", function
|
3263
|
+
bound("blur", function() {
|
3111
3264
|
element.msFocus = false
|
3112
3265
|
})
|
3113
3266
|
if (rmsinput.test($type)) {
|
3114
|
-
watchValueInTimer(function
|
3267
|
+
watchValueInTimer(function() {
|
3115
3268
|
if (root.contains(element)) {
|
3116
3269
|
if (!element.msFocus && element.oldValue !== element.value) {
|
3117
3270
|
updateVModel()
|
@@ -3126,28 +3279,29 @@ duplexBinding.INPUT = function (element, evaluator, data) {
|
|
3126
3279
|
}
|
3127
3280
|
|
3128
3281
|
element.oldValue = element.value
|
3129
|
-
|
3282
|
+
avalon.injectBinding(data)
|
3130
3283
|
callback.call(element, element.value)
|
3131
3284
|
}
|
3132
3285
|
duplexBinding.TEXTAREA = duplexBinding.INPUT
|
3133
3286
|
duplexBinding.SELECT = function(element, evaluator, data) {
|
3134
3287
|
var $elem = avalon(element)
|
3135
|
-
|
3136
|
-
|
3137
|
-
|
3138
|
-
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3142
|
-
|
3143
|
-
|
3144
|
-
|
3145
|
-
|
3146
|
-
|
3288
|
+
|
3289
|
+
function updateVModel() {
|
3290
|
+
if ($elem.data("duplexObserve") !== false) {
|
3291
|
+
var val = $elem.val() //字符串或字符串数组
|
3292
|
+
if (Array.isArray(val)) {
|
3293
|
+
val = val.map(function(v) {
|
3294
|
+
return data.pipe(v, data, "get")
|
3295
|
+
})
|
3296
|
+
} else {
|
3297
|
+
val = data.pipe(val, data, "get")
|
3298
|
+
}
|
3299
|
+
if (val + "" !== element.oldValue) {
|
3300
|
+
evaluator(val)
|
3301
|
+
}
|
3302
|
+
data.changed.call(element, val, data)
|
3147
3303
|
}
|
3148
|
-
data.changed.call(element, val, data)
|
3149
3304
|
}
|
3150
|
-
}
|
3151
3305
|
data.handler = function() {
|
3152
3306
|
var val = evaluator()
|
3153
3307
|
val = val && val.$model || val
|
@@ -3168,74 +3322,77 @@ duplexBinding.SELECT = function(element, evaluator, data) {
|
|
3168
3322
|
}
|
3169
3323
|
}
|
3170
3324
|
data.bound("change", updateVModel)
|
3171
|
-
|
3172
|
-
|
3325
|
+
element.msCallback = function() {
|
3326
|
+
avalon.injectBinding(data)
|
3173
3327
|
data.changed.call(element, evaluator(), data)
|
3174
|
-
}
|
3328
|
+
}
|
3175
3329
|
}
|
3176
|
-
|
3177
|
-
|
3178
3330
|
// bindingHandlers.html 定义在if.js
|
3179
|
-
bindingExecutors.html = function(val, elem, data) {
|
3180
|
-
|
3181
|
-
var isHtmlFilter = "group" in data
|
3331
|
+
bindingExecutors.html = function (val, elem, data) {
|
3332
|
+
var isHtmlFilter = elem.nodeType !== 1
|
3182
3333
|
var parent = isHtmlFilter ? elem.parentNode : elem
|
3183
3334
|
if (!parent)
|
3184
3335
|
return
|
3185
|
-
|
3186
|
-
|
3336
|
+
val = val == null ? "" : val
|
3337
|
+
if (data.oldText !== val) {
|
3338
|
+
data.oldText = val
|
3339
|
+
} else {
|
3340
|
+
return
|
3341
|
+
}
|
3342
|
+
if (elem.nodeType === 3) {
|
3343
|
+
var signature = generateID("html")
|
3344
|
+
parent.insertBefore(DOC.createComment(signature), elem)
|
3345
|
+
data.element = DOC.createComment(signature + ":end")
|
3346
|
+
parent.replaceChild(data.element, elem)
|
3347
|
+
elem = data.element
|
3348
|
+
}
|
3349
|
+
if (typeof val !== "object") {//string, number, boolean
|
3350
|
+
var fragment = avalon.parseHTML(String(val))
|
3351
|
+
} else if (val.nodeType === 11) { //将val转换为文档碎片
|
3352
|
+
fragment = val
|
3187
3353
|
} else if (val.nodeType === 1 || val.item) {
|
3188
|
-
var nodes = val.nodeType === 1 ? val.childNodes : val.item
|
3189
|
-
fragment =
|
3354
|
+
var nodes = val.nodeType === 1 ? val.childNodes : val.item
|
3355
|
+
fragment = avalonFragment.cloneNode(true)
|
3190
3356
|
while (nodes[0]) {
|
3191
3357
|
fragment.appendChild(nodes[0])
|
3192
3358
|
}
|
3193
|
-
} else {
|
3194
|
-
fragment = avalon.parseHTML(val)
|
3195
3359
|
}
|
3360
|
+
|
3361
|
+
nodes = avalon.slice(fragment.childNodes)
|
3196
3362
|
//插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空
|
3197
|
-
var comment = DOC.createComment("ms-html")
|
3198
3363
|
if (isHtmlFilter) {
|
3199
|
-
|
3200
|
-
|
3201
|
-
|
3202
|
-
|
3203
|
-
|
3364
|
+
var endValue = elem.nodeValue.slice(0, -4)
|
3365
|
+
while (true) {
|
3366
|
+
var node = elem.previousSibling
|
3367
|
+
if (!node || node.nodeType === 8 && node.nodeValue === endValue) {
|
3368
|
+
break
|
3369
|
+
} else {
|
3204
3370
|
parent.removeChild(node)
|
3205
|
-
i++
|
3206
3371
|
}
|
3207
3372
|
}
|
3208
|
-
parent.
|
3209
|
-
data.element = comment //防止被CG
|
3373
|
+
parent.insertBefore(fragment, elem)
|
3210
3374
|
} else {
|
3211
|
-
avalon.clearHTML(
|
3212
|
-
}
|
3213
|
-
if (isHtmlFilter) {
|
3214
|
-
data.group = fragment.childNodes.length || 1
|
3215
|
-
}
|
3216
|
-
nodes = avalon.slice(fragment.childNodes)
|
3217
|
-
if (nodes[0]) {
|
3218
|
-
if (comment.parentNode)
|
3219
|
-
comment.parentNode.replaceChild(fragment, comment)
|
3220
|
-
if (isHtmlFilter) {
|
3221
|
-
data.element = nodes[0]
|
3222
|
-
}
|
3375
|
+
avalon.clearHTML(elem).appendChild(fragment)
|
3223
3376
|
}
|
3224
3377
|
scanNodeArray(nodes, data.vmodels)
|
3225
3378
|
}
|
3226
|
-
|
3227
3379
|
bindingHandlers["if"] =
|
3228
|
-
|
3229
|
-
|
3230
|
-
|
3231
|
-
|
3232
|
-
|
3233
|
-
|
3380
|
+
bindingHandlers.data =
|
3381
|
+
bindingHandlers.text =
|
3382
|
+
bindingHandlers.html =
|
3383
|
+
function(data, vmodels) {
|
3384
|
+
parseExprProxy(data.value, vmodels, data)
|
3385
|
+
}
|
3234
3386
|
|
3235
3387
|
bindingExecutors["if"] = function(val, elem, data) {
|
3388
|
+
try {
|
3389
|
+
if(!elem.parentNode) return
|
3390
|
+
} catch(e) {return}
|
3236
3391
|
if (val) { //插回DOM树
|
3237
3392
|
if (elem.nodeType === 8) {
|
3238
3393
|
elem.parentNode.replaceChild(data.template, elem)
|
3394
|
+
elem.ifRemove = null
|
3395
|
+
// animate.enter(data.template, elem.parentNode)
|
3239
3396
|
elem = data.element = data.template //这时可能为null
|
3240
3397
|
}
|
3241
3398
|
if (elem.getAttribute(data.name)) {
|
@@ -3247,6 +3404,8 @@ bindingExecutors["if"] = function(val, elem, data) {
|
|
3247
3404
|
if (elem.nodeType === 1) {
|
3248
3405
|
var node = data.element = DOC.createComment("ms-if")
|
3249
3406
|
elem.parentNode.replaceChild(node, elem)
|
3407
|
+
elem.ifRemove = node
|
3408
|
+
// animate.leave(elem, node.parentNode, node)
|
3250
3409
|
data.template = elem //元素节点
|
3251
3410
|
ifGroup.appendChild(elem)
|
3252
3411
|
data.rollback = function() {
|
@@ -3257,8 +3416,6 @@ bindingExecutors["if"] = function(val, elem, data) {
|
|
3257
3416
|
}
|
3258
3417
|
}
|
3259
3418
|
}
|
3260
|
-
|
3261
|
-
|
3262
3419
|
//ms-important绑定已经在scanTag 方法中实现
|
3263
3420
|
//ms-include绑定已由ms-attr绑定实现
|
3264
3421
|
|
@@ -3302,11 +3459,9 @@ bindingExecutors.on = function(callback, elem, data) {
|
|
3302
3459
|
}
|
3303
3460
|
}
|
3304
3461
|
}
|
3305
|
-
|
3306
|
-
|
3307
|
-
bindingHandlers.repeat = function(data, vmodels) {
|
3462
|
+
bindingHandlers.repeat = function (data, vmodels) {
|
3308
3463
|
var type = data.type
|
3309
|
-
parseExprProxy(data.value, vmodels, data,
|
3464
|
+
parseExprProxy(data.value, vmodels, data, 1)
|
3310
3465
|
data.proxies = []
|
3311
3466
|
var freturn = false
|
3312
3467
|
try {
|
@@ -3315,11 +3470,12 @@ bindingHandlers.repeat = function(data, vmodels) {
|
|
3315
3470
|
if (xtype !== "object" && xtype !== "array") {
|
3316
3471
|
freturn = true
|
3317
3472
|
avalon.log("warning:" + data.value + "只能是对象或数组")
|
3473
|
+
} else {
|
3474
|
+
data.xtype = xtype
|
3318
3475
|
}
|
3319
3476
|
} catch (e) {
|
3320
3477
|
freturn = true
|
3321
3478
|
}
|
3322
|
-
|
3323
3479
|
var arr = data.value.split(".") || []
|
3324
3480
|
if (arr.length > 1) {
|
3325
3481
|
arr.pop()
|
@@ -3333,41 +3489,43 @@ bindingHandlers.repeat = function(data, vmodels) {
|
|
3333
3489
|
}
|
3334
3490
|
}
|
3335
3491
|
}
|
3492
|
+
|
3336
3493
|
var elem = data.element
|
3337
|
-
elem.
|
3338
|
-
|
3339
|
-
|
3340
|
-
|
3341
|
-
|
3342
|
-
|
3343
|
-
|
3344
|
-
|
3345
|
-
|
3346
|
-
|
3347
|
-
|
3348
|
-
|
3349
|
-
|
3350
|
-
|
3351
|
-
|
3352
|
-
|
3353
|
-
|
3354
|
-
|
3355
|
-
|
3356
|
-
|
3357
|
-
|
3358
|
-
|
3359
|
-
|
3360
|
-
|
3361
|
-
|
3362
|
-
|
3363
|
-
|
3364
|
-
|
3365
|
-
|
3494
|
+
if (elem.nodeType === 1) {
|
3495
|
+
elem.removeAttribute(data.name)
|
3496
|
+
data.sortedCallback = getBindingCallback(elem, "data-with-sorted", vmodels)
|
3497
|
+
data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels)
|
3498
|
+
var signature = generateID(type)
|
3499
|
+
var start = DOC.createComment(signature)
|
3500
|
+
var end = DOC.createComment(signature + ":end")
|
3501
|
+
data.signature = signature
|
3502
|
+
data.template = avalonFragment.cloneNode(false)
|
3503
|
+
if (type === "repeat") {
|
3504
|
+
var parent = elem.parentNode
|
3505
|
+
parent.replaceChild(end, elem)
|
3506
|
+
parent.insertBefore(start, end)
|
3507
|
+
data.template.appendChild(elem)
|
3508
|
+
} else {
|
3509
|
+
while (elem.firstChild) {
|
3510
|
+
data.template.appendChild(elem.firstChild)
|
3511
|
+
}
|
3512
|
+
elem.appendChild(start)
|
3513
|
+
elem.appendChild(end)
|
3514
|
+
}
|
3515
|
+
data.element = end
|
3516
|
+
data.handler = bindingExecutors.repeat
|
3517
|
+
data.rollback = function () {
|
3518
|
+
var elem = data.element
|
3519
|
+
if (!elem)
|
3520
|
+
return
|
3521
|
+
data.handler("clear")
|
3522
|
+
}
|
3366
3523
|
}
|
3524
|
+
|
3367
3525
|
if (freturn) {
|
3368
3526
|
return
|
3369
3527
|
}
|
3370
|
-
|
3528
|
+
|
3371
3529
|
data.$outer = {}
|
3372
3530
|
var check0 = "$key"
|
3373
3531
|
var check1 = "$val"
|
@@ -3375,6 +3533,7 @@ bindingHandlers.repeat = function(data, vmodels) {
|
|
3375
3533
|
check0 = "$first"
|
3376
3534
|
check1 = "$last"
|
3377
3535
|
}
|
3536
|
+
|
3378
3537
|
for (i = 0; v = vmodels[i++]; ) {
|
3379
3538
|
if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) {
|
3380
3539
|
data.$outer = v
|
@@ -3383,81 +3542,101 @@ bindingHandlers.repeat = function(data, vmodels) {
|
|
3383
3542
|
}
|
3384
3543
|
var $events = $repeat.$events
|
3385
3544
|
var $list = ($events || {})[subscribers]
|
3386
|
-
|
3387
|
-
addSubscribers(data, $list)
|
3388
|
-
}
|
3545
|
+
injectDependency($list, data)
|
3389
3546
|
if (xtype === "object") {
|
3390
|
-
data
|
3391
|
-
var pool = !$events ? {} : $events.$withProxyPool || ($events.$withProxyPool = {})
|
3392
|
-
data.handler("append", $repeat, pool)
|
3547
|
+
data.handler("append")
|
3393
3548
|
} else if ($repeat.length) {
|
3394
3549
|
data.handler("add", 0, $repeat.length)
|
3395
3550
|
}
|
3396
3551
|
}
|
3397
3552
|
|
3398
|
-
bindingExecutors.repeat = function(method, pos, el) {
|
3553
|
+
bindingExecutors.repeat = function (method, pos, el) {
|
3554
|
+
var data = this
|
3555
|
+
if (!method && data.xtype) {
|
3556
|
+
var old = data.$repeat
|
3557
|
+
var neo = data.evaluator.apply(0, data.args || [])
|
3558
|
+
|
3559
|
+
if (data.xtype === "array") {
|
3560
|
+
if (old.length === neo.length) {
|
3561
|
+
return
|
3562
|
+
}
|
3563
|
+
method = "add"
|
3564
|
+
pos = 0
|
3565
|
+
data.$repeat = neo
|
3566
|
+
el = neo.length
|
3567
|
+
} else {
|
3568
|
+
if (keysVM(old).join(";;") === keysVM(neo).join(";;")) {
|
3569
|
+
return
|
3570
|
+
}
|
3571
|
+
method = "append"
|
3572
|
+
data.$repeat = neo
|
3573
|
+
}
|
3574
|
+
}
|
3399
3575
|
if (method) {
|
3400
|
-
var
|
3576
|
+
var start, fragment
|
3401
3577
|
var end = data.element
|
3578
|
+
var comments = getComments(data)
|
3402
3579
|
var parent = end.parentNode
|
3403
3580
|
var proxies = data.proxies
|
3404
|
-
var transation =
|
3581
|
+
var transation = avalonFragment.cloneNode(false)
|
3405
3582
|
switch (method) {
|
3406
|
-
case "add": //在pos位置后添加el数组(pos
|
3583
|
+
case "add": //在pos位置后添加el数组(pos为插入位置,el为要插入的个数)
|
3407
3584
|
var n = pos + el
|
3408
|
-
var
|
3409
|
-
var last = array.length - 1
|
3410
|
-
var fragments = [], fragment
|
3411
|
-
var start = locateNode(data, pos)
|
3585
|
+
var fragments = []
|
3412
3586
|
for (var i = pos; i < n; i++) {
|
3413
3587
|
var proxy = eachProxyAgent(i, data)
|
3414
3588
|
proxies.splice(i, 0, proxy)
|
3415
3589
|
shimController(data, transation, proxy, fragments)
|
3416
3590
|
}
|
3417
|
-
parent.insertBefore(transation,
|
3591
|
+
parent.insertBefore(transation, comments[pos] || end)
|
3418
3592
|
for (i = 0; fragment = fragments[i++]; ) {
|
3419
3593
|
scanNodeArray(fragment.nodes, fragment.vmodels)
|
3420
3594
|
fragment.nodes = fragment.vmodels = null
|
3421
3595
|
}
|
3596
|
+
|
3422
3597
|
break
|
3423
3598
|
case "del": //将pos后的el个元素删掉(pos, el都是数字)
|
3424
|
-
|
3425
|
-
end = locateNode(data, pos + el)
|
3426
|
-
sweepNodes(start, end)
|
3599
|
+
sweepNodes(comments[pos], comments[pos + el] || end)
|
3427
3600
|
var removed = proxies.splice(pos, el)
|
3428
3601
|
recycleProxies(removed, "each")
|
3429
3602
|
break
|
3430
3603
|
case "clear":
|
3431
|
-
|
3432
|
-
if (
|
3433
|
-
start = check.$stamp || check
|
3604
|
+
start = comments[0]
|
3605
|
+
if (start) {
|
3434
3606
|
sweepNodes(start, end)
|
3607
|
+
if (data.xtype === "object") {
|
3608
|
+
parent.insertBefore(start, end)
|
3609
|
+
}else{
|
3610
|
+
recycleProxies(proxies, "each")
|
3611
|
+
}
|
3435
3612
|
}
|
3436
|
-
recycleProxies(proxies, "each")
|
3437
3613
|
break
|
3438
3614
|
case "move":
|
3439
|
-
start =
|
3440
|
-
|
3441
|
-
|
3442
|
-
|
3443
|
-
|
3444
|
-
|
3445
|
-
|
3446
|
-
|
3447
|
-
|
3448
|
-
|
3449
|
-
|
3450
|
-
|
3451
|
-
|
3452
|
-
|
3453
|
-
|
3454
|
-
|
3615
|
+
start = comments[0]
|
3616
|
+
if (start) {
|
3617
|
+
var signature = start.nodeValue
|
3618
|
+
var rooms = []
|
3619
|
+
var room = [],
|
3620
|
+
node
|
3621
|
+
sweepNodes(start, end, function () {
|
3622
|
+
room.unshift(this)
|
3623
|
+
if (this.nodeValue === signature) {
|
3624
|
+
rooms.unshift(room)
|
3625
|
+
room = []
|
3626
|
+
}
|
3627
|
+
})
|
3628
|
+
sortByIndex(rooms, pos)
|
3629
|
+
sortByIndex(proxies, pos)
|
3630
|
+
while (room = rooms.shift()) {
|
3631
|
+
while (node = room.shift()) {
|
3632
|
+
transation.appendChild(node)
|
3633
|
+
}
|
3455
3634
|
}
|
3635
|
+
parent.insertBefore(transation, end)
|
3456
3636
|
}
|
3457
|
-
parent.insertBefore(transation, end)
|
3458
3637
|
break
|
3459
3638
|
case "index": //将proxies中的第pos个起的所有元素重新索引
|
3460
|
-
last = proxies.length - 1
|
3639
|
+
var last = proxies.length - 1
|
3461
3640
|
for (; el = proxies[pos]; pos++) {
|
3462
3641
|
el.$index = pos
|
3463
3642
|
el.$first = pos === 0
|
@@ -3467,15 +3646,23 @@ bindingExecutors.repeat = function(method, pos, el) {
|
|
3467
3646
|
case "set": //将proxies中的第pos个元素的VM设置为el(pos为数字,el任意)
|
3468
3647
|
proxy = proxies[pos]
|
3469
3648
|
if (proxy) {
|
3470
|
-
|
3649
|
+
fireDependencies(proxy.$events[data.param || "el"])
|
3471
3650
|
}
|
3472
|
-
|
3473
|
-
case "append":
|
3474
|
-
var
|
3651
|
+
break
|
3652
|
+
case "append":
|
3653
|
+
var object = data.$repeat //原来第2参数, 被循环对象
|
3654
|
+
var pool = Array.isArray(proxies) ||!proxies ? {}: proxies //代理对象组成的hash
|
3655
|
+
data.proxies = pool
|
3475
3656
|
var keys = []
|
3476
3657
|
fragments = []
|
3477
|
-
for (var key in
|
3478
|
-
if (
|
3658
|
+
for (var key in pool) {
|
3659
|
+
if (!object.hasOwnProperty(key)) {
|
3660
|
+
proxyRecycler(pool[key], withProxyPool) //去掉之前的代理VM
|
3661
|
+
delete(pool[key])
|
3662
|
+
}
|
3663
|
+
}
|
3664
|
+
for (key in object) { //得到所有键名
|
3665
|
+
if (object.hasOwnProperty(key) && key !== "hasOwnProperty") {
|
3479
3666
|
keys.push(key)
|
3480
3667
|
}
|
3481
3668
|
}
|
@@ -3487,14 +3674,11 @@ bindingExecutors.repeat = function(method, pos, el) {
|
|
3487
3674
|
}
|
3488
3675
|
for (i = 0; key = keys[i++]; ) {
|
3489
3676
|
if (key !== "hasOwnProperty") {
|
3490
|
-
|
3491
|
-
pool[key] = withProxyAgent(key, data)
|
3492
|
-
}
|
3677
|
+
pool[key] = withProxyAgent(pool[key], key, data)
|
3493
3678
|
shimController(data, transation, pool[key], fragments)
|
3494
3679
|
}
|
3495
3680
|
}
|
3496
|
-
|
3497
|
-
parent.insertBefore(comment, end)
|
3681
|
+
|
3498
3682
|
parent.insertBefore(transation, end)
|
3499
3683
|
for (i = 0; fragment = fragments[i++]; ) {
|
3500
3684
|
scanNodeArray(fragment.nodes, fragment.vmodels)
|
@@ -3502,29 +3686,26 @@ bindingExecutors.repeat = function(method, pos, el) {
|
|
3502
3686
|
}
|
3503
3687
|
break
|
3504
3688
|
}
|
3689
|
+
if (!data.$repeat || data.$repeat.hasOwnProperty("$lock")) //IE6-8 VBScript对象会报错, 有时候data.$repeat不存在
|
3690
|
+
return
|
3505
3691
|
if (method === "clear")
|
3506
3692
|
method = "del"
|
3507
3693
|
var callback = data.renderedCallback || noop,
|
3508
3694
|
args = arguments
|
3509
|
-
|
3510
|
-
|
3511
|
-
|
3512
|
-
|
3513
|
-
}
|
3514
|
-
}, NaN)
|
3695
|
+
if (parent.oldValue && parent.tagName === "SELECT") { //fix #503
|
3696
|
+
avalon(parent).val(parent.oldValue.split(","))
|
3697
|
+
}
|
3698
|
+
callback.apply(parent, args)
|
3515
3699
|
}
|
3516
3700
|
}
|
3517
|
-
|
3518
|
-
"with,each".replace(rword, function(name) {
|
3701
|
+
"with,each".replace(rword, function (name) {
|
3519
3702
|
bindingHandlers[name] = bindingHandlers.repeat
|
3520
3703
|
})
|
3521
3704
|
|
3522
3705
|
function shimController(data, transation, proxy, fragments) {
|
3523
3706
|
var content = data.template.cloneNode(true)
|
3524
3707
|
var nodes = avalon.slice(content.childNodes)
|
3525
|
-
|
3526
|
-
content.insertBefore(proxy.$stamp, content.firstChild)
|
3527
|
-
}
|
3708
|
+
content.insertBefore(DOC.createComment(data.signature), content.firstChild)
|
3528
3709
|
transation.appendChild(content)
|
3529
3710
|
var nv = [proxy].concat(data.vmodels)
|
3530
3711
|
var fragment = {
|
@@ -3534,11 +3715,21 @@ function shimController(data, transation, proxy, fragments) {
|
|
3534
3715
|
fragments.push(fragment)
|
3535
3716
|
}
|
3536
3717
|
|
3537
|
-
function
|
3538
|
-
var
|
3539
|
-
|
3718
|
+
function getComments(data) {
|
3719
|
+
var ret = []
|
3720
|
+
var nodes = data.element.parentNode.childNodes
|
3721
|
+
for (var i = 0, node; node = nodes[i++]; ) {
|
3722
|
+
if (node.nodeValue === data.signature) {
|
3723
|
+
ret.push(node)
|
3724
|
+
} else if (node.nodeValue === data.signature + ":end") {
|
3725
|
+
break
|
3726
|
+
}
|
3727
|
+
}
|
3728
|
+
return ret
|
3540
3729
|
}
|
3541
3730
|
|
3731
|
+
|
3732
|
+
//移除掉start与end之间的节点(保留end)
|
3542
3733
|
function sweepNodes(start, end, callback) {
|
3543
3734
|
while (true) {
|
3544
3735
|
var node = end.previousSibling
|
@@ -3555,24 +3746,89 @@ function sweepNodes(start, end, callback) {
|
|
3555
3746
|
// 为ms-each,ms-with, ms-repeat会创建一个代理VM,
|
3556
3747
|
// 通过它们保持一个下上文,让用户能调用$index,$first,$last,$remove,$key,$val,$outer等属性与方法
|
3557
3748
|
// 所有代理VM的产生,消费,收集,存放通过xxxProxyFactory,xxxProxyAgent, recycleProxies,xxxProxyPool实现
|
3558
|
-
var eachProxyPool = []
|
3559
3749
|
var withProxyPool = []
|
3750
|
+
function withProxyFactory() {
|
3751
|
+
var proxy = modelFactory({
|
3752
|
+
$key: "",
|
3753
|
+
$outer: {},
|
3754
|
+
$host: {},
|
3755
|
+
$val: {
|
3756
|
+
get: function () {
|
3757
|
+
return this.$host[this.$key]
|
3758
|
+
},
|
3759
|
+
set: function (val) {
|
3760
|
+
this.$host[this.$key] = val
|
3761
|
+
}
|
3762
|
+
}
|
3763
|
+
}, {
|
3764
|
+
$val: 1
|
3765
|
+
})
|
3766
|
+
proxy.$id = generateID("$proxy$with")
|
3767
|
+
return proxy
|
3768
|
+
}
|
3769
|
+
|
3770
|
+
function withProxyAgent(proxy, key, data) {
|
3771
|
+
proxy = proxy || withProxyPool.pop()
|
3772
|
+
if (!proxy) {
|
3773
|
+
proxy = withProxyFactory()
|
3774
|
+
} else {
|
3775
|
+
proxy.$reinitialize()
|
3776
|
+
}
|
3777
|
+
var host = data.$repeat
|
3778
|
+
proxy.$key = key
|
3779
|
+
|
3780
|
+
proxy.$host = host
|
3781
|
+
proxy.$outer = data.$outer
|
3782
|
+
if (host.$events) {
|
3783
|
+
proxy.$events.$val = host.$events[key]
|
3784
|
+
} else {
|
3785
|
+
proxy.$events = {}
|
3786
|
+
}
|
3787
|
+
return proxy
|
3788
|
+
}
|
3789
|
+
|
3790
|
+
|
3791
|
+
function recycleProxies(proxies) {
|
3792
|
+
eachProxyRecycler(proxies)
|
3793
|
+
}
|
3794
|
+
function eachProxyRecycler(proxies) {
|
3795
|
+
proxies.forEach(function (proxy) {
|
3796
|
+
proxyRecycler(proxy, eachProxyPool)
|
3797
|
+
})
|
3798
|
+
proxies.length = 0
|
3799
|
+
}
|
3800
|
+
|
3801
|
+
|
3802
|
+
var eachProxyPool = []
|
3560
3803
|
function eachProxyFactory(name) {
|
3561
3804
|
var source = {
|
3562
3805
|
$host: [],
|
3563
3806
|
$outer: {},
|
3564
|
-
$stamp: 1,
|
3565
3807
|
$index: 0,
|
3566
3808
|
$first: false,
|
3567
3809
|
$last: false,
|
3568
3810
|
$remove: avalon.noop
|
3569
3811
|
}
|
3570
3812
|
source[name] = {
|
3571
|
-
get: function() {
|
3572
|
-
|
3813
|
+
get: function () {
|
3814
|
+
var e = this.$events
|
3815
|
+
var array = e.$index
|
3816
|
+
e.$index = e[name] //#817 通过$index为el收集依赖
|
3817
|
+
try {
|
3818
|
+
return this.$host[this.$index]
|
3819
|
+
} finally {
|
3820
|
+
e.$index = array
|
3821
|
+
}
|
3573
3822
|
},
|
3574
|
-
set: function(val) {
|
3575
|
-
|
3823
|
+
set: function (val) {
|
3824
|
+
try {
|
3825
|
+
var e = this.$events
|
3826
|
+
var array = e.$index
|
3827
|
+
e.$index = []
|
3828
|
+
this.$host.set(this.$index, val)
|
3829
|
+
} finally {
|
3830
|
+
e.$index = array
|
3831
|
+
}
|
3576
3832
|
}
|
3577
3833
|
}
|
3578
3834
|
var second = {
|
@@ -3581,14 +3837,13 @@ function eachProxyFactory(name) {
|
|
3581
3837
|
$index: 1
|
3582
3838
|
}
|
3583
3839
|
var proxy = modelFactory(source, second)
|
3584
|
-
var e = proxy.$events
|
3585
|
-
e[name] = e.$first = e.$last = e.$index
|
3586
3840
|
proxy.$id = generateID("$proxy$each")
|
3587
3841
|
return proxy
|
3588
3842
|
}
|
3589
3843
|
|
3590
3844
|
function eachProxyAgent(index, data) {
|
3591
|
-
var param = data.param || "el",
|
3845
|
+
var param = data.param || "el",
|
3846
|
+
proxy
|
3592
3847
|
for (var i = 0, n = eachProxyPool.length; i < n; i++) {
|
3593
3848
|
var candidate = eachProxyPool[i]
|
3594
3849
|
if (candidate && candidate.hasOwnProperty(param)) {
|
@@ -3606,93 +3861,45 @@ function eachProxyAgent(index, data) {
|
|
3606
3861
|
proxy.$last = index === last
|
3607
3862
|
proxy.$host = host
|
3608
3863
|
proxy.$outer = data.$outer
|
3609
|
-
proxy.$
|
3610
|
-
proxy.$remove = function() {
|
3864
|
+
proxy.$remove = function () {
|
3611
3865
|
return host.removeAt(proxy.$index)
|
3612
3866
|
}
|
3613
3867
|
return proxy
|
3614
3868
|
}
|
3615
3869
|
|
3616
|
-
function withProxyFactory() {
|
3617
|
-
var proxy = modelFactory({
|
3618
|
-
$key: "",
|
3619
|
-
$outer: {},
|
3620
|
-
$host: {},
|
3621
|
-
$val: {
|
3622
|
-
get: function() {
|
3623
|
-
return this.$host[this.$key]
|
3624
|
-
},
|
3625
|
-
set: function(val) {
|
3626
|
-
this.$host[this.$key] = val
|
3627
|
-
}
|
3628
|
-
}
|
3629
|
-
}, {
|
3630
|
-
$val: 1
|
3631
|
-
})
|
3632
|
-
proxy.$id = generateID("$proxy$with")
|
3633
|
-
return proxy
|
3634
|
-
}
|
3635
3870
|
|
3636
|
-
function
|
3637
|
-
var
|
3638
|
-
|
3639
|
-
|
3871
|
+
function proxyRecycler(proxy, proxyPool) {
|
3872
|
+
for (var i in proxy.$events) {
|
3873
|
+
var arr = proxy.$events[i]
|
3874
|
+
if (Array.isArray(arr)) {
|
3875
|
+
arr.forEach(function (data) {
|
3876
|
+
if (typeof data === "object")
|
3877
|
+
disposeData(data)
|
3878
|
+
})// jshint ignore:line
|
3879
|
+
arr.length = 0
|
3880
|
+
}
|
3640
3881
|
}
|
3641
|
-
|
3642
|
-
proxy
|
3643
|
-
|
3644
|
-
proxy.$outer = data.$outer
|
3645
|
-
if (host.$events) {
|
3646
|
-
proxy.$events.$val = host.$events[key]
|
3647
|
-
} else {
|
3648
|
-
proxy.$events = {}
|
3882
|
+
proxy.$host = proxy.$outer = {}
|
3883
|
+
if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
|
3884
|
+
proxyPool.pop()
|
3649
3885
|
}
|
3650
|
-
return proxy
|
3651
|
-
}
|
3652
|
-
|
3653
|
-
function recycleProxies(proxies, type) {
|
3654
|
-
var proxyPool = type === "each" ? eachProxyPool : withProxyPool
|
3655
|
-
avalon.each(proxies, function(key, proxy) {
|
3656
|
-
if (proxy.$events) {
|
3657
|
-
for (var i in proxy.$events) {
|
3658
|
-
if (Array.isArray(proxy.$events[i])) {
|
3659
|
-
proxy.$events[i].forEach(function(data) {
|
3660
|
-
if (typeof data === "object")
|
3661
|
-
disposeData(data)
|
3662
|
-
})// jshint ignore:line
|
3663
|
-
proxy.$events[i].length = 0
|
3664
|
-
}
|
3665
|
-
}
|
3666
|
-
proxy.$host = proxy.$outer = {}
|
3667
|
-
if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
|
3668
|
-
proxyPool.pop()
|
3669
|
-
}
|
3670
|
-
}
|
3671
|
-
})
|
3672
|
-
if (type === "each")
|
3673
|
-
proxies.length = 0
|
3674
3886
|
}
|
3675
3887
|
|
3676
|
-
|
3677
|
-
|
3678
|
-
|
3679
3888
|
/*********************************************************************
|
3680
3889
|
* 各种指令 *
|
3681
3890
|
**********************************************************************/
|
3682
3891
|
//ms-skip绑定已经在scanTag 方法中实现
|
3683
3892
|
// bindingHandlers.text 定义在if.js
|
3684
3893
|
bindingExecutors.text = function(val, elem) {
|
3685
|
-
|
3686
|
-
|
3687
|
-
|
3688
|
-
|
3689
|
-
|
3690
|
-
|
3691
|
-
|
3692
|
-
|
3693
|
-
}
|
3894
|
+
val = val == null ? "" : val //不在页面上显示undefined null
|
3895
|
+
if (elem.nodeType === 3) { //绑定在文本节点上
|
3896
|
+
try { //IE对游离于DOM树外的节点赋值会报错
|
3897
|
+
elem.data = val
|
3898
|
+
} catch (e) {}
|
3899
|
+
} else { //绑定在特性节点上
|
3900
|
+
elem.textContent = val
|
3901
|
+
}
|
3694
3902
|
}
|
3695
|
-
|
3696
3903
|
function parseDisplay(nodeName, val) {
|
3697
3904
|
//用于取得此类标签的默认display值
|
3698
3905
|
var key = "_" + nodeName
|
@@ -3712,42 +3919,33 @@ function parseDisplay(nodeName, val) {
|
|
3712
3919
|
|
3713
3920
|
avalon.parseDisplay = parseDisplay
|
3714
3921
|
|
3715
|
-
bindingHandlers.visible = function(data, vmodels) {
|
3716
|
-
var elem = avalon(data.element)
|
3717
|
-
var display = elem.css("display")
|
3718
|
-
if (display === "none") {
|
3719
|
-
var style = elem[0].style
|
3720
|
-
var has = /visibility/i.test(style.cssText)
|
3721
|
-
var visible = elem.css("visibility")
|
3722
|
-
style.display = ""
|
3723
|
-
style.visibility = "hidden"
|
3724
|
-
display = elem.css("display")
|
3725
|
-
if (display === "none") {
|
3726
|
-
display = parseDisplay(elem[0].nodeName)
|
3727
|
-
}
|
3728
|
-
style.visibility = has ? visible : ""
|
3729
|
-
}
|
3730
|
-
data.display = display
|
3922
|
+
bindingHandlers.visible = function (data, vmodels) {
|
3731
3923
|
parseExprProxy(data.value, vmodels, data)
|
3732
3924
|
}
|
3733
3925
|
|
3734
|
-
bindingExecutors.visible = function(val, elem,
|
3735
|
-
|
3926
|
+
bindingExecutors.visible = function (val, elem, binding) {
|
3927
|
+
if (val) {
|
3928
|
+
elem.style.display = binding.display || ""
|
3929
|
+
if (avalon(elem).css("display") === "none") {
|
3930
|
+
elem.style.display = binding.display = parseDisplay(elem.nodeName)
|
3931
|
+
}
|
3932
|
+
} else {
|
3933
|
+
elem.style.display = "none"
|
3934
|
+
}
|
3736
3935
|
}
|
3737
|
-
|
3738
3936
|
bindingHandlers.widget = function(data, vmodels) {
|
3739
3937
|
var args = data.value.match(rword)
|
3740
3938
|
var elem = data.element
|
3741
3939
|
var widget = args[0]
|
3742
3940
|
var id = args[1]
|
3743
|
-
if (!id || id === "$") {//没有定义或为$时,取组件名+随机数
|
3941
|
+
if (!id || id === "$") { //没有定义或为$时,取组件名+随机数
|
3744
3942
|
id = generateID(widget)
|
3745
3943
|
}
|
3746
|
-
var optName = args[2] || widget//没有定义,取组件名
|
3944
|
+
var optName = args[2] || widget //没有定义,取组件名
|
3747
3945
|
var constructor = avalon.ui[widget]
|
3748
3946
|
if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
|
3749
3947
|
vmodels = elem.vmodels || vmodels
|
3750
|
-
for (var i = 0, v; v = vmodels[i++];
|
3948
|
+
for (var i = 0, v; v = vmodels[i++];) {
|
3751
3949
|
if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
|
3752
3950
|
var vmOptions = v[optName]
|
3753
3951
|
vmOptions = vmOptions.$model || vmOptions
|
@@ -3757,6 +3955,7 @@ bindingHandlers.widget = function(data, vmodels) {
|
|
3757
3955
|
if (vmOptions) {
|
3758
3956
|
var wid = vmOptions[widget + "Id"]
|
3759
3957
|
if (typeof wid === "string") {
|
3958
|
+
log("warning!不再支持" + widget + "Id")
|
3760
3959
|
id = wid
|
3761
3960
|
}
|
3762
3961
|
}
|
@@ -3772,27 +3971,26 @@ bindingHandlers.widget = function(data, vmodels) {
|
|
3772
3971
|
if (vmodel.$id) {
|
3773
3972
|
avalon.vmodels[id] = vmodel
|
3774
3973
|
createSignalTower(elem, vmodel)
|
3775
|
-
|
3974
|
+
try {
|
3776
3975
|
vmodel.$init(function() {
|
3777
3976
|
avalon.scan(elem, [vmodel].concat(vmodels))
|
3778
3977
|
if (typeof options.onInit === "function") {
|
3779
3978
|
options.onInit.call(elem, vmodel, options, vmodels)
|
3780
3979
|
}
|
3781
3980
|
})
|
3782
|
-
}
|
3981
|
+
} catch (e) {}
|
3783
3982
|
data.rollback = function() {
|
3784
3983
|
try {
|
3785
|
-
vmodel.widgetElement = null
|
3786
3984
|
vmodel.$remove()
|
3787
|
-
|
3788
|
-
}
|
3985
|
+
vmodel.widgetElement = null // 放到$remove后边
|
3986
|
+
} catch (e) {}
|
3789
3987
|
elem.msData = {}
|
3790
3988
|
delete avalon.vmodels[vmodel.$id]
|
3791
3989
|
}
|
3792
|
-
|
3990
|
+
injectDisposeQueue(data, widgetList)
|
3793
3991
|
if (window.chrome) {
|
3794
3992
|
elem.addEventListener("DOMNodeRemovedFromDocument", function() {
|
3795
|
-
setTimeout(
|
3993
|
+
setTimeout(rejectDisposeQueue)
|
3796
3994
|
})
|
3797
3995
|
}
|
3798
3996
|
} else {
|
@@ -3862,7 +4060,7 @@ var filters = avalon.filters = {
|
|
3862
4060
|
truncate: function(str, length, truncation) {
|
3863
4061
|
//length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串
|
3864
4062
|
length = length || 30
|
3865
|
-
truncation = truncation ===
|
4063
|
+
truncation = typeof truncation === "string" ? truncation : "..."
|
3866
4064
|
return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str)
|
3867
4065
|
},
|
3868
4066
|
$filter: function(val) {
|
@@ -4155,71 +4353,56 @@ new function() {// jshint ignore:line
|
|
4155
4353
|
/*********************************************************************
|
4156
4354
|
* END *
|
4157
4355
|
**********************************************************************/
|
4158
|
-
new function() {
|
4356
|
+
new function () {
|
4159
4357
|
avalon.config({
|
4160
4358
|
loader: false
|
4161
4359
|
})
|
4162
|
-
var fns = [],
|
4360
|
+
var fns = [], loaded = DOC.readyState === "complete", fn
|
4163
4361
|
function flush(f) {
|
4164
4362
|
loaded = 1
|
4165
4363
|
while (f = fns.shift())
|
4166
4364
|
f()
|
4167
4365
|
}
|
4168
|
-
|
4169
|
-
|
4170
|
-
|
4366
|
+
|
4367
|
+
avalon.bind(DOC, "DOMContentLoaded", fn = function () {
|
4368
|
+
avalon.unbind(DOC, "DOMContentLoaded", fn)
|
4369
|
+
flush()
|
4370
|
+
})
|
4371
|
+
|
4372
|
+
var id = setInterval(function () {
|
4373
|
+
if (document.readyState === "complete" && document.body) {
|
4374
|
+
clearInterval(id)
|
4171
4375
|
flush()
|
4172
|
-
}
|
4173
|
-
}
|
4174
|
-
|
4175
|
-
|
4176
|
-
clearInterval(id)
|
4177
|
-
flush()
|
4178
|
-
}
|
4179
|
-
}, 50)
|
4180
|
-
}
|
4181
|
-
avalon.ready = function(fn) {
|
4376
|
+
}
|
4377
|
+
}, 50)
|
4378
|
+
|
4379
|
+
avalon.ready = function (fn) {
|
4182
4380
|
loaded ? fn(avalon) : fns.push(fn)
|
4183
4381
|
}
|
4184
|
-
avalon.ready(function() {
|
4382
|
+
avalon.ready(function () {
|
4185
4383
|
avalon.scan(DOC.body)
|
4186
4384
|
})
|
4187
4385
|
}
|
4188
4386
|
|
4189
4387
|
new function() {// jshint ignore:line
|
4190
|
-
|
4388
|
+
var touchProxy = {}
|
4389
|
+
var IEtouch = navigator.pointerEnabled
|
4390
|
+
var IEMStouch = navigator.msPointerEnabled
|
4191
4391
|
var ua = navigator.userAgent
|
4192
4392
|
var isAndroid = ua.indexOf("Android") > 0
|
4193
|
-
var
|
4393
|
+
var isGoingtoFixTouchEndEvent = isAndroid && ua.match(/Firefox|Opera/gi)
|
4394
|
+
//合成做成触屏事件所需要的各种原生事件
|
4395
|
+
var touchNames = ["touchstart", "touchmove", "touchend", "touchcancel"]
|
4396
|
+
var touchTimeout = null
|
4397
|
+
var longTapTimeout = null
|
4398
|
+
var dragDistance = 30
|
4399
|
+
var clickDuration = 750 //小于750ms是点击,长于它是长按或拖动
|
4194
4400
|
var me = bindingHandlers.on
|
4195
|
-
var touchProxy = {}
|
4196
4401
|
|
4197
|
-
|
4198
|
-
var IE9_10touch = navigator.msPointerEnabled
|
4199
|
-
var w3ctouch = (function() {
|
4200
|
-
var supported = isIOS || false
|
4201
|
-
//http://stackoverflow.com/questions/5713393/creating-and-firing-touch-events-on-a-touch-enabled-browser
|
4202
|
-
try {
|
4203
|
-
var div = document.createElement("div")
|
4204
|
-
div.ontouchstart = function() {
|
4205
|
-
supported = true
|
4206
|
-
}
|
4207
|
-
var e = document.createEvent("TouchEvent")
|
4208
|
-
e.initUIEvent("touchstart", true, true)
|
4209
|
-
div.dispatchEvent(e)
|
4210
|
-
} catch (err) {
|
4211
|
-
}
|
4212
|
-
div = div.ontouchstart = null
|
4213
|
-
return supported
|
4214
|
-
})()
|
4215
|
-
var touchSupported = !!(w3ctouch || IE11touch || IE9_10touch)
|
4216
|
-
//合成做成触屏事件所需要的各种原生事件
|
4217
|
-
var touchNames = ["mousedown", "mousemove", "mouseup", ""]
|
4218
|
-
if (w3ctouch) {
|
4219
|
-
touchNames = ["touchstart", "touchmove", "touchend", "touchcancel"]
|
4220
|
-
} else if (IE11touch) {
|
4402
|
+
if (IEtouch) {
|
4221
4403
|
touchNames = ["pointerdown", "pointermove", "pointerup", "pointercancel"]
|
4222
|
-
}
|
4404
|
+
}
|
4405
|
+
if (IEMStouch) {
|
4223
4406
|
touchNames = ["MSPointerDown", "MSPointerMove", "MSPointerUp", "MSPointerCancel"]
|
4224
4407
|
}
|
4225
4408
|
function isPrimaryTouch(event){
|
@@ -4230,140 +4413,132 @@ new function() {// jshint ignore:line
|
|
4230
4413
|
return (e.type === 'pointer'+type || e.type.toLowerCase() === 'mspointer'+type)
|
4231
4414
|
}
|
4232
4415
|
|
4233
|
-
var touchTimeout, longTapTimeout
|
4234
4416
|
//判定滑动方向
|
4235
4417
|
function swipeDirection(x1, x2, y1, y2) {
|
4236
4418
|
return Math.abs(x1 - x2) >=
|
4237
4419
|
Math.abs(y1 - y2) ? (x1 - x2 > 0 ? "left" : "right") : (y1 - y2 > 0 ? "up" : "down")
|
4238
4420
|
}
|
4239
|
-
|
4240
|
-
var touches = event.touches && event.touches.length ? event.touches : [event];
|
4241
|
-
var e = event.changedTouches ? event.changedTouches[0] : touches[0]
|
4242
|
-
return {
|
4243
|
-
x: e.clientX,
|
4244
|
-
y: e.clientY
|
4245
|
-
}
|
4246
|
-
}
|
4421
|
+
|
4247
4422
|
function fireEvent(el, name, detail) {
|
4248
4423
|
var event = document.createEvent("Events")
|
4249
4424
|
event.initEvent(name, true, true)
|
4250
|
-
|
4251
|
-
//event.isTrusted = false 设置这个opera会报错
|
4252
|
-
if (detail)
|
4425
|
+
if (detail) {
|
4253
4426
|
event.detail = detail
|
4427
|
+
}
|
4254
4428
|
el.dispatchEvent(event)
|
4255
4429
|
}
|
4430
|
+
|
4256
4431
|
function onMouse(event) {
|
4257
|
-
|
4258
|
-
|
4259
|
-
|
4260
|
-
if (
|
4261
|
-
|
4262
|
-
|
4263
|
-
|
4432
|
+
var target = event.target,
|
4433
|
+
element = touchProxy.element
|
4434
|
+
|
4435
|
+
if (element && element !== target) {
|
4436
|
+
var type = target.type || '',
|
4437
|
+
targetTag = target.tagName.toLowerCase(),
|
4438
|
+
elementTag = element.tagName.toLowerCase()
|
4439
|
+
// 通过手机的“前往”提交表单时不可禁止默认行为;通过label focus input时也不可以阻止默认行为
|
4440
|
+
if ((targetTag === 'input' && elementTag === "label") || type === 'submit') {
|
4441
|
+
return false
|
4442
|
+
}
|
4443
|
+
if (event.stopImmediatePropagation) {
|
4444
|
+
event.stopImmediatePropagation()
|
4445
|
+
} else {
|
4446
|
+
event.propagationStopped = true
|
4447
|
+
}
|
4448
|
+
event.stopPropagation()
|
4449
|
+
event.preventDefault()
|
4264
4450
|
}
|
4265
|
-
event.stopPropagation()
|
4266
|
-
event.preventDefault()
|
4267
4451
|
}
|
4268
4452
|
function cancelLongTap() {
|
4269
4453
|
if (longTapTimeout) clearTimeout(longTapTimeout)
|
4270
4454
|
longTapTimeout = null
|
4271
4455
|
}
|
4272
4456
|
function touchstart(event) {
|
4273
|
-
var _isPointerType = isPointerEventType(event,
|
4457
|
+
var _isPointerType = isPointerEventType(event, "down"),
|
4274
4458
|
firstTouch = _isPointerType ? event : event.touches[0],
|
4275
|
-
element =
|
4459
|
+
element = "tagName" in firstTouch.target ? firstTouch.target: firstTouch.target.parentNode,
|
4276
4460
|
now = Date.now(),
|
4277
4461
|
delta = now - (touchProxy.last || now)
|
4278
4462
|
|
4279
4463
|
if (_isPointerType && !isPrimaryTouch(event)) return
|
4280
|
-
|
4281
|
-
|
4282
|
-
|
4283
|
-
|
4464
|
+
if (touchProxy.x1 || touchProxy.y1) {
|
4465
|
+
touchProxy.x1 = undefined
|
4466
|
+
touchProxy.y1 = undefined
|
4467
|
+
}
|
4284
4468
|
if (delta > 0 && delta <= 250) {
|
4285
4469
|
touchProxy.isDoubleTap = true
|
4286
4470
|
}
|
4471
|
+
touchProxy.x = firstTouch.pageX
|
4472
|
+
touchProxy.y = firstTouch.pageY
|
4473
|
+
touchProxy.mx = 0
|
4474
|
+
touchProxy.my = 0
|
4287
4475
|
touchProxy.last = now
|
4288
4476
|
touchProxy.element = element
|
4289
|
-
|
4290
|
-
当触发hold和longtap事件时会触发touchcancel事件,从而阻止touchend事件的触发,继而保证在同时绑定tap和hold(longtap)事件时只触发其中一个事件
|
4291
|
-
*/
|
4292
|
-
avalon(element).addClass(fastclick.activeClass)
|
4477
|
+
|
4293
4478
|
longTapTimeout = setTimeout(function() {
|
4294
4479
|
longTapTimeout = null
|
4295
4480
|
fireEvent(element, "hold")
|
4296
4481
|
fireEvent(element, "longtap")
|
4297
4482
|
touchProxy = {}
|
4298
|
-
|
4299
|
-
}, fastclick.clickDuration)
|
4483
|
+
}, clickDuration)
|
4300
4484
|
return true
|
4301
4485
|
}
|
4302
4486
|
function touchmove(event) {
|
4487
|
+
|
4303
4488
|
var _isPointerType = isPointerEventType(event, 'down'),
|
4304
|
-
|
4489
|
+
firstTouch = _isPointerType ? event : event.touches[0],
|
4490
|
+
x = firstTouch.pageX,
|
4491
|
+
y = firstTouch.pageY
|
4305
4492
|
if (_isPointerType && !isPrimaryTouch(event)) return
|
4306
|
-
|
4493
|
+
/*
|
4494
|
+
android下某些浏览器触发了touchmove事件的话touchend事件不触发,禁用touchmove可以解决此bug
|
4495
|
+
http://stackoverflow.com/questions/14486804/understanding-touch-events
|
4496
|
+
*/
|
4497
|
+
if (isGoingtoFixTouchEndEvent && Math.abs(touchProxy.x - x) > 10) {
|
4498
|
+
event.preventDefault()
|
4499
|
+
}
|
4307
4500
|
cancelLongTap()
|
4308
|
-
|
4309
|
-
touchProxy.
|
4501
|
+
|
4502
|
+
touchProxy.x1 = x // touchend事件没有pageX、pageY始终为0,且没有clientX和clientY事件
|
4503
|
+
touchProxy.y1 = y
|
4504
|
+
touchProxy.mx += Math.abs(touchProxy.x - x)
|
4505
|
+
touchProxy.my += Math.abs(touchProxy.y - y)
|
4310
4506
|
}
|
4311
4507
|
function touchend(event) {
|
4312
|
-
var _isPointerType = isPointerEventType(event, 'down')
|
4508
|
+
var _isPointerType = isPointerEventType(event, 'down'),
|
4313
4509
|
element = touchProxy.element
|
4314
4510
|
|
4315
4511
|
if (_isPointerType && !isPrimaryTouch(event)) return
|
4512
|
+
if (!element) return // longtap|hold触发后touchProxy为{}
|
4316
4513
|
|
4317
|
-
if (!element) {
|
4318
|
-
return
|
4319
|
-
}
|
4320
4514
|
cancelLongTap()
|
4321
|
-
|
4322
|
-
var totalX = Math.abs(touchProxy.x - e.x)
|
4323
|
-
var totalY = Math.abs(touchProxy.y - e.y)
|
4324
|
-
if (totalX > 30 || totalY > 30) {
|
4515
|
+
if ((touchProxy.x1 && Math.abs(touchProxy.x1 - touchProxy.x) > dragDistance) || (touchProxy.y1 && Math.abs(touchProxy.y1 - touchProxy.y) > dragDistance)) {
|
4325
4516
|
//如果用户滑动的距离有点大,就认为是swipe事件
|
4326
|
-
var direction = swipeDirection(touchProxy.x,
|
4517
|
+
var direction = swipeDirection(touchProxy.x, touchProxy.x1, touchProxy.y, touchProxy.y1)
|
4327
4518
|
var details = {
|
4328
4519
|
direction: direction
|
4329
4520
|
}
|
4330
4521
|
fireEvent(element, "swipe", details)
|
4331
4522
|
fireEvent(element, "swipe" + direction, details)
|
4332
|
-
avalon(element).removeClass(fastclick.activeClass)
|
4333
4523
|
touchProxy = {}
|
4334
4524
|
} else {
|
4335
|
-
if (
|
4336
|
-
// 失去焦点的处理
|
4337
|
-
if (document.activeElement && document.activeElement !== element) {
|
4338
|
-
document.activeElement.blur()
|
4339
|
-
}
|
4340
|
-
//如果此元素不为表单元素,或者它没有disabled
|
4341
|
-
var forElement
|
4342
|
-
if (element.tagName.toLowerCase() === "label") {
|
4343
|
-
forElement = element.htmlFor ? document.getElementById(element.htmlFor) : null
|
4344
|
-
}
|
4345
|
-
if (forElement) {
|
4346
|
-
fastclick.focus(forElement)
|
4347
|
-
} else {
|
4348
|
-
fastclick.focus(element)
|
4349
|
-
}
|
4350
|
-
event.preventDefault()
|
4525
|
+
if (touchProxy.mx < dragDistance && touchProxy.my < dragDistance) {
|
4351
4526
|
fireEvent(element, 'tap')
|
4352
|
-
avalon.fastclick.fireEvent(element, "click", event)
|
4353
|
-
avalon(element).removeClass(fastclick.activeClass)
|
4354
4527
|
if (touchProxy.isDoubleTap) {
|
4355
4528
|
fireEvent(element, "doubletap")
|
4356
|
-
avalon.fastclick.fireEvent(element, "dblclick", event)
|
4357
4529
|
touchProxy = {}
|
4358
|
-
|
4530
|
+
touchProxy.element = element
|
4359
4531
|
} else {
|
4360
4532
|
touchTimeout = setTimeout(function() {
|
4361
4533
|
clearTimeout(touchTimeout)
|
4362
4534
|
touchTimeout = null
|
4363
|
-
touchProxy
|
4364
|
-
|
4535
|
+
if (touchProxy.element) fireEvent(touchProxy.element, "singletap")
|
4536
|
+
touchProxy = {};
|
4537
|
+
touchProxy.element = element
|
4365
4538
|
}, 250)
|
4366
4539
|
}
|
4540
|
+
} else {
|
4541
|
+
touchProxy = {}
|
4367
4542
|
}
|
4368
4543
|
}
|
4369
4544
|
}
|
@@ -4380,71 +4555,7 @@ new function() {// jshint ignore:line
|
|
4380
4555
|
touchProxy = {}
|
4381
4556
|
})
|
4382
4557
|
}
|
4383
|
-
|
4384
|
-
//这是苹果乱搞异致的,他们想在小屏幕设备上通过快速点击两次,将放大了的网页缩放至原始比例。
|
4385
|
-
var fastclick = avalon.fastclick = {
|
4386
|
-
activeClass: "ms-click-active",
|
4387
|
-
clickDuration: 750, //小于750ms是点击,长于它是长按或拖动
|
4388
|
-
dragDistance: 30, //最大移动的距离
|
4389
|
-
fireEvent: function(element, type, event) {
|
4390
|
-
var clickEvent = document.createEvent("MouseEvents")
|
4391
|
-
clickEvent.initMouseEvent(type, true, true, window, 1, event.screenX, event.screenY,
|
4392
|
-
event.clientX, event.clientY, false, false, false, false, 0, null)
|
4393
|
-
Object.defineProperty(clickEvent, "fireByAvalon", {
|
4394
|
-
value: true
|
4395
|
-
})
|
4396
|
-
element.dispatchEvent(clickEvent)
|
4397
|
-
},
|
4398
|
-
focus: function(target) {
|
4399
|
-
if (this.canFocus(target)) {
|
4400
|
-
//https://github.com/RubyLouvre/avalon/issues/254
|
4401
|
-
var value = target.value
|
4402
|
-
target.value = value
|
4403
|
-
if (isIOS && target.setSelectionRange && target.type.indexOf("date") !== 0 && target.type !== 'time') {
|
4404
|
-
// iOS 7, date datetime等控件直接对selectionStart,selectionEnd赋值会抛错
|
4405
|
-
var n = value.length
|
4406
|
-
target.setSelectionRange(n, n)
|
4407
|
-
} else {
|
4408
|
-
target.focus()
|
4409
|
-
}
|
4410
|
-
}
|
4411
|
-
},
|
4412
|
-
canClick: function(target) {
|
4413
|
-
switch (target.nodeName.toLowerCase()) {
|
4414
|
-
case "textarea":
|
4415
|
-
case "select":
|
4416
|
-
case "input":
|
4417
|
-
return !target.disabled
|
4418
|
-
default:
|
4419
|
-
return true
|
4420
|
-
}
|
4421
|
-
},
|
4422
|
-
canFocus: function(target) {
|
4423
|
-
switch (target.nodeName.toLowerCase()) {
|
4424
|
-
case "textarea":
|
4425
|
-
return true;
|
4426
|
-
case "select":
|
4427
|
-
return !isAndroid
|
4428
|
-
case "input":
|
4429
|
-
switch (target.type) {
|
4430
|
-
case "button":
|
4431
|
-
case "checkbox":
|
4432
|
-
case "file":
|
4433
|
-
case "image":
|
4434
|
-
case "radio":
|
4435
|
-
case "submit":
|
4436
|
-
return false
|
4437
|
-
}
|
4438
|
-
// No point in attempting to focus disabled inputs
|
4439
|
-
return !target.disabled && !target.readOnly
|
4440
|
-
default:
|
4441
|
-
return false
|
4442
|
-
}
|
4443
|
-
}
|
4444
|
-
};
|
4445
|
-
|
4446
|
-
|
4447
|
-
["swipe", "swipeleft", "swiperight", "swipeup", "swipedown", "doubletap", "tap", "dblclick", "longtap", "hold"].forEach(function(method) {
|
4558
|
+
["swipe", "swipeleft", "swiperight", "swipeup", "swipedown", "doubletap", "tap", "singletap", "dblclick", "longtap", "hold"].forEach(function(method) {
|
4448
4559
|
me[method + "Hook"] = me["clickHook"]
|
4449
4560
|
})
|
4450
4561
|
|
@@ -4481,6 +4592,7 @@ new function() {// jshint ignore:line
|
|
4481
4592
|
if (noGlobal === void 0) {
|
4482
4593
|
window.avalon = avalon
|
4483
4594
|
}
|
4595
|
+
|
4484
4596
|
return avalon
|
4485
4597
|
|
4486
4598
|
}));
|