"] //div可以不用闭合
}
@@ -1650,9 +1649,14 @@
tagHooks.optgroup = tagHooks.option
tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead
tagHooks.th = tagHooks.td
-//处理SVG
- tagHooks.circle = tagHooks.ellipse = tagHooks.line = tagHooks.path =
- tagHooks.polygon = tagHooks.polyline = tagHooks.rect = tagHooks.text
+ String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function(tag) {
+ tagHooks[tag] = tagHooks.g //处理SVG
+ })
+ var rtagName = /<([\w:]+)/ //取得其tagName
+ var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
+ var rcreate = W3C ? /[^\d\D]/ : /(<(?:script|link|style|meta|noscript))/ig
+ var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"])
+ var rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/ //需要处理套嵌关系的标签
var script = DOC.createElement("script")
avalon.parseHTML = function(html) {
if (typeof html !== "string") {
@@ -1672,14 +1676,16 @@
var els = wrapper.getElementsByTagName("script")
if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性
for (var i = 0, el; el = els[i++]; ) {
- if (!el.type || scriptTypes[el.type]) { //如果script节点的MIME能让其执行脚本
+ if (scriptTypes[el.type]) {
+ //以偷龙转凤方式恢复执行脚本功能
neo = script.cloneNode(false) //FF不能省略参数
ap.forEach.call(el.attributes, function(attr) {
if (attr && attr.specified) {
neo[attr.name] = attr.value //复制其属性
+ neo.setAttribute(attr.name, attr.value)
}
})
- neo.text = el.text //必须指定,因为无法在attributes中遍历出来
+ neo.text = el.text
el.parentNode.replaceChild(neo, el) //替换节点
}
}
@@ -1691,23 +1697,35 @@
for (els = wrapper["getElementsByTagName"]("br"), i = 0; el = els[i++]; ) {
if (el.className && el.className === "msNoScope") {
el.parentNode.removeChild(el)
+ i--
}
}
- for (els = wrapper.all, i = 0; el = els[i++]; ) {//fix VML
+ for (els = wrapper.all, i = 0; el = els[i++]; ) { //fix VML
if (isVML(el)) {
fixVML(el)
}
}
+ if (tag === "tr") {
+ for (els = wrapper.children, i = 0; el = els[i++]; ) {
+ // IE6-8,如果动态生成tr元素,必须会在后面添加早已废弃caption的标签,其nodeName,innerHTML都为""
+ if (el.nodeName == "") {
+ el.parentNode.removeChild(el)
+ i--
+ }
+ }
+ }
}
while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上!
fragment.appendChild(firstChild)
}
return fragment
}
+
function isVML(src) {
var nodeName = src.nodeName
- return nodeName.toLowerCase() === nodeName && src.scopeName && src.outerText === ""
+ return nodeName.toLowerCase() === nodeName && src.scopeName && src.outerText === ""
}
+
function fixVML(node) {
if (node.currentStyle.behavior !== "url(#default#VML)") {
node.style.behavior = "url(#default#VML)"
@@ -1733,6 +1751,7 @@
}
return node
}
+
/*********************************************************************
* 事件管理器 *
**********************************************************************/
@@ -1775,56 +1794,69 @@
type = RegExp.$2
}
var events = this.$events
- var callbacks = events[type] || []
- var all = events.$all || []
var args = aslice.call(arguments, 1)
- for (var i = 0, callback; callback = callbacks[i++]; ) {
- if (isFunction(callback))
- callback.apply(this, args)
- }
- for (var i = 0, callback; callback = all[i++]; ) {
- if (isFunction(callback))
- callback.apply(this, arguments)
- }
- var element = events.expr && findNode(events.expr)
- if (element) {
- var detail = [type].concat(args)
- var alls = []
- if (special === "up" || special === "down" || special === "all") {
- for (var i in avalon.vmodels) {
- var v = avalon.vmodels[i]
- if (v && v.$events && v.$events.expr) {
- if (v !== this) {
- var node = findNode(v.$events.expr)
- if (!node) {
- continue
- }
- var ok = special === "all" ? 1 : //全局广播
- special === "down" ? element.contains(node) : //向下捕获
- node.contains(element)//向上冒泡
- if (ok) {
- alls.push([node, v])
- }
+ var detail = [type].concat(args)
+ if (special === "all") {
+ for (var i in avalon.vmodels) {
+ var v = avalon.vmodels[i]
+ if (v !== this) {
+ v.$fire.apply(v, detail)
+ }
+ }
+ } else if (special === "up" || special === "down") {
+ var element = events.expr && findNode(events.expr)
+ if (!element)
+ return
+ for (var i in avalon.vmodels) {
+ var v = avalon.vmodels[i]
+ if (v !== this) {
+ if (v.$events.expr) {
+ var node = findNode(v.$events.expr)
+ if (!node) {
+ continue
+ }
+ var ok = special === "down" ? element.contains(node) : //向下捕获
+ node.contains(element) //向上冒泡
+ if (ok) {
+ node._avalon = v //符合条件的加一个标识
}
}
}
- var nodes = DOC.getElementsByTagName("*")//实现节点排序
- alls.sort(function(a, b) {
- return Array.prototype.indexOf.call(nodes, a[0]) - Array.prototype.indexOf.call(nodes, b[0])
- })
- if (special === "up") {
- alls.reverse()
+ }
+ var nodes = DOC.getElementsByTagName("*") //实现节点排序
+ var alls = []
+ Array.prototype.forEach.call(nodes, function(el) {
+ if (el._avalon) {
+ alls.push(el._avalon)
+ el._avalon = ""
+ el.removeAttribute("_avalon")
}
- alls.forEach(function(v) {
- v[1].$fire.apply(v[1], detail)
- })
+ })
+ if (special === "up") {
+ alls.reverse()
+ }
+ for (var i = 0, el; el = alls[i++]; ) {
+ if (el.$fire.apply(el, detail) === false) {
+ break
+ }
+ }
+ } else {
+ var callbacks = events[type] || []
+ var all = events.$all || []
+ for (var i = 0, callback; callback = callbacks[i++]; ) {
+ if (isFunction(callback))
+ callback.apply(this, args)
+ }
+ for (var i = 0, callback; callback = all[i++]; ) {
+ if (isFunction(callback))
+ callback.apply(this, arguments)
}
}
}
}
var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/
var findNode = DOC.querySelector ? function(str) {
- return DOC.querySelector(str)
+ return DOC.querySelector(str)
} : function(str) {
var match = str.match(ravalon)
var all = DOC.getElementsByTagName(match[1])
@@ -1838,6 +1870,7 @@
* 依赖调度系统 *
**********************************************************************/
var ronduplex = /^(duplex|on)$/
+
function registerSubscriber(data) {
Registry[expose] = data //暴光此函数,方便collectSubscribers收集
avalon.openComputedCollect = true
@@ -1867,12 +1900,31 @@
function collectSubscribers(list) { //收集依赖于这个访问器的订阅者
var data = Registry[expose]
if (list && data && avalon.Array.ensure(list, data) && data.element) { //只有数组不存在此元素才push进去
- $$subscribers.push({
- data: data, list: list
- })
+ addSubscribers(data, list)
+ }
+ }
+
+ function addSubscribers(data, list) {
+ data.$uuid = data.$uuid || generateID()
+ list.$uuid = list.$uuid || generateID()
+ var obj = {
+ data: data,
+ list: list,
+ toString: function() {
+ return data.$uuid + " " + list.$uuid
+ }
+ }
+ if (!$$subscribers[obj]) {
+ $$subscribers[obj] = 1
+ $$subscribers.push(obj)
}
}
- var $$subscribers = [], $startIndex = 0, $maxIndex = 200
+ var $$subscribers = [],
+ $startIndex = 0,
+ $maxIndex = 200,
+ beginTime = new Date(),
+ removeID
+
function removeSubscribers() {
for (var i = $startIndex, n = $startIndex + $maxIndex; i < n; i++) {
var obj = $$subscribers[i]
@@ -1885,10 +1937,11 @@
el.sourceIndex === 0 : !root.contains(el) : !avalon.contains(root, el))
if (remove) { //如果它没有在DOM树
$$subscribers.splice(i, 1)
+ delete $$subscribers[obj]
avalon.Array.remove(obj.list, data)
//log("debug: remove " + data.type)
- if (data.type === "if" && data.template && data.template.parentNode === head) {
- head.removeChild(data.template)
+ if (data.type === "if" && data.template && data.template.parentNode === ifGroup) {
+ ifGroup.removeChild(data.template)
}
for (var key in data) {
data[key] = null
@@ -1896,6 +1949,7 @@
obj.data = obj.list = null
i--
n--
+
}
}
obj = $$subscribers[i]
@@ -1904,26 +1958,27 @@
} else {
$startIndex = 0
}
+ beginTime = new Date()
}
- var beginTime = new Date(), removeID
+
function notifySubscribers(list) { //通知依赖于这个访问器的订阅者更新自身
- var currentTime = new Date()
clearTimeout(removeID)
- if (currentTime - beginTime > 333) {
+ if (new Date() - beginTime > 444) {
removeSubscribers()
- beginTime = new Date()
} else {
- removeID = setTimeout(removeSubscribers, 333)
+ removeID = setTimeout(removeSubscribers, 444)
}
if (list && list.length) {
var args = aslice.call(arguments, 1)
for (var i = list.length, fn; fn = list[--i]; ) {
var el = fn.element
- if (fn.$repeat) {
- fn.handler.apply(fn, args) //处理监控数组的方法
- } else if (fn.element && fn.type !== "on") {//事件绑定只能由用户触发,不能由程序触发
- var fun = fn.evaluator || noop
- fn.handler(fun.apply(0, fn.args || []), el, fn)
+ if (el && el.parentNode) {
+ if (fn.$repeat) {
+ fn.handler.apply(fn, args) //处理监控数组的方法
+ } else if (fn.type !== "on") { //事件绑定只能由用户触发,不能由程序触发
+ var fun = fn.evaluator || noop
+ fn.handler(fun.apply(0, fn.args || []), el, fn)
+ }
}
}
}
@@ -1932,32 +1987,58 @@
/*********************************************************************
* 扫描系统 *
**********************************************************************/
- avalon.scan = function(elem, vmodel) {
+ var scanObject = {}
+ avalon.scanCallback = function(fn, group) {
+ group = group || "$all"
+ var array = scanObject[group] || (scanObject[group] = [])
+ array.push(fn)
+ }
+ avalon.scan = function(elem, vmodel, group) {
elem = elem || root
+ group = group || "$all"
+ var array = scanObject[group] || []
var vmodels = vmodel ? [].concat(vmodel) : []
+ var scanIndex = 0;
+ var scanAll = false
+ var fn
+ var dirty = false
+ function cb(i) {
+ scanIndex += i
+ dirty = true
+ setTimeout(function() {
+ if (scanIndex <= 0 && !scanAll) {
+ scanAll = true
+ while (fn = array.shift()) {
+ fn()
+ }
+ }
+ })
+ }
+ vmodels.cb = cb
scanTag(elem, vmodels)
+ //html, include, widget
+ if (!dirty) {
+ while (fn = array.shift()) {
+ fn()
+ }
+ }
}
//http://www.w3.org/TR/html5/syntax.html#void-elements
var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase())
- //确保元素的内容被完全扫描渲染完毕才调用回调
- var interval = W3C ? 15 : 50
-
- function checkScan(elem, callback) {
- var innerHTML = NaN,
- id = setInterval(function() {
- var currHTML = elem.innerHTML
- if (currHTML === innerHTML) {
- clearInterval(id)
- callback()
- } else {
- innerHTML = currHTML
- }
- }, interval)
+ function checkScan(elem, callback, innerHTML) {
+ var id = setTimeout(function() {
+ var currHTML = elem.innerHTML
+ clearTimeout(id)
+ if (currHTML === innerHTML) {
+ callback()
+ } else {
+ checkScan(elem, callback, currHTML)
+ }
+ })
}
-
function scanTag(elem, vmodels, node) {
//扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
//--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
@@ -1976,17 +2057,24 @@
return
}
//ms-important不包含父VM,ms-controller相反
+ var cb = vmodels.cb
vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
+ vmodels.cb = cb
var name = node.name
elem.removeAttribute(name) //removeAttributeNode不会刷新[ms-controller]样式规则
- elem.setAttribute("avalonctrl", node.value)
- newVmodel.$events.expr = elem.tagName + '[avalonctrl="' + node.value + '"]'
+ createSignalTower(elem, newVmodel)
avalon(elem).removeClass(name)
}
scanAttr(elem, vmodels) //扫描特性节点
}
+ function createSignalTower(elem, vmodel) {
+ var id = elem.getAttribute("avalonctrl") || vmodel.$id
+ elem.setAttribute("avalonctrl", id)
+ vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]'
+ }
+
function scanNodeList(parent, vmodels) {
var node = parent.firstChild
while (node) {
@@ -2001,6 +2089,7 @@
scanNode(node, node.nodeType, vmodels)
}
}
+
function scanNode(node, nodeType, vmodels) {
if (nodeType === 1) {
scanTag(node, vmodels) //扫描元素节点
@@ -2068,9 +2157,11 @@
"on": 3000
}
var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit")
+
function bindingSorter(a, b) {
return a.priority - b.priority
}
+ var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled")
function scanAttr(elem, vmodels) {
//防止setAttribute, removeAttribute时 attributes自动被同步,导致for循环出错
var attributes = getAttributes ? getAttributes(elem) : avalon.slice(elem.attributes)
@@ -2089,12 +2180,12 @@
if (events[type]) {
param = type
type = "on"
- } else if (type === "enabled") {//吃掉ms-enabled绑定,用ms-disabled代替
- type = "disabled"
- value = "!(" + value + ")"
- }
- //吃掉以下几个绑定,用ms-attr-*绑定代替
- if (type === "checked" || type === "selected" || type === "disabled" || type === "readonly") {
+ } else if (obsoleteAttrs[type]) {
+ log("ms-" + type + "已经被废弃,请使用ms-attr-*代替")
+ if (type === "enabled") { //吃掉ms-enabled绑定,用ms-disabled代替
+ type = "disabled"
+ value = "!(" + value + ")"
+ }
param = type
type = "attr"
elem.removeAttribute(name)
@@ -2130,6 +2221,7 @@
log("warning!一个元素上不能同时定义ms-checked与ms-duplex")
}
var firstBinding = bindings[0] || {}
+
switch (firstBinding.type) {
case "if":
case "repeat":
@@ -2141,10 +2233,8 @@
if (!stopScan[elem.tagName] && rbind.test(elem.innerHTML.replace(rlt, "<").replace(rgt, ">"))) {
scanNodeList(elem, vmodels) //扫描子孙元素
}
- break;
+ break
}
-
-
}
//IE67下,在循环绑定中,一个节点如果是通过cloneNode得到,自定义属性的specified为false,无法进入里面的分支,
//但如果我们去掉scanAttr中的attr.specified检测,一个元素会有80+个特性节点(因为它不区分固有属性与自定义属性),很容易卡死页面
@@ -2195,6 +2285,9 @@
}
function executeBindings(bindings, vmodels) {
+ if (bindings.length)
+ vmodels.cb(bindings.length)
+
for (var i = 0, data; data = bindings[i++]; ) {
data.vmodels = vmodels
bindingHandlers[data.type](data, vmodels)
@@ -2212,6 +2305,7 @@
r11b = /U2hvcnRDaXJjdWl0/g,
rlt = /</g,
rgt = />/g
+
function trimFilter(value, leach) {
if (value.indexOf("|") > 0) { // 抽取过滤器 先替换掉所有短路与
value = value.replace(r11a, "U2hvcnRDaXJjdWl0") //btoa("ShortCircuit")
@@ -2281,8 +2375,7 @@
",package,private,protected,public,short,static,super,synchronized" +
",throws,transient,volatile"
// ECMA 5 - use strict
- + ",arguments,let,yield"
- + ",undefined"
+ + ",arguments,let,yield" + ",undefined"
var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g
var rsplit = /[^\w$]+/g
var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g')
@@ -2304,6 +2397,7 @@
return cacheVars(key, uniqSet(match))
}
/*添加赋值语句*/
+
function addAssign(vars, scope, name, data) {
var ret = [],
prefix = " = " + name + "."
@@ -2321,7 +2415,8 @@
}
function uniqSet(array) {
- var ret = [], unique = {}
+ var ret = [],
+ unique = {}
for (var i = 0; i < array.length; i++) {
var el = array[i]
var id = el && typeof el.$id === "string" ? el.$id : el
@@ -2335,6 +2430,7 @@
function createCache(maxLength) {
var keys = []
+
function cache(key, value) {
if (keys.push(key) > maxLength) {
delete cache[keys.shift()]
@@ -2457,21 +2553,23 @@
'\\': '\\\\'
}
var quote = window.JSON && JSON.stringify || function(str) {
- return '"' + str.replace(/[\\\"\x00-\x1f]/g, function(a) {
+ return '"' + str.replace(/[\\\"\x00-\x1f]/g, function(a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"'
}
//parseExpr的智能引用代理
- function parseExprProxy(code, scopes, data, tokens) {
+
+ function parseExprProxy(code, scopes, data, tokens, noregister) {
+ scopes.cb(-1)
if (Array.isArray(tokens)) {
code = tokens.map(function(el) {
return el.expr ? "(" + el.value + ")" : quote(el.value)
}).join(" + ")
}
parseExpr(code, scopes, data)
- if (data.evaluator) {
+ if (data.evaluator && !noregister) {
data.handler = bindingExecutors[data.handlerName || data.type]
data.evaluator.toString = function() {
return data.type + " binding to eval(" + code + ")"
@@ -2495,15 +2593,12 @@
"http-equiv": "httpEquiv"
}
- var anomaly = "accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan,"
- + "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight,"
- + "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
+ var anomaly = "accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan," + "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight," + "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
anomaly.replace(rword, function(name) {
propMap[name.toLowerCase()] = name
})
-
- var cssText = ""
- head.insertBefore(avalon.parseHTML(cssText), head.firstChild) //避免IE6 base标签BUG
+ var ifGroup = head.insertBefore(document.createElement("avalon"), head.firstChild) //避免IE6 base标签BUG
+ ifGroup.innerHTML = "X"
var rnoscripts = /
(?:[\s\S]+?)<\/noscript>/img
var rnoscriptText = /([\s\S]+?)<\/noscript>/im
@@ -2545,26 +2640,20 @@
if (boolMap[attrName]) {
var bool = boolMap[attrName]
if (typeof elem[bool] === "boolean") {
+ // IE6-11不支持动态设置fieldset的disabled属性,IE11下样式是生效了,但无法阻止用户对其底下的input元素进行设值……
return elem[bool] = !!val
}
}
var toRemove = (val === false) || (val === null) || (val === void 0)
- if (!W3C && propMap[attrName]) {//旧式IE下需要进行名字映射
+
+ if (!W3C && propMap[attrName]) { //旧式IE下需要进行名字映射
attrName = propMap[attrName]
- var isInnate = true
}
if (toRemove) {
return elem.removeAttribute(attrName)
}
- if (window.VBArray && !isInnate) {//IE下需要区分固有属性与自定义属性
- if (isVML(elem)) {
- isInnate = true
- } else if (!rsvg.test(elem)) {
- var attrs = elem.attributes || {}
- var attr = attrs[attrName]
- isInnate = attr ? attr.expando === false : attr === null
- }
- }
+ //SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy
+ var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false)
if (isInnate) {
elem[attrName] = val
} else {
@@ -2572,18 +2661,33 @@
}
} else if (method === "include" && val) {
var vmodels = data.vmodels
- var rendered = getBindingCallback(elem, "data-include-rendered", vmodels)
- var loaded = getBindingCallback(elem, "data-include-loaded", vmodels)
-
+ var rendered = data.includeRendered
+ var loaded = data.includeLoaded
+ var replace = data.includeReplaced
+ var target = replace ? elem.parentNode : elem
+ vmodels.cb(1)
function scanTemplate(text) {
if (loaded) {
- text = loaded.apply(elem, [text].concat(vmodels))
+ text = loaded.apply(target, [text].concat(vmodels))
}
- avalon.innerHTML(elem, text)
- scanNodeList(elem, vmodels)
- rendered && checkScan(elem, function() {
- rendered.call(elem)
- })
+ if (rendered) {
+ checkScan(target, function() {
+ rendered.call(target)
+ }, NaN)
+ }
+ while (true) {
+ var node = data.startInclude.nextSibling
+ if (node && node !== data.endInclude) {
+ target.removeChild(node)
+ } else {
+ break
+ }
+ }
+ var dom = avalon.parseHTML(text)
+ var nodes = avalon.slice(dom.childNodes)
+ target.insertBefore(dom, data.endInclude)
+ scanNodeArray(nodes, vmodels)
+ vmodels.cb(-1)
}
if (data.param === "src") {
if (cacheTmpls[val]) {
@@ -2639,7 +2743,7 @@
}
elem[method] = val
if (window.chrome && elem.tagName === "EMBED") {
- var parent = elem.parentNode//#525 chrome1-37下embed标签动态设置src不能发生请求
+ var parent = elem.parentNode //#525 chrome1-37下embed标签动态设置src不能发生请求
var comment = document.createComment("ms-src")
parent.replaceChild(comment, elem)
parent.replaceChild(elem, comment)
@@ -2668,7 +2772,7 @@
if (!data.hasBindEvent) { //确保只绑定一次
var activate = "mouseenter" //在移出移入时切换类名
var abandon = "mouseleave"
- if (method === "active") {//在聚焦失焦中切换类名
+ if (method === "active") { //在聚焦失焦中切换类名
elem.tabIndex = elem.tabIndex || -1
activate = "mousedown"
abandon = "mouseup"
@@ -2741,20 +2845,15 @@
}
break
case "clear":
- var size = "proxySize" in data ? data.proxySize : proxies.length
- if (size) {
- var n = size * group, k = 0
- while (true) {
- var nextNode = data.element.nextSibling
- if (nextNode && k < n) {
- parent.removeChild(nextNode)
- k++
- } else {
- break
- }
+ while (true) {
+ var node = data.element.nextSibling
+ if (node && node !== data.endRepeat) {
+ parent.removeChild(node)
+ } else {
+ break
}
- recycleEachProxies(proxies)
}
+ recycleEachProxies(proxies)
break
case "move": //将proxies中的第pos个元素移动el位置上(pos, el都是数字)
var t = proxies.splice(pos, 1)[0]
@@ -2800,13 +2899,14 @@
calculateFragmentGroup(data)
break
}
- var callback = data.renderedCallback || noop, args = arguments
+ var callback = data.renderedCallback || noop,
+ args = arguments
checkScan(parent, function() {
callback.apply(parent, args)
- if (parent.oldValue && parent.tagName === "SELECT" && method === "index") {//fix #503
+ if (parent.oldValue && parent.tagName === "SELECT" && method === "index") { //fix #503
avalon(parent).val(parent.oldValue.split(","))
}
- })
+ }, NaN)
}
},
"html": function(val, elem, data) {
@@ -2847,15 +2947,17 @@
} else {
avalon.innerHTML(parent, val)
}
+ data.vmodels.cb(1)
avalon.nextTick(function() {
scanNodeList(parent, data.vmodels)
+ data.vmodels.cb(-1)
})
},
"if": function(val, elem, data) {
if (val) { //插回DOM树
if (elem.nodeType === 8) {
elem.parentNode.replaceChild(data.template, elem)
- elem = data.element = data.template
+ elem = data.element = data.template //这时可能为null
}
if (elem.getAttribute(data.name)) {
elem.removeAttribute(data.name)
@@ -2866,7 +2968,7 @@
var node = data.element = DOC.createComment("ms-if")
elem.parentNode.replaceChild(node, elem)
data.template = elem //元素节点
- head.appendChild(elem)
+ ifGroup.appendChild(elem)
}
}
},
@@ -2878,7 +2980,9 @@
}
var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
if (eventType === "scan") {
- callback.call(elem, {type: eventType})
+ callback.call(elem, {
+ type: eventType
+ })
} else if (typeof data.specialBind === "function") {
data.specialBind(elem, callback)
} else {
@@ -2895,7 +2999,7 @@
"text": function(val, elem) {
val = val == null ? "" : val //不在页面上显示undefined null
if (elem.nodeType === 3) { //绑定在文本节点上
- try {//IE对游离于DOM树外的节点赋值会报错
+ try { //IE对游离于DOM树外的节点赋值会报错
elem.data = val
} catch (e) {
}
@@ -2947,8 +3051,24 @@
text = RegExp.$1
}
}
+ if (data.type === "include") {
+ var elem = data.element
+ data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels)
+ data.includeLoaded = getBindingCallback(elem, "data-include-loaded", vmodels)
+ var outer = data.includeReplaced = !!avalon(elem).data("includeReplace")
+ data.startInclude = DOC.createComment("ms-include")
+ data.endInclude = DOC.createComment("ms-include-end")
+ if (outer) {
+ data.element = data.startInclude
+ elem.parentNode.insertBefore(data.startInclude, elem)
+ elem.parentNode.insertBefore(data.endInclude, elem.nextSibling)
+ } else {
+ elem.insertBefore(data.startInclude, elem.firstChild)
+ elem.appendChild(data.endInclude)
+ }
+ }
data.handlerName = "attr" //handleName用于处理多种绑定共用同一种bindingExecutor的情况
- parseExprProxy(text, vmodels, data, (simple ? null : scanExpr(data.value)))
+ parseExprProxy(text, vmodels, data, (simple ? 0 : scanExpr(data.value)))
},
//根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
//http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
@@ -2981,7 +3101,7 @@
if (!hasExpr) {
data.immobileClass = className
}
- parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : null))
+ parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : 0))
} else {
data.immobileClass = data.oldStyle = data.param
parseExprProxy(text, vmodels, data)
@@ -2989,30 +3109,40 @@
},
"duplex": function(data, vmodels) {
var elem = data.element,
- tagName = elem.tagName
+ tagName = elem.tagName,
+ hasCast
+ parseExprProxy(data.value, vmodels, data, 0, 1)
if (typeof duplexBinding[tagName] === "function") {
data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
- //由于情况特殊,不再经过parseExprProxy
- parseExpr(data.value, vmodels, data, "duplex")
if (data.evaluator && data.args) {
- var form = elem.form
- if (form && form.msValidate) {
- form.msValidate(elem)
- }
- data.msType = data.param || ""
- if (data.msType === "bool") {
- data.msType = "boolean"
- log("ms-duplex-bool已经更名为ms-duplex-boolean")
- } else if (data.msType === "text") {
- data.msType = "string"
- log("ms-duplex-text已经更名为ms-duplex-string")
+ var params = []
+ var casting = oneObject("string,number,boolean,checked")
+ if (elem.type === "radio" && data.param === "") {
+ data.param = "checked"
}
- if (data.msType === "radio") {
- log("ms-duplex-radio将在2.0废掉,请尽量不要用")
- }
- if (!/boolean|string|number/.test(data.msType)) {
- data.msType = ""
+ data.param.replace(/\w+/g, function(name) {
+ if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) {
+ if (name === "radio")
+ log("ms-duplex-radio已经更名为ms-duplex-checked")
+ name = "checked"
+ data.isChecked = true
+ }
+ if (name === "bool") {
+ name = "boolean"
+ log("ms-duplex-bool已经更名为ms-duplex-boolean")
+ } else if (name === "text") {
+ name = "string"
+ log("ms-duplex-text已经更名为ms-duplex-string")
+ }
+ if (casting[name]) {
+ hasCast = true
+ }
+ avalon.Array.ensure(params, name)
+ })
+ if (!hasCast) {
+ params.push("string")
}
+ data.param = params.join("-")
data.bound = function(type, callback) {
if (elem.addEventListener) {
elem.addEventListener(type, callback, false)
@@ -3025,15 +3155,22 @@
old && old()
}
}
+ for (var i in avalon.vmodels) {
+ var v = avalon.vmodels[i]
+ v.$fire("avalon-ms-duplex-init", data)
+ }
+ var cpipe = data.pipe || (data.pipe = pipe)
+ cpipe(null, data, "init")
duplexBinding[elem.tagName](elem, data.evaluator.apply(null, data.args), data)
}
}
},
"repeat": function(data, vmodels) {
var type = data.type
- parseExpr(data.value, vmodels, data)
+ parseExprProxy(data.value, vmodels, data, 0, 1)
data.proxies = []
var freturn = false
+ vmodels.cb(-1)
try {
var $repeat = data.$repeat = data.evaluator.apply(0, data.args || [])
var xtype = avalon.type($repeat)
@@ -3051,25 +3188,30 @@
data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels)
var comment = data.element = DOC.createComment("ms-repeat")
+ var endRepeat = data.endRepeat = DOC.createComment("ms-repeat-end")
+
+ hyperspace.appendChild(comment)
+ hyperspace.appendChild(endRepeat)
+
if (type === "each" || type === "with") {
data.template = elem.innerHTML.trim()
- avalon.clearHTML(elem).appendChild(comment)
+ avalon.clearHTML(elem).appendChild(hyperspace)
} else {
data.template = elem.outerHTML.trim()
+ elem.parentNode.replaceChild(hyperspace, elem)
data.group = 1
- elem.parentNode.replaceChild(comment, elem)
}
- data.rollback = function() {//只用于list为对象的情况
+ data.rollback = function() { //只用于list为对象的情况
bindingExecutors.repeat.call(data, "clear")
var elem = data.element
var parentNode = elem.parentNode
var content = avalon.parseHTML(data.template)
var target = content.firstChild
parentNode.replaceChild(content, elem)
+ parentNode.removeChild(data.endRepeat)
target = data.element = data.type === "repeat" ? target : parentNode
- data.group = null
- target.setAttribute(data.name, data.value)
+ data.group = target.setAttribute(data.name, data.value)
}
var arr = data.value.split(".") || []
if (arr.length > 1) {
@@ -3104,9 +3246,7 @@
}
var $list = ($repeat.$events || {})[subscribers]
if ($list && avalon.Array.ensure($list, data)) {
- $$subscribers.push({
- data: data, list: $list
- })
+ addSubscribers(data, $list)
}
if (!Array.isArray($repeat) && type !== "each") {
var pool = withProxyPool[$repeat.$id]
@@ -3168,54 +3308,68 @@
var args = data.value.match(rword)
var elem = data.element
var widget = args[0]
- if (args[1] === "$" || !args[1]) {
- args[1] = widget + setTimeout("1")
+ var id = args[1]
+ if (!id || id === "$") {//没有定义或为$时,取组件名+随机数
+ id = widget + setTimeout("1")
}
- data.value = args.join(",")
+ var optName = args[2] || widget//没有定义,取组件名
+ vmodels.cb(-1)
var constructor = avalon.ui[widget]
if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
vmodels = elem.vmodels || vmodels
- var optName = args[2] || widget //尝试获得配置项的名字,没有则取widget的名字
for (var i = 0, v; v = vmodels[i++]; ) {
if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
- var nearestVM = v
+ var vmOptions = v[optName]
+ vmOptions = vmOptions.$model || vmOptions
break
}
}
- if (nearestVM) {
- var vmOptions = nearestVM[optName]
- vmOptions = vmOptions.$model || vmOptions
- var id = vmOptions[widget + "Id"]
- if (typeof id === "string") {
- args[1] = id
+ if (vmOptions) {
+ var wid = vmOptions[widget + "Id"]
+ if (typeof wid === "string") {
+ id = wid
}
}
- var widgetData = avalon.getWidgetData(elem, args[0]) //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
- data[widget + "Id"] = args[1]
- data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
+ //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
+ var widgetData = avalon.getWidgetData(elem, widget)
+ data.value = [widget, id, optName].join(",")
+ data[widget + "Id"] = id
+ data.evaluator = noop
+ var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
elem.removeAttribute("ms-widget")
var vmodel = constructor(elem, data, vmodels) || {} //防止组件不返回VM
- data.evaluator = noop
- elem.msData["ms-widget-id"] = vmodel.$id || ""
- if (vmodel.hasOwnProperty("$init")) {
- vmodel.$init()
- }
- if (vmodel.hasOwnProperty("$remove")) {
- function offTree() {
- if (!elem.msRetain && !root.contains(elem)) {
- vmodel.$remove()
- elem.msData = {}
- delete VMODELS[vmodel.$id]
- return false
- }
- }
- if (window.chrome) {
- elem.addEventListener("DOMNodeRemovedFromDocument", function() {
- setTimeout(offTree)
+ if (vmodel.$id) {
+ avalon.vmodels[id] = vmodel
+ createSignalTower(elem, vmodel)
+ if (vmodel.hasOwnProperty("$init")) {
+ vmodel.$init(function() {
+ var nv = [vmodel].concat(vmodels)
+ nv.cb = vmodels.cb
+ avalon.scan(elem, nv)
+ if (typeof options.onInit === "function") {
+ options.onInit.call(elem, vmodel, options, vmodels)
+ }
})
- } else {
- avalon.tick(offTree)
}
+ if (vmodel.hasOwnProperty("$remove")) {
+ function offTree() {
+ if (!elem.msRetain && !root.contains(elem)) {
+ vmodel.$remove()
+ elem.msData = {}
+ delete VMODELS[vmodel.$id]
+ return false
+ }
+ }
+ if (window.chrome) {
+ elem.addEventListener("DOMNodeRemovedFromDocument", function() {
+ setTimeout(offTree)
+ })
+ } else {
+ avalon.tick(offTree)
+ }
+ }
+ } else {
+ avalon.scan(elem, vmodels)
}
} else if (vmodels.length) { //如果该组件还没有加载,那么保存当前的vmodels
elem.vmodels = vmodels
@@ -3240,33 +3394,75 @@
//将模型中的字段与input, textarea的value值关联在一起
var duplexBinding = bindingHandlers.duplex
+
+ function fixNull(val) {
+ return val == null ? "" : val
+ }
+ avalon.duplexHooks = {
+ checked: {
+ get: function(val, data) {
+ return !data.element.oldValue
+ }
+ },
+ string: {
+ get: function(val) { //同步到VM
+ return val
+ },
+ set: fixNull
+ },
+ "boolean": {
+ get: function(val) {
+ return val === "true"
+ },
+ set: fixNull
+ },
+ number: {
+ get: function(val) {
+ return isFinite(val) ? parseFloat(val) || 0 : val
+ },
+ set: fixNull
+ }
+ }
+
+ function pipe(val, data, action, e) {
+ data.param.replace(/\w+/g, function(name) {
+ var hook = avalon.duplexHooks[name]
+ if (hook && typeof hook[action] === "function") {
+ val = hook[action](val, data)
+ }
+ })
+ return val
+ }
//如果一个input标签添加了model绑定。那么它对应的字段将与元素的value连结在一起
//字段变,value就变;value变,字段也跟着变。默认是绑定input事件,
+
duplexBinding.INPUT = function(element, evaluator, data) {
var type = element.type,
bound = data.bound,
$elem = avalon(element),
- firstTigger = false,
composing = false
+
function callback(value) {
- firstTigger = true
- data.changed.call(this, value)
+ data.changed.call(this, value, data)
}
+
function compositionStart() {
composing = true
}
+
function compositionEnd() {
composing = false
}
//当value变化时改变model的值
+
function updateVModel() {
- if (composing)//处理中文输入法在minlengh下引发的BUG
+ if (composing) //处理中文输入法在minlengh下引发的BUG
return
var val = element.oldValue = element.value //防止递归调用形成死循环
- var typedVal = getTypedValue(data, val) //尝式转换为正确的格式
+ var lastValue = data.pipe(val, data, "get")
if ($elem.data("duplex-observe") !== false) {
- evaluator(typedVal)
- callback.call(element, typedVal)
+ evaluator(lastValue)
+ callback.call(element, lastValue)
if ($elem.data("duplex-focus")) {
avalon.nextTick(function() {
element.focus()
@@ -3277,29 +3473,24 @@
//当model变化时,它就会改变value的值
data.handler = function() {
- var val = evaluator()
- val = val == null ? "" : val + ""
+ var val = data.pipe(evaluator(), data, "set")
if (val !== element.value) {
element.value = val
}
}
- if (type === "checkbox" && data.param === "radio") {
- type = "radio"
- }
- if (type === "radio") {
+ if (data.isChecked || element.type === "radio") {
var IE6 = !window.XMLHttpRequest
updateVModel = function() {
if ($elem.data("duplex-observe") !== false) {
- var val = element.value
- var typedValue = data.msType ? getTypedValue(data, val) : !element.oldValue
- evaluator(typedValue)
- callback.call(element, typedValue)
+ var lastValue = data.pipe(element.value, data, "get")
+ evaluator(lastValue)
+ callback.call(element, lastValue)
}
}
data.handler = function() {
var val = evaluator()
- var checked = data.msType ? val + "" === element.value : !!val
+ var checked = data.isChecked ? !!val : val + "" === element.value
element.oldValue = checked
if (IE6) {
setTimeout(function() {
@@ -3323,69 +3514,52 @@
log("ms-duplex应用于checkbox上要对应一个数组")
array = [array]
}
- var typedValue = getTypedValue(data, element.value)
- avalon.Array[method](array, typedValue)
+ avalon.Array[method](array, data.pipe(element.value, data, "get"))
callback.call(element, array)
}
}
data.handler = function() {
var array = [].concat(evaluator()) //强制转换为数组
- element.checked = array.indexOf(getTypedValue(data, element.value)) >= 0
+ element.checked = array.indexOf(data.pipe(element.value, data, "get")) >= 0
}
-
bound(W3C ? "change" : "click", updateVModel)
-
} else {
- var event = element.attributes["data-duplex-event"] || element.attributes["data-event"] || {}
+ var events = element.getAttribute("data-duplex-event") || element.getAttribute("data-event") || "input"
if (element.attributes["data-event"]) {
log("data-event指令已经废弃,请改用data-duplex-event")
}
- event = event.value
- if (event === "change") {
- bound("change", updateVModel)
- } else {
- if (W3C) { //IE9+, W3C
- bound("input", updateVModel)
- bound("compositionstart", compositionStart)
- bound("compositionend", compositionEnd)
- if ("onselectionchange"in DOC) {//fix IE9 http://www.matts411.com/post/internet-explorer-9-oninput/
- function selectionchange(e) {
- if (e.type === "focus") {
- DOC.addEventListener("selectionchange", updateVModel, false);
- } else {
- DOC.removeEventListener("selectionchange", updateVModel, false);
+
+ function delay(e) {
+ setTimeout(function() {
+ updateVModel(e)
+ })
+ }
+ events.replace(rword, function(name) {
+ switch (name) {
+ case "input":
+ if (W3C) { //IE9+, W3C
+ bound("input", updateVModel)
+ bound("compositionstart", compositionStart)
+ bound("compositionend", compositionEnd)
+ //http://www.cnblogs.com/rubylouvre/archive/2013/02/17/2914604.html
+ //http://www.matts411.com/post/internet-explorer-9-oninput/
+ if (DOC.documentMode === 9) {
+ bound("paste", delay)
+ bound("cut", delay)
}
+ } else { //onpropertychange事件无法区分是程序触发还是用户触发
+ bound("propertychange", function(e) {
+ if (e.propertyName === "value")
+ updateVModel()
+ })
}
- bound("focus", selectionchange)
- bound("blur", selectionchange)
- }
- } else {
- var events = ["keyup", "paste", "cut", "change"]
-
- function removeFn(e) {
- var key = e.keyCode
- // command modifiers arrows
- if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40))
- return
- if (e.type === "cut") {
- avalon.nextTick(updateVModel)
- } else {
- updateVModel()
- }
- }
-
- events.forEach(function(type) {
- element.attachEvent("on" + type, removeFn)
- })
-
- data.rollback = function() {
- events.forEach(function(type) {
- element.detachEvent("on" + type, removeFn)
- })
- }
+ break
+ default:
+ bound(name, updateVModel)
+ break
}
- }
+ })
}
element.oldValue = element.value
launch(function() {
@@ -3396,42 +3570,34 @@
}
})
registerSubscriber(data)
- var timer = setTimeout(function() {
- if (!firstTigger) {
- callback.call(element, element.value)
- }
- clearTimeout(timer)
- }, 31)
- }
-
- function getTypedValue(data, val) {
- switch (data.msType) {
- case "boolean":
- return val === "true"
- case "number":
- return isFinite(val) || val === "" ? parseFloat(val) || 0 : val
- default:
- return val
- }
+ callback.call(element, element.value)
}
var TimerID, ribbon = [],
launch = noop
+
function W3CFire(el, name, detail) {
var event = DOC.createEvent("Events")
event.initEvent(name, true, true)
+ event.isTrusted = false
if (detail) {
event.detail = detail
}
el.dispatchEvent(event)
}
- function onTree() { //disabled状态下改动不触发input事件
- if (!this.disabled && this.oldValue !== this.value) {
+ function onTree(value) { //disabled状态下改动不触发input事件
+ var newValue = arguments.length ? value : this.value
+ if (!this.disabled && this.oldValue !== newValue) {
+ var type = this.getAttribute("data-duplex-event") || "input"
+ type = type.match(rword).shift()
if (W3C) {
- W3CFire(this, "input")
+ W3CFire(this, type)
} else {
- this.fireEvent("onchange")
+ try {
+ this.fireEvent("on" + type)
+ } catch (e) {
+ }
}
}
}
@@ -3454,16 +3620,14 @@
}
}
- function newSetter(newValue) {
- oldSetter.call(this, newValue)
- if (newValue !== this.oldValue) {
- W3CFire(this, "input")
- }
+ function newSetter(value) {
+ onSetter.call(this, value)
+ onTree.call(this, value)
}
try {
var inputProto = HTMLInputElement.prototype
- Object.getOwnPropertyNames(inputProto)//故意引发IE6-8等浏览器报错
- var oldSetter = Object.getOwnPropertyDescriptor(inputProto, "value").set //屏蔽chrome, safari,opera
+ Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错
+ var onSetter = Object.getOwnPropertyDescriptor(inputProto, "value").set //屏蔽chrome, safari,opera
Object.defineProperty(inputProto, "value", {
set: newSetter
})
@@ -3473,20 +3637,21 @@
duplexBinding.SELECT = function(element, evaluator, data) {
var $elem = avalon(element)
+
function updateVModel() {
if ($elem.data("duplex-observe") !== false) {
var val = $elem.val() //字符串或字符串数组
if (Array.isArray(val)) {
val = val.map(function(v) {
- return getTypedValue(data, v)
+ return data.pipe(v, data, "get")
})
} else {
- val = getTypedValue(data, val)
+ val = data.pipe(val, data, "get")
}
if (val + "" !== element.oldValue) {
evaluator(val)
}
- data.changed.call(element, val)
+ data.changed.call(element, val, data)
}
}
data.handler = function() {
@@ -3509,18 +3674,11 @@
}
}
data.bound("change", updateVModel)
- var innerHTML = NaN
- var id = setInterval(function() {
- var currHTML = element.innerHTML
- if (currHTML === innerHTML) {
- clearInterval(id)
- //先等到select里的option元素被扫描后,才根据model设置selected属性
- registerSubscriber(data)
- data.changed.call(element, evaluator())
- } else {
- innerHTML = currHTML
- }
- }, 20)
+ checkScan(element,function() {
+ //先等到select里的option元素被扫描后,才根据model设置selected属性
+ registerSubscriber(data)
+ data.changed.call(element, evaluator(), data)
+ }, NaN)
}
duplexBinding.TEXTAREA = duplexBinding.INPUT
//============================= event binding =======================
@@ -3631,7 +3789,7 @@
function Collection(model) {
var array = []
array.$id = generateID()
- array.$model = model //数据模型
+ array.$model = model //数据模型
array.$events = {}
array.$events[subscribers] = []
array._ = modelFactory({
@@ -3658,7 +3816,7 @@
pos = typeof pos === "number" ? pos : oldLength
var added = []
for (var i = 0, n = arr.length; i < n; i++) {
- added[i] = convert(arr[i], this.$model[i])
+ added[i] = convert(arr[i], this.$model[pos + i])
}
_splice.apply(this, [pos, 0].concat(added))
this._fire("add", pos, added)
@@ -3706,7 +3864,8 @@
// 必须存在第一个参数,需要大于-1, 为添加或删除元素的基点
a = _number(a, this.length)
var removed = _splice.apply(this.$model, arguments),
- ret = [], change
+ ret = [],
+ change
this._stopFireLength = true //确保在这个方法中 , $watch("length",fn)只触发一次
if (removed.length) {
ret = this._del(a, removed.length)
@@ -3823,44 +3982,49 @@
//============ each/repeat/with binding 用到的辅助函数与对象 ======================
//为ms-each, ms-with, ms-repeat要循环的元素外包一个msloop临时节点,ms-controller的值为代理VM的$id
+
function shimController(data, transation, proxy, fragments) {
var dom = avalon.parseHTML(data.template)
var nodes = avalon.slice(dom.childNodes)
transation.appendChild(dom)
proxy.$outer = data.$outer
+ var ov = data.vmodels
+ var nv = [proxy].concat(ov)
+ nv.cb = ov.cb
var fragment = {
nodes: nodes,
- vmodels: [proxy].concat(data.vmodels)
+ vmodels: nv
}
fragments.push(fragment)
}
- // 取得用于定位的节点。比如data.group = 3, 结构为
- //
+ //如果ms-repeat紧挨着ms-repeat-end,那么就返回ms-repeat-end
+ // 取得用于定位的节点。比如group = 3, 结构为
+ //
// 当pos为0时,返回 br#first
// 当pos为1时,返回 br#second
- // 当pos为2时,返回 null
+ // 当pos为2时,返回 ms-repeat-end
+
function locateFragment(data, pos) {
- var comment = data.element
- if (data.type == "repeat") {//ms-repeat,data.group为1
- var node = comment.nextSibling
- for (var i = 0, n = pos; i < n; i++) {
- if (node) {
- node = node.nextSibling
+ var startRepeat = data.element
+ var endRepeat = data.endRepeat
+ var nodes = []
+ var node = startRepeat.nextSibling
+ if (node !== endRepeat) {
+ do {
+ if (node !== endRepeat) {
+ nodes.push(node)
} else {
break
}
- }
- } else {
- var nodes = avalon.slice(comment.parentNode.childNodes, 1)
- var group = data.group || nodes.length / data.proxies.length
- node = nodes[group * pos]
+ } while (node = node.nextSibling)
}
- return node || null
+ return nodes[data.group * pos] || endRepeat
}
function removeFragment(node, group, pos) {
var n = group * (pos || 1)
- var nodes = [node], i = 1
+ var nodes = [node],
+ i = 1
var view = hyperspace
while (i < n) {
node = node.nextSibling
@@ -3876,9 +4040,10 @@
function calculateFragmentGroup(data) {
if (!isFinite(data.group)) {
- var nodes = avalon.slice(data.element.parentNode.childNodes, 1)
+ var nodes = data.element.parentNode.childNodes
+ var length = nodes.length - 2 //去掉两个注释节点
var n = "proxySize" in data ? data.proxySize : data.proxies.length
- data.group = nodes.length / n
+ data.group = length / n
}
}
// 为ms-each, ms-repeat创建一个代理对象,通过它们能使用一些额外的属性与功能($index,$first,$last,$remove,$key,$val,$outer)
@@ -3897,8 +4062,10 @@
return proxy
}
var eachProxyPool = []
+
function getEachProxy(index, item, data, last) {
- var param = data.param || "el", proxy
+ var param = data.param || "el",
+ proxy
var source = {
$remove: function() {
return data.$repeat.removeAt(proxy.$index)
@@ -3912,7 +4079,7 @@
source[param] = item
for (var i = 0, n = eachProxyPool.length; i < n; i++) {
var proxy = eachProxyPool[i]
- if (proxy.hasOwnProperty(param)) {
+ if (proxy.hasOwnProperty(param) && (avalon.type(proxy[param]) === avalon.type(item))) {
for (var k in source) {
proxy[k] = source[k]
}
@@ -3984,16 +4151,16 @@
sanitize: function(str) {
return str.replace(rscripts, "").replace(ropen, function(a, b) {
var match = a.toLowerCase().match(/<(\w+)\s/)
- if (match) {//处理a标签的href属性,img标签的src属性,form标签的action属性
+ if (match) { //处理a标签的href属性,img标签的src属性,form标签的action属性
var reg = rsanitize[match[1]]
if (reg) {
a = a.replace(reg, function(s, name, value) {
var quote = value.charAt(0)
- return name + "=" + quote + "javascript:void(0)" + quote
+ return name + "=" + quote + "javascript:void(0)" + quote
})
}
}
- return a.replace(ron, " ").replace(/\s+/g, " ")//移除onXXX事件
+ return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件
})
},
escape: function(html) {
@@ -4178,8 +4345,7 @@
}
return string
}
- var rfixFFDate = /^(\d+)-(\d+)-(\d{4})$/
- var rfixIEDate = /^(\d+)\s+(\d+),(\d{4})$/
+ var rfixYMD = /^(\d+)\D(\d+)\D(\d+)/
filters.date = function(date, format) {
var locate = filters.date.locate,
text = "",
@@ -4192,9 +4358,10 @@
date = toInt(date)
} else {
var trimDate = date.trim()
- if (trimDate.match(rfixFFDate) || trimDate.match(rfixIEDate)) {
- date = RegExp.$3 + "/" + RegExp.$1 + "/" + RegExp.$2
- }
+ date = trimDate.replace(rfixYMD, function(a, b, c, d) {
+ var array = d.length === 4 ? [d, b, c] : [b, c, d]
+ return array.join("/")
+ })
date = jsonStringToDate(date)
}
date = new Date(date)
@@ -4271,12 +4438,9 @@
filters.date.locate = locate
}
-
/*********************************************************************
* AMD加载器 *
**********************************************************************/
-
- var innerRequire
var modules = avalon.modules = {
"ready!": {
exports: avalon
@@ -4638,6 +4802,7 @@
**********************************************************************/
var readyList = []
+
function fireReady() {
if (DOC.body) { // 在IE8 iframe中doScrollCheck可能不正确
if (innerRequire) {
@@ -4699,4 +4864,4 @@
http://www.cnblogs.com/henryzhu/p/mvvm-1-why-mvvm.ht
http://dev.oupeng.com/wp-content/uploads/20131109-kennyluck-optimizing-js-games.html#controls-slide
http://ps.p12345.com/
- */
+ */
\ No newline at end of file
diff --git a/avalon.min.js b/avalon.min.js
index cbfbfdd8d..4126c3bc4 100644
--- a/avalon.min.js
+++ b/avalon.min.js
@@ -1,121 +1,125 @@
-(function(p){function A(){}function x(){r.console&&avalon.config.debug&&Function.apply.call(console.log,console,arguments)}function T(b,c){"string"===typeof b&&(b=b.match(D)||[]);for(var d={},e=void 0!==c?c:1,f=0,g=b.length;fb?Math.max(c+b,0):Math.min(b,c)}function Sb(b,c,
-d){if(U(c)||c&&c.nodeType||-1!==d.indexOf(b)||-1!==ta.indexOf(b))return!1;c=d.$special;return b&&"$"===b.charAt(0)&&!c[b]?!1:!0}function J(b,c,d){if(Array.isArray(b)){var e=b.concat();b.length=0;c=Tb(b);c.pushArray(e);return c}if("number"===typeof b.nodeType||b.$id&&b.$model&&b.$events)return b;Array.isArray(b.$skipArray)||(b.$skipArray=[]);b.$skipArray.$special=c||{};var f={};d=d||{};var g={},h={},k=[];for(e in b)(function(c,e){d[c]=e;if(Sb(c,e,b.$skipArray)){var q,l=avalon.type(e);g[c]=[];if("object"===
-l&&U(e.get)&&2>=Object.keys(e).length){var H=e.set,K=e.get;q=function(b){var e=f.$events,g=d[c];if(arguments.length){if(ka)return;if(U(H)){var h=e[c];e[c]=[];H.call(f,b);e[c]=h}}else avalon.openComputedCollect&&la(e[c]);b=d[c]=K.call(f);if(!ma(g,b)){if(na&&(h=V[f.$id])&&h[c])h[c].$val=b;ua(e[c]);f.$events&&O.$fire.call(f,c,b,g)}return b};k.push(function(){Z[z]={evaluator:q,element:F,type:"computed::"+c,handler:A,args:[]};q();la(g[c]);delete Z[z]})}else va.test(l)?(q=function(b){var e=q.child,h=d[c];
-if(arguments.length)!ka&&!ma(h,b)&&(e=q.child=Ub(f,c,b,l),b=d[c]=e.$model,(e=wa[e.$id])&&e(),f.$events&&O.$fire.call(f,c,b,h));else return la(g[c]),e},(q.child=J(e,0,d[c])).$events[G]=g[c]):q=function(b){var e=d[c];if(arguments.length){if(!ma(e,b)){d[c]=b;if(na){var h=V[f.$id];h&&h[c]&&(h[c].$val=b)}ua(g[c]);f.$events&&O.$fire.call(f,c,b,e)}}else return la(g[c]),e};h[c]=q}})(e,b[e]);ta.forEach(function(c){delete b[c];delete d[c]});var f=oa(f,Vb(h),b),l;for(l in b)h[l]||(f[l]=b[l]);f.$id=Va();f.$model=
-d;f.$events=g;for(e in O)c=O[e],v||(c=c.bind(f)),f[e]=c;f.hasOwnProperty=function(b){return b in f.$model};k.forEach(function(b){b()});return f}function Ub(b,c,d,e){var f=b[c];if("array"===e){if(!Array.isArray(d)||f===d)return f;f.clear();f.pushArray(d.concat());return f}var g=b.$events[c];V[f.$id]&&(na--,delete V[f.$id]);var h=J(d);wa[h.$id]=function(b){for(;b=g.shift();)(function(b){b.type&&avalon.nextTick(function(){b.rollback&&b.rollback();C[b.type](b,b.vmodels)})})(b);delete wa[h.$id]};return h}
-function $(b,c,d){b="for(var "+b+"i=0,n = this.length; i < n; i++){"+c.replace("_","((i in this) && fn.call(scope,this[i],i,this))")+"}"+d;return Function("fn,scope",b)}function Xa(b,c){try{for(;c=c.parentNode;)if(c===b)return!0;return!1}catch(d){return!1}}function Ya(){return(new XMLSerializer).serializeToString(this)}function t(b){for(var c in b)if(P.call(b,c)){var d=b[c];if("function"===typeof t.plugins[c])t.plugins[c](d);else"object"===typeof t[c]?avalon.mix(t[c],d):t[c]=d}return this}function Za(b){return b.replace(/([a-z\d])([A-Z]+)/g,
-"$1-$2").toLowerCase()}function pa(b){return 0>b.indexOf("-")&&0>b.indexOf("_")?b:b.replace(/[-_][^-_]/g,function(b){return b.charAt(1).toUpperCase()})}function $a(b){if(!("classList"in b)){b.classList={node:b};for(var c in ab)b.classList[c.slice(1)]=ab[c]}return b.classList}function bb(b){try{b="true"===b?!0:"false"===b?!1:"null"===b?null:+b+""===b?+b:Wb.test(b)?avalon.parseJSON(b):b}catch(c){}return b}function cb(b,c){if(0>=b.offsetWidth){if(Xb.test(w["@:get"](b,"display"))){var d={node:b},e;for(e in db)d[e]=
-b.style[e],b.style[e]=db[e];c.push(d)}(d=b.parentNode)&&1===d.nodeType&&cb(d,c)}}function eb(b){var c=b.nodeName;return c.toLowerCase()===c&&b.scopeName&&""===b.outerText}function Yb(b){"url(#default#VML)"!==b.currentStyle.behavior&&(b.style.behavior="url(#default#VML)",b.style.display="inline-block",b.style.zoom=1)}function xa(b){Z[z]=b;avalon.openComputedCollect=!0;var c=b.evaluator;if(c)try{var d=Zb.test(b.type)?b:c.apply(0,b.args);b.handler(d,b.element,b)}catch(e){x("warning:exception throwed in [registerSubscriber] "+
-e),delete b.evaluator,c=b.element,3===c.nodeType&&(d=c.parentNode,t.commentInterpolate?d.replaceChild(p.createComment(b.value),c):c.data=L+b.value+M)}avalon.openComputedCollect=!1;delete Z[z]}function la(b){var c=Z[z];b&&(c&&avalon.Array.ensure(b,c)&&c.element)&&aa.push({data:c,list:b})}function fb(){for(var b=ya,c=ya+$b;b"))&&za(b,c)}}function Ba(b,c){for(var d=0,e;e=b[d++];)e.vmodels=c,C[e.type](e,c),e.evaluator&&(e.element&&1===e.element.nodeType)&&e.element.removeAttribute(e.name);b.length=0}function ob(b,c){0b&&delete c[d.shift()];return c[e]=f}var d=[];return c}function ra(b,c,d){var e=d.type,f=d.filters?d.filters.join(""):"",g=c.map(function(b){return b.$id.replace(kc,"$1")})+b+e+f,h=lc(b).concat(),k=[],l=[],n=[],m="";c=tb(c);for(var q=0,m=c.length;q>0)-(d.clientLeft>>0),c.pageY=b.clientY+(d.scrollTop>>0)-(d.clientTop>>0),c.wheelDeltaY=c.wheelDelta,c.wheelDeltaX=0);c.timeStamp=new Date-0;c.originalEvent=b;c.preventDefault=function(){b.returnValue=!1};c.stopPropagation=function(){b.cancelBubble=!0};return c}function Tb(b){var c=
-[];c.$id=Va();c.$model=b;c.$events={};c.$events[G]=[];c._=J({length:b.length});c._.$watch("length",function(b,d){c.$fire("length",b,d)});for(var d in O)c[d]=O[d];avalon.mix(c,wb);return c}function xb(b,c,d,e){var f=avalon.parseHTML(b.template),g=avalon.slice(f.childNodes);c.appendChild(f);d.$outer=b.$outer;b={nodes:g,vmodels:[d].concat(b.vmodels)};e.push(b)}function Fa(b,c){var d=b.element;if("repeat"==b.type)for(var d=d.nextSibling,e=0;et.maxRepeatSize&&fa.pop()}b.length=0}function R(){p.body&&(E?(s["ready!"].state=2,E.checkDeps()):Bb.forEach(function(b){b(avalon)}),R=A)}function Cb(){try{B.doScroll("left"),R()}catch(b){setTimeout(Cb)}}var z=new Date-0,G="$"+z,r=this||(0,eval)("this"),wc=r.require,xc=r.define,ka=!1,D=/[^, ]+/g,Db=/\[native code\]/,va=/^(?:object|array)$/,Eb=/^\[object SVG\w*Element\]$/,Rb=/^\[object (?:Window|DOMWindow|global)\]$/,Ga=Object.prototype,P=Ga.hasOwnProperty,ja=Ga.toString,
-I=Array.prototype,ba=I.slice,Z={},v=r.dispatchEvent,B=p.documentElement,F=p.getElementsByTagName("head")[0],W=p.createDocumentFragment(),ga=p.createElement("div"),Fb={};"Boolean Number String Function Array Date RegExp Object Error".replace(D,function(b){Fb["[object "+b+"]"]=b.toLowerCase()});avalon=function(b){return new avalon.init(b)};avalon.init=function(b){this[0]=this.element=b};avalon.fn=avalon.prototype=avalon.init.prototype;avalon.type=function(b){return null==b?String(b):"object"===typeof b||
-"function"===typeof b?Fb[ja.call(b)]||"object":typeof b};var U="object"===typeof alert?function(b){try{return/^\s*\bfunction\b/.test(b+"")}catch(c){return!1}}:function(b){return"[object Function]"==ja.call(b)};avalon.isFunction=U;avalon.isWindow=function(b){return!b?!1:b==b.document&&b.document!=b};Wa(r)&&(avalon.isWindow=Wa);avalon.isPlainObject=function(b,c){if(!b||"object"!==avalon.type(b)||b.nodeType||avalon.isWindow(b))return!1;try{if(b.constructor&&!P.call(b,"constructor")&&!P.call(b.constructor.prototype,
-"isPrototypeOf"))return!1}catch(d){return!1}for(c in b);return void 0===c||P.call(b,c)};Db.test(Object.getPrototypeOf)&&(avalon.isPlainObject=function(b){return!!b&&"object"===typeof b&&Object.getPrototypeOf(b)===Ga});avalon.mix=avalon.fn.mix=function(){var b,c,d,e,f,g=arguments[0]||{},h=1,k=arguments.length,l=!1;"boolean"===typeof g&&(l=g,g=arguments[1]||{},h++);"object"!==typeof g&&"function"!==avalon.type(g)&&(g={});h===k&&(g=this,h--);for(;h 0 Then","\t\t["+b+'] = [__proxy__]([__data__],"'+b+'")',"\tEnd If","\tOn Error Goto 0","\tEnd Property");f.push("End Class");b=f.join("\r\n");
-b=r.findOrDefineVBClass(e,b);b===e&&r.parseVB(["Function "+e+"Factory(a, b)","\tDim o","\tSet o = (New "+e+")(a, b)","\tSet "+e+"Factory = o","End Function"].join("\r\n"));return r[b+"Factory"](c,yc)}}if(!"\u53f8\u5f92\u6b63\u7f8e".trim){var zc=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;String.prototype.trim=function(){return this.replace(zc,"")}}var Ac=!{toString:null}.propertyIsEnumerable("toString"),Bc=function(){}.propertyIsEnumerable("prototype"),Gb="toString toLocaleString valueOf hasOwnProperty isPrototypeOf propertyIsEnumerable constructor".split(" "),
-Cc=Gb.length;Object.keys||(Object.keys=function(b){var c=[],d=Bc&&"function"===typeof b;if("string"===typeof b||b&&b.callee)for(d=0;d
-arguments.length&&void 0===b)return this;var c=this,d=arguments;return function(){var e=[],f;for(f=1;fe&&(e+=d);ee&&(e=Math.max(0,d+e));0<=e;e--)if(this[e]===b)return e;return-1},forEach:$("","_",""),filter:$("r=[],j=0,",
-"if(_)r[j++]=this[i]","return r"),map:$("r=[],","r[i]=_","return r"),some:$("","if(_)return true","return false"),every:$("","if(!_)return false","return true")});B.contains||(Node.prototype.contains=function(b){return!!(this.compareDocumentPosition(b)&16)});p.contains||(p.contains=function(b){return Xa(p,b)});if(r.SVGElement){var Hb=p.createElementNS("http://www.w3.org/2000/svg","svg");Hb.innerHTML=' ';if(!Eb.test(Hb.firstChild)){var Ia=function(b,c){if(b&&
-b.childNodes)for(var d=b.childNodes,e=0,f;f=d[e++];)if(f.tagName){var g=p.createElementNS("http://www.w3.org/2000/svg",f.tagName.toLowerCase());I.forEach.call(f.attributes,function(b){g.setAttribute(b.name,b.value)});Ia(f,g);c.appendChild(g)}};Object.defineProperties(SVGElement.prototype,{outerHTML:{enumerable:!0,configurable:!0,get:Ya,set:function(b){var c=this.tagName.toLowerCase(),d=this.parentNode;b=avalon.parseHTML(b);"svg"===c?d.insertBefore(b,this):(c=p.createDocumentFragment(),Ia(b,c),d.insertBefore(c,
-this));d.removeChild(this)}},innerHTML:{enumerable:!0,configurable:!0,get:function(){var b=RegExp(""+this.nodeName+">$","i");return this.outerHTML.replace(RegExp("<"+this.nodeName+'\\b(?:(["\'])[^"]*?(\\1)|[^>])*>',"i"),"").replace(b,"")},set:function(b){avalon.clearHTM&&(avalon.clearHTML(this),b=avalon.parseHTML(b),Ia(b,this))}}})}}!B.outerHTML&&r.HTMLElement&&HTMLElement.prototype.__defineGetter__("outerHTML",Ya);var L,M,ca,Ib,sb,Jb=/[-.*+?^${}()|[\]\/\\]/g,S={loader:function(b){r.define=b?E.define:
-xc;r.require=b?E:wc},interpolate:function(b){L=b[0];M=b[1];if(L===M)throw new SyntaxError("openTag!==closeTag");if("\x3c!--,--\x3e"===b+"")t.commentInterpolate=!0;else{b=L+"test"+M;ga.innerHTML=b;if(ga.innerHTML!==b&&0<=ga.innerHTML.indexOf("<"))throw new SyntaxError("\u6b64\u5b9a\u754c\u7b26\u4e0d\u5408\u6cd5");ga.innerHTML=""}b=(L+"").replace(Jb,"\\$&");var c=(M+"").replace(Jb,"\\$&");ca=RegExp(b+"(.*?)"+c);Ib=RegExp(b+"(.*?)"+c,"g");sb=RegExp(b+".*?"+c+"|\\sms-")}};t.debug=!0;t.plugins=S;t.plugins.interpolate(["{{",
-"}}"]);t.paths={};t.shim={};t.maxRepeatSize=100;avalon.config=t;var ab={_toString:function(){var b=this.node.className;return("string"===typeof b?b:b.baseVal).split(/\s+/).join(" ")},_contains:function(b){return-1<(" "+this+" ").indexOf(" "+b+" ")},_add:function(b){this.contains(b)||this._set(this+" "+b)},_remove:function(b){this._set((" "+this+" ").replace(" "+b+" "," ").trim())},__set:function(b){var c=this.node;"string"===typeof c.className?c.className=b:c.setAttribute("class",b)}};"add,remove".replace(D,
-function(b){avalon.fn[b+"Class"]=function(c){var d=this[0];c&&("string"===typeof c&&d&&1===d.nodeType)&&c.replace(/\S+/g,function(c){$a(d)[b](c)});return this}});avalon.fn.mix({hasClass:function(b){var c=this[0]||{};return 1===c.nodeType&&$a(c).contains(b)},toggleClass:function(b,c){for(var d,e=0,f=b.split(/\s+/),g="boolean"===typeof c;d=f[e++];)this[(g?c:!this.hasClass(d))?"addClass":"removeClass"](d);return this},attr:function(b,c){return 2===arguments.length?(this[0].setAttribute(b,c),this):this[0].getAttribute(b)},
-data:function(b,c){b="data-"+Za(b||"");switch(arguments.length){case 2:return this.attr(b,c),this;case 1:var d=this.attr(b);return bb(d);case 0:var e={};I.forEach.call(this[0].attributes,function(c){c&&(b=c.name,b.indexOf("data-")||(b=pa(b.slice(5)),e[b]=bb(c.value)))});return e}},removeData:function(b){b="data-"+Za(b);this[0].removeAttribute(b);return this},css:function(b,c){if(avalon.isPlainObject(b))for(var d in b)avalon.css(this,d,b[d]);else var e=avalon.css(this,b,c);return void 0!==e?e:this},
-position:function(){var b,c,d=this[0],e={top:0,left:0};if(d)return"fixed"===this.css("position")?c=d.getBoundingClientRect():(b=this.offsetParent(),c=this.offset(),"HTML"!==b[0].tagName&&(e=b.offset()),e.top+=avalon.css(b[0],"borderTopWidth",!0),e.left+=avalon.css(b[0],"borderLeftWidth",!0)),{top:c.top-e.top-avalon.css(d,"marginTop",!0),left:c.left-e.left-avalon.css(d,"marginLeft",!0)}},offsetParent:function(){for(var b=this[0].offsetParent||B;b&&"HTML"!==b.tagName&&"static"===avalon.css(b,"position");)b=
-b.offsetParent;return avalon(b||B)},bind:function(b,c,d){if(this[0])return avalon.bind(this[0],b,c,d)},unbind:function(b,c,d){this[0]&&avalon.unbind(this[0],b,c,d);return this},val:function(b){var c=this[0];if(c&&1===c.nodeType){var d=0===arguments.length,e=d?":get":":set",f=Ja,g;g=c.tagName.toLowerCase();g="input"===g&&/checkbox|radio/.test(c.type)?"checked":g;if(e=f[g+e])var h=e(c,b);else{if(d)return(c.value||"").replace(/\r/g,"");c.value=b}}return d?h:this}});var Wb=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
-Dc=/^[\],:{}\s]*$/,Ec=/(?:^|:|,)(?:\s*\[)+/g,Fc=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,Gc=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g;avalon.parseJSON=r.JSON?JSON.parse:function(b){if("string"===typeof b){if((b=b.trim())&&Dc.test(b.replace(Fc,"@").replace(Gc,"]").replace(Ec,"")))return(new Function("return "+b))();avalon.error("Invalid JSON: "+b)}};avalon.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){avalon.fn[b]=function(d){var e=this[0]||{},f=e.window&&
-e.document?e:9===e.nodeType?e.defaultView||e.parentWindow:!1,g="scrollTop"===b;if(arguments.length)f?f.scrollTo(!g?d:avalon(f).scrollLeft(),g?d:avalon(f).scrollTop()):e[b]=d;else return f?c in f?f[c]:B[b]:e[b]}});var w=avalon.cssHooks={},Kb=["","-webkit-","-o-","-moz-","-ms-"],Ka={"float":"cssFloat",background:"backgroundColor"};avalon.cssNumber=T("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom");avalon.cssName=function(b,c,d){if(Ka[b])return Ka[b];c=c||B.style;
-for(var e=0,f=Kb.length;e=d?"alpha(opacity="+100*d+")":"";c=b.filter||"";b.zoom=1;b.filter=(Lb.test(c)?c.replace(Lb,d):c+" "+d).trim();b.filter||b.removeAttribute("filter")};w["opacity:get"]=function(b){b=b.filters.alpha||b.filters["DXImageTransform.Microsoft.Alpha"];return(b&&b.enabled?b.opacity:100)/100+""}}"top,left".replace(D,function(b){w[b+":get"]=function(c){var d=w["@:get"](c,b);return/px$/.test(d)?d:avalon(c).position()[b]+"px"}});var db={position:"absolute",visibility:"hidden",display:"block"},
-Xb=/^(none|table(?!-c[ea]).+)/;"Width,Height".replace(D,function(b){var c=b.toLowerCase(),d="client"+b,e="scroll"+b,f="offset"+b;w[c+":get"]=function(c,d,e){var l=-4;"number"===typeof e&&(l=e);d="Width"===b?["Left","Right"]:["Top","Bottom"];e=c[f];if(2===l)return e+avalon.css(c,"margin"+d[0],!0)+avalon.css(c,"margin"+d[1],!0);0>l&&(e=e-avalon.css(c,"border"+d[0]+"Width",!0)-avalon.css(c,"border"+d[1]+"Width",!0));-4===l&&(e=e-avalon.css(c,"padding"+d[0],!0)-avalon.css(c,"padding"+d[1],!0));return e};
-w[c+"&get"]=function(b){var d=[];cb(b,d);for(var e=w[c+":get"](b),f=0,n;n=d[f++];){b=n.node;for(var m in n)"string"===typeof n[m]&&(b.style[m]=n[m])}return e};avalon.fn[c]=function(g){var h=this[0];if(0===arguments.length){if(h.setTimeout)return h["inner"+b]||h.document.documentElement[d];if(9===h.nodeType){var k=h.documentElement;return Math.max(h.body[e],k[e],h.body[f],k[f],k[d])}return w[c+"&get"](h)}return this.css(c,g)};avalon.fn["inner"+b]=function(){return w[c+":get"](this[0],void 0,-2)};avalon.fn["outer"+
-b]=function(b){return w[c+":get"](this[0],void 0,!0===b?2:0)}});avalon.fn.offset=function(){var b=this[0],c={left:0,top:0};if(!b||!b.tagName||!b.ownerDocument)return c;var d=b.ownerDocument,e=d.body,f=d.documentElement,d=d.defaultView||d.parentWindow;if(!avalon.contains(f,b))return c;b.getBoundingClientRect&&(c=b.getBoundingClientRect());var b=f.clientTop||e.clientTop,g=f.clientLeft||e.clientLeft,h=Math.max(d.pageYOffset||0,f.scrollTop,e.scrollTop),e=Math.max(d.pageXOffset||0,f.scrollLeft,e.scrollLeft);
-return{top:c.top+h-b,left:c.left+e-g}};var Kc=/^]+))?)*\s+value[\s=]/i,Ja={"option:get":function(b){return b.hasAttribute?b.hasAttribute("value")?b.value:b.text.trim():Kc.test(b.outerHTML)?b.value:b.text},"select:get":function(b,c){for(var d,e=b.options,f=b.selectedIndex,g=Ja["option:get"],h="select-one"===b.type||0>f,k=h?null:[],l=h?f+1:e.length,n=0>f?l:h?f:0;n]*)\/>/ig,Mb=v?/[^\d\D]/:/(<(?:script|link|style|meta|noscript))/ig,Nc=T("text/javascript","text/ecmascript","application/ecmascript","application/javascript","text/vbscript"),Oc=/<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/,y={area:[1,""],param:[1,""],
-col:[2,""],legend:[1,""],option:[1,""],thead:[1,""],tr:[2,""],td:[3,""],text:[1,''," "],_default:v?[0,""]:[1,"X"]};y.optgroup=y.option;y.tbody=y.tfoot=y.colgroup=y.caption=y.thead;y.th=y.td;y.circle=y.ellipse=y.line=y.path=y.polygon=y.polyline=y.rect=y.text;var Pc=p.createElement("script");avalon.parseHTML=
-function(b){"string"!==typeof b&&(b+="");b=b.replace(Mc,"<$1>$2>").trim();var c=(Lc.exec(b)||["",""])[1].toLowerCase(),d=y[c]||y._default,c=W.cloneNode(!1),e=ga,f;v||(b=b.replace(Mb,"
$1"));e.innerHTML=d[1]+b+(d[2]||"");b=e.getElementsByTagName("script");if(b.length)for(var g=0,h;h=b[g++];)if(!h.type||Nc[h.type])f=Pc.cloneNode(!1),I.forEach.call(h.attributes,function(b){b&&b.specified&&(f[b.name]=b.value)}),f.text=h.text,h.parentNode.replaceChild(f,h);for(g=d[0];g--;e=e.lastChild);
-if(!v){b=e.getElementsByTagName("br");for(g=0;h=b[g++];)h.className&&"msNoScope"===h.className&&h.parentNode.removeChild(h);b=e.all;for(g=0;h=b[g++];)eb(h)&&Yb(h)}for(;d=e.firstChild;)c.appendChild(d);return c};avalon.innerHTML=function(b,c){if(!v&&!Mb.test(c)&&!Oc.test(c))try{b.innerHTML=c;return}catch(d){}var e=this.parseHTML(c);this.clearHTML(b).appendChild(e)};avalon.clearHTML=function(b){for(b.textContent="";b.firstChild;)b.removeChild(b.firstChild);return b};var O={$watch:function(b,c){if("function"===
-typeof c){var d=this.$events[b];d?d.push(c):this.$events[b]=[c]}else this.$events=this.$watch.backup;return this},$unwatch:function(b,c){var d=arguments.length;if(0===d)this.$watch.backup=this.$events,this.$events={};else if(1===d)this.$events[b]=[];else for(var d=this.$events[b]||[],e=d.length;0>~--e;)if(d[e]===c)return d.splice(e,1);return this},$fire:function(b){var c;/^(\w+)!(\S+)$/.test(b)&&(c=RegExp.$1,b=RegExp.$2);for(var d=this.$events,e=d[b]||[],f=d.$all||[],g=ba.call(arguments,1),h=0,k;k=
-e[h++];)U(k)&&k.apply(this,g);for(h=0;k=f[h++];)U(k)&&k.apply(this,arguments);if(d=d.expr&&Nb(d.expr)){var l=[b].concat(g);if("up"===c||"down"===c||"all"===c){for(h in avalon.vmodels)if((g=avalon.vmodels[h])&&(g.$events&&g.$events.expr)&&g!==this)if((e=Nb(g.$events.expr))&&("all"===c||("down"===c?d.contains(e):e.contains(d))))e._avalon=g;var h=p.getElementsByTagName("*"),n=[];Array.prototype.forEach.call(h,function(b){b._avalon&&(n.push(b._avalon),b._avalon="",b.removeAttribute("_avalon"))});"up"===
-c&&n.reverse();n.forEach(function(b){b.$fire.apply(b,l)})}}}},Qc=/(\w+)\[(avalonctrl)="(\S+)"\]/,Nb=p.querySelector?function(b){return p.querySelector(b)}:function(b){b=b.match(Qc);for(var c=p.getElementsByTagName(b[1]),d=0,e;e=c[d++];)if(e.getAttribute(b[2])===b[3])return e},Zb=/^(duplex|on)$/,aa=[],ya=0,$b=200,hb=new Date,gb;avalon.scan=function(b,c){b=b||B;var d=c?[].concat(c):[];jb(b,d)};var dc=T("AREA,BASE,BASEFONT,BR,COL,COMMAND,EMBED,HR,IMG,INPUT,LINK,META,PARAM,SOURCE,TRACK,WBR,NOSCRIPT,SCRIPT,STYLE,TEXTAREA"),
-ac=v?15:50,qb=/ms-(\w+)-?(.*)/,rb={"if":10,repeat:90,data:100,widget:110,each:1400,"with":1500,duplex:2E3,on:3E3},cc=T("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit");if(!"1"[0])var Ma=Ca(512),Rc=/\s+(ms-[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g,Sc=/^['"]/,Tc=/<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/i,Uc=/&/g,pb=function(b){b=b.outerHTML;if(""===b.slice(0,2)||!b.trim())return[];b=
-b.match(Tc)[0];var c=[],d,e;if(Ma[b])return Ma[b];for(;d=Rc.exec(b);)(e=d[2])&&(e=(Sc.test(e)?e.slice(1,-1):e).replace(Uc,"&")),d=d[1].toLowerCase(),d.match(qb),c.push({name:d,specified:!0,value:e||""});return Ma(b,c)};var hc=/\|\s*(\w+)\s*(\([^)]*\))?/g,gc=/\|\|/g,ic=/U2hvcnRDaXJjdWl0/g,ec=/</g,fc=/>/g,Vc=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g,Wc=/[^\w$]+/g,Xc=RegExp(""+("\\b"+"break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined".replace(/,/g,
-"\\b|\\b")+"\\b"),"g"),Yc=/\b\d[^,]*/g,Zc=/^,+|,+$/g,Na=Ca(512),lc=function(b){var c=","+b.trim();if(Na[c])return Na[c];b=b.replace(Vc,"").replace(Wc,",").replace(Xc,"").replace(Yc,"").replace(Zc,"").split(/^$|,+/);return Na(c,tb(b))},Da=Ca(128),mc=/\w\[.*\]|\w\.\w/,kc=/(\$proxy\$[a-z]+)\d+$/,$c={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},nc=r.JSON&&JSON.stringify||function(b){return'"'+b.replace(/[\\\"\x00-\x1f]/g,function(b){var d=$c[b];return"string"===typeof d?
-d:"\\u"+("0000"+b.charCodeAt(0).toString(16)).slice(-4)})+'"'};avalon.parseExprProxy=Q;var Oa={"accept-charset":"acceptCharset","char":"ch",charoff:"chOff","class":"className","for":"htmlFor","http-equiv":"httpEquiv"};"accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan,dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight,rowSpan,tabIndex,useMap,vSpace,valueType,vAlign".replace(D,function(b){Oa[b.toLowerCase()]=b});F.insertBefore(avalon.parseHTML(""),
-F.firstChild);var ad=/
(?:[\s\S]+?)<\/noscript>/img,bd=/([\s\S]+?)<\/noscript>/im,Pa=function(){return new (r.XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP")},ha=function(b,c,d){if(b=b.getAttribute(c)){c=0;for(var e;e=d[c++];)if(e.hasOwnProperty(b)&&"function"===typeof e[b])return e[b]}},Qa=avalon.templateCache={};avalon.contains=Xa;var Ra={};"autofocus,autoplay,async,allowTransparency,checked,controls,declare,disabled,defer,defaultChecked,defaultSelectedcontentEditable,isMap,loop,multiple,noHref,noResize,noShade,open,readOnly,selected".replace(D,
-function(b){Ra[b.toLowerCase()]=b});var Ea=avalon.bindingExecutors={attr:function(b,c,d){var e=d.type,f=d.param;if("css"===e)avalon(c).css(f,b);else if("attr"===e){if(Ra[f]&&(d=Ra[f],"boolean"===typeof c[d]))return c[d]=!!b;if(!v&&Oa[f])var f=Oa[f],g=!0;if(!1===b||null===b||void 0===b)return c.removeAttribute(f);r.VBArray&&!g&&(eb(c)?g=!0:Eb.test(c)||(g=(g=(c.attributes||{})[f])?!1===g.expando:null===g));g?c[f]=b:c.setAttribute(f,b)}else if("include"===e&&b){var h=d.vmodels,k=ha(c,"data-include-rendered",
-h),l=ha(c,"data-include-loaded",h),n=function(b){l&&(b=l.apply(c,[b].concat(h)));avalon.innerHTML(c,b);za(c,h);k&&ib(c,function(){k.call(c)})};if("src"===d.param)if(Qa[b])avalon.nextTick(function(){n(Qa[b])});else{var m=Pa();m.onreadystatechange=function(){if(4===m.readyState){var c=m.status;if(200<=c&&300>c||304===c||1223===c)n(Qa[b]=m.responseText)}};m.open("GET",b,!0);"withCredentials"in m&&(m.withCredentials=!0);m.setRequestHeader("X-Requested-With","XMLHttpRequest");m.send(null)}else{var q=b&&
-1===b.nodeType?b:p.getElementById(b);if(q){if("NOSCRIPT"===q.tagName&&!q.innerHTML&&!q.fixIE78){m=Pa();m.open("GET",location,!1);m.send(null);f=p.getElementsByTagName("noscript");g=(m.responseText||"").match(ad)||[];d=g.length;for(e=0;ec||37<=c&&40>=c)||("cut"===b.type?avalon.nextTick(h):h())};H.forEach(function(c){b.attachEvent("on"+c,K)});d.rollback=function(){H.forEach(function(c){b.detachEvent("on"+c,K)})}}b.oldValue=b.value;Pb(function(){if(avalon.contains(B,b))oc.call(b);else if(!b.msRetain)return!1});xa(d);var N=setTimeout(function(){m||e.call(b,b.value);clearTimeout(N)},31)};var vb,ea=[],Pb=A;avalon.tick=function(b){1===ea.push(b)&&(vb=setInterval(pc,
-60))};try{var Sa=HTMLInputElement.prototype;Object.getOwnPropertyNames(Sa);var rc=Object.getOwnPropertyDescriptor(Sa,"value").set;Object.defineProperty(Sa,"value",{set:qc})}catch(kd){Pb=avalon.tick}Y.SELECT=function(b,c,d){var e=avalon(b);d.handler=function(){var d=c(),d=d&&d.$model||d;Array.isArray(d)?b.multiple||x("ms-duplex\u5728\u4e0a\u8981\u6c42\u5bf9\u5e94\u4e00\u4e2a\u6570\u7ec4"):b.multiple&&x("ms-duplex\u5728\u4e0d\u80fd\u5bf9\u5e94\u4e00\u4e2a\u6570\u7ec4");
-d=Array.isArray(d)?d.map(String):d+"";d+""!==b.oldValue&&(e.val(d),b.oldValue=d+"")};d.bound("change",function(){if(!1!==e.data("duplex-observe")){var f=e.val(),f=Array.isArray(f)?f.map(function(b){return X(d,b)}):X(d,f);f+""!==b.oldValue&&c(f);d.changed.call(b,f)}});var f=NaN,g=setInterval(function(){var e=b.innerHTML;e===f?(clearInterval(g),xa(d),d.changed.call(b,c())):f=e},20)};Y.TEXTAREA=Y.INPUT;var ia=avalon.eventHooks;"onmouseenter"in B||avalon.each({mouseenter:"mouseover",mouseleave:"mouseout"},
-function(b,c){ia[b]={type:c,deel:function(c,e){return function(f){var g=f.relatedTarget;if(!g||g!==c&&!(c.compareDocumentPosition(g)&16))return delete f.type,f.type=b,e.call(c,f)}}}});avalon.each({AnimationEvent:"animationend",WebKitAnimationEvent:"webkitAnimationEnd"},function(b,c){r[b]&&!ia.animationend&&(ia.animationend={type:c})});"oninput"in p.createElement("input")||(ia.input={type:"propertychange",deel:function(b,c){return function(d){if("value"===d.propertyName)return d.type="input",c.call(b,
-d)}}});if(void 0===p.onmousewheel){var Qb=void 0!==p.onwheel?"wheel":"DOMMouseScroll",cd="wheel"===Qb?"deltaY":"detail";ia.mousewheel={type:Qb,deel:function(b,c){return function(d){d.wheelDeltaY=d.wheelDelta=0]*>([\S\s]*?)<\/script\s*>/gim,ed=/\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g,fd=/<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig,gd={a:/\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig,img:/\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig,
-form:/\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig},hd=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,id=/([^\#-~| |!])/g,Ua=avalon.filters={uppercase:function(b){return b.toUpperCase()},lowercase:function(b){return b.toLowerCase()},truncate:function(b,c,d){c=c||30;d=void 0===d?"...":d;return b.length>c?b.slice(0,c-d.length)+d:String(b)},camelize:pa,sanitize:function(b){return b.replace(dd,"").replace(fd,function(b,d){var e=b.toLowerCase().match(/<(\w+)\s/);e&&(e=gd[e[1]])&&(b=b.replace(e,function(b,c,
-d){b=d.charAt(0);return c+"="+b+"javascript:void(0)"+b}));return b.replace(ed," ").replace(/\s+/g," ")})},escape:function(b){return String(b).replace(/&/g,"&").replace(hd,function(b){var d=b.charCodeAt(0);b=b.charCodeAt(1);return""+(1024*(d-55296)+(b-56320)+65536)+";"}).replace(id,function(b){return""+b.charCodeAt(0)+";"}).replace(//g,">")},currency:function(b,c){return(c||"\uffe5")+avalon.filters.number(b)},number:function(b,c,d,e){b=(b+"").replace(/[^0-9+\-Ee.]/g,
-"");b=!isFinite(+b)?0:+b;c=!isFinite(+c)?0:Math.abs(c);e=e||",";d=d||".";var f="",f=function(b,c){var d=Math.pow(10,c);return""+Math.round(b*d)/d},f=(c?f(b,c):""+Math.round(b)).split(".");3b&&(e="-",b=-b);for(b=""+b;b.length-e)g+=e;0===g&&-12===e&&(g=12);return b(g,d,f)}}function d(b,c){return function(d,e){var f=d["get"+b](),g=(c?"SHORT"+b:b).toUpperCase();return e[g][f]}}function e(b){var c;if(c=b.match(k)){b=new Date(0);var d=0,e=0,f=c[8]?b.setUTCFullYear:b.setFullYear,g=c[8]?b.setUTCHours:b.setHours;c[9]&&(d=parseInt(c[9]+c[10],10),e=parseInt(c[9]+c[11],10));f.call(b,parseInt(c[1],10),parseInt(c[2],10)-1,parseInt(c[3],10));d=parseInt(c[4]||0,10)-d;e=parseInt(c[5]||0,10)-e;f=parseInt(c[6]||
-0,10);c=Math.round(1E3*parseFloat("0."+(c[7]||0)));g.call(b,d,e,f,c)}return b}var f={yyyy:c("FullYear",4),yy:c("FullYear",2,0,!0),y:c("FullYear",1),MMMM:d("Month"),MMM:d("Month",!0),MM:c("Month",2,1),M:c("Month",1,1),dd:c("Date",2),d:c("Date",1),HH:c("Hours",2),H:c("Hours",1),hh:c("Hours",2,-12),h:c("Hours",1,-12),mm:c("Minutes",2),m:c("Minutes",1),ss:c("Seconds",2),s:c("Seconds",1),sss:c("Milliseconds",3),EEEE:d("Day"),EEE:d("Day",!0),a:function(b,c){return 12>b.getHours()?c.AMPMS[0]:c.AMPMS[1]},
-Z:function(c){c=-1*c.getTimezoneOffset();return c=(0<=c?"+":"")+(b(Math[0e?avalon.error(b+" \u5bf9\u5e94\u8d44\u6e90\u4e0d\u5b58\u5728\u6216\u6ca1\u6709\u5f00\u542f CORS"):(s[d].state=2,s[d].exports=c.responseText,E.checkDeps())}};c.open("GET",
-b,!0);"withCredentials"in c&&(c.withCredentials=!0);c.setRequestHeader("X-Requested-With","XMLHttpRequest");c.send();return d};var q=c(!0);q||(q=avalon.slice(p.scripts).pop().src);q=b(q);m=t.base=q.slice(0,q.lastIndexOf("/")+1);var u=/\/\w+\/\.\./;E=avalon.require=function(b,c,d){var f={},h=[],n=0,q=0,p=d||"callback"+setTimeout("1");d=d||m;String(b).replace(D,function(b){if(b=g(b,d))n++,s[b]&&2===s[b].state&&q++,f[b]||(h.push(b),f[b]="\u53f8\u5f92\u6b63\u7f8e")});s[p]={id:p,factory:c,deps:f,args:h,
-state:1};n===q?k(p,h,c):l.unshift(p);e()};E.define=function(e,f,g){var h=ba.call(arguments);if("string"===typeof e)var k=h.shift();"function"===typeof h[0]&&h.unshift([]);var l=s[k]&&1<=s[k].state?k:b(c());!s[l]&&k&&(s[l]={id:l,factory:g,state:1});g=h[1];g.id=k;g.delay=function(b){h.push(b);var c=!0;try{c=d(s[b].deps,b)}catch(e){}c&&avalon.error(b+"\u6a21\u5757\u4e0e\u4e4b\u524d\u7684\u6a21\u5757\u5b58\u5728\u5faa\u73af\u4f9d\u8d56\uff0c\u8bf7\u4e0d\u8981\u76f4\u63a5\u7528script\u6807\u7b7e\u5f15\u5165"+
-b+"\u6a21\u5757");delete g.delay;E.apply(null,h)};l?g.delay(l,h):n.push(g)};E.define.amd=s;E.config=t;E.checkDeps=e};var Bb=[];"complete"===p.readyState?setTimeout(R):v?p.addEventListener("DOMContentLoaded",R):(p.attachEvent("onreadystatechange",function(){"complete"===p.readyState&&R()}),B.doScroll&&Cb());avalon.bind(r,"load",R);avalon.ready=function(b){E?E("ready!",b):R===A?b(avalon):Bb.push(b)};avalon.config({loader:!0});avalon.ready(function(){avalon.scan(p.body)})})(document);
+(function(p){function y(){}function v(){r.console&&avalon.config.debug&&Function.apply.call(console.log,console,arguments)}function M(b,c){"string"===typeof b&&(b=b.match(z)||[]);for(var d={},e=void 0!==c?c:1,f=0,g=b.length;fb?Math.max(c+b,0):Math.min(b,c)}function Wb(b,c,
+d){if(V(c)||c&&c.nodeType||-1!==d.indexOf(b)||-1!==ta.indexOf(b))return!1;c=d.$special;return b&&"$"===b.charAt(0)&&!c[b]?!1:!0}function N(b,c,d){if(Array.isArray(b)){var e=b.concat();b.length=0;c=Xb(b);c.pushArray(e);return c}if("number"===typeof b.nodeType||b.$id&&b.$model&&b.$events)return b;Array.isArray(b.$skipArray)||(b.$skipArray=[]);b.$skipArray.$special=c||{};var f={};d=d||{};var g={},h={},k=[];for(e in b)(function(c,e){d[c]=e;if(Wb(c,e,b.$skipArray)){var l,t=avalon.type(e);g[c]=[];if("object"===
+t&&V(e.get)&&2>=Object.keys(e).length){var H=e.set,F=e.get;l=function(b){var e=f.$events,g=d[c];if(arguments.length){if(ja)return;if(V(H)){var h=e[c];e[c]=[];H.call(f,b);e[c]=h}}else avalon.openComputedCollect&&ka(e[c]);b=d[c]=F.call(f);if(!la(g,b)){if(ma&&(h=W[f.$id])&&h[c])h[c].$val=b;va(e[c]);f.$events&&R.$fire.call(f,c,b,g)}return b};k.push(function(){Y[A]={evaluator:l,element:J,type:"computed::"+c,handler:y,args:[]};l();ka(g[c]);delete Y[A]})}else wa.test(t)?(l=function(b){var e=l.child,h=d[c];
+if(arguments.length)!ja&&!la(h,b)&&(e=l.child=Yb(f,c,b,t),b=d[c]=e.$model,(e=xa[e.$id])&&e(),f.$events&&R.$fire.call(f,c,b,h));else return ka(g[c]),e},(l.child=N(e,0,d[c])).$events[G]=g[c]):l=function(b){var e=d[c];if(arguments.length){if(!la(e,b)){d[c]=b;if(ma){var h=W[f.$id];h&&h[c]&&(h[c].$val=b)}va(g[c]);f.$events&&R.$fire.call(f,c,b,e)}}else return ka(g[c]),e};h[c]=l}})(e,b[e]);ta.forEach(function(c){delete b[c];delete d[c]});var f=na(f,Zb(h),b),l;for(l in b)h[l]||(f[l]=b[l]);f.$id=ha();f.$model=
+d;f.$events=g;for(e in R)c=R[e],w||(c=c.bind(f)),f[e]=c;f.hasOwnProperty=function(b){return b in f.$model};k.forEach(function(b){b()});return f}function Yb(b,c,d,e){var f=b[c];if("array"===e){if(!Array.isArray(d)||f===d)return f;f.clear();f.pushArray(d.concat());return f}var g=b.$events[c];W[f.$id]&&(ma--,delete W[f.$id]);var h=N(d);h.$events[G]=g;xa[h.$id]=function(b){for(;b=g.shift();)(function(b){b.type&&avalon.nextTick(function(){b.rollback&&b.rollback();C[b.type](b,b.vmodels)})})(b);delete xa[h.$id]};
+return h}function Z(b,c,d){b="for(var "+b+"i=0,n = this.length; i < n; i++){"+c.replace("_","((i in this) && fn.call(scope,this[i],i,this))")+"}"+d;return Function("fn,scope",b)}function Za(b,c){try{for(;c=c.parentNode;)if(c===b)return!0;return!1}catch(d){return!1}}function $a(){return(new XMLSerializer).serializeToString(this)}function u(b){for(var c in b)if(O.call(b,c)){var d=b[c];if("function"===typeof u.plugins[c])u.plugins[c](d);else"object"===typeof u[c]?avalon.mix(u[c],d):u[c]=d}return this}
+function ab(b){return b.replace(/([a-z\d])([A-Z]+)/g,"$1-$2").toLowerCase()}function oa(b){return 0>b.indexOf("-")&&0>b.indexOf("_")?b:b.replace(/[-_][^-_]/g,function(b){return b.charAt(1).toUpperCase()})}function bb(b){if(!("classList"in b)){b.classList={node:b};for(var c in cb)b.classList[c.slice(1)]=cb[c]}return b.classList}function db(b){try{b="true"===b?!0:"false"===b?!1:"null"===b?null:+b+""===b?+b:$b.test(b)?avalon.parseJSON(b):b}catch(c){}return b}function eb(b,c){if(0>=b.offsetWidth){if(ac.test(x["@:get"](b,
+"display"))){var d={node:b},e;for(e in fb)d[e]=b.style[e],b.style[e]=fb[e];c.push(d)}(d=b.parentNode)&&1===d.nodeType&&eb(d,c)}}function gb(b){var c=b.nodeName;return c.toLowerCase()===c&&b.scopeName&&""===b.outerText}function bc(b){"url(#default#VML)"!==b.currentStyle.behavior&&(b.style.behavior="url(#default#VML)",b.style.display="inline-block",b.style.zoom=1)}function ya(b){Y[A]=b;avalon.openComputedCollect=!0;var c=b.evaluator;if(c)try{var d=cc.test(b.type)?b:c.apply(0,b.args);b.handler(d,b.element,
+b)}catch(e){v("warning:exception throwed in [registerSubscriber] "+e),delete b.evaluator,c=b.element,3===c.nodeType&&(d=c.parentNode,u.commentInterpolate?d.replaceChild(p.createComment(b.value),c):c.data=P+b.value+Q)}avalon.openComputedCollect=!1;delete Y[A]}function ka(b){var c=Y[A];b&&(c&&avalon.Array.ensure(b,c)&&c.element)&&hb(c,b)}function hb(b,c){b.$uuid=b.$uuid||ha();c.$uuid=c.$uuid||ha();var d={data:b,list:c,toString:function(){return b.$uuid+" "+c.$uuid}};S[d]||(S[d]=1,S.push(d))}function ib(){for(var b=
+za,c=za+dc;b"))&&ob(b,c)}}function Ca(b,c){b.length&&c.cb(b.length);for(var d=0,e;e=b[d++];)e.vmodels=c,C[e.type](e,c),e.evaluator&&(e.element&&1===e.element.nodeType)&&e.element.removeAttribute(e.name);b.length=0}function rb(b,c){0b&&delete c[d.shift()];return c[e]=f}var d=[];return c}function xb(b,c,d){var e=d.type,f=d.filters?d.filters.join(""):"",g=c.map(function(b){return b.$id.replace(oc,"$1")})+b+e+f,h=pc(b).concat(),k=[],l=[],m=[],n="";c=wb(c);for(var q=0,n=c.length;q>0)-(d.clientLeft>>0),c.pageY=b.clientY+(d.scrollTop>>0)-(d.clientTop>>0),c.wheelDeltaY=c.wheelDelta,c.wheelDeltaX=0);c.timeStamp=new Date-0;c.originalEvent=b;c.preventDefault=function(){b.returnValue=!1};c.stopPropagation=
+function(){b.cancelBubble=!0};return c}function Xb(b){var c=[];c.$id=ha();c.$model=b;c.$events={};c.$events[G]=[];c._=N({length:b.length});c._.$watch("length",function(b,d){c.$fire("length",b,d)});for(var d in R)c[d]=R[d];avalon.mix(c,Ab);return c}function Bb(b,c,d,e){var f=avalon.parseHTML(b.template),g=avalon.slice(f.childNodes);c.appendChild(f);d.$outer=b.$outer;b=b.vmodels;d=[d].concat(b);d.cb=b.cb;e.push({nodes:g,vmodels:d})}function Ha(b,c){var d=b.endRepeat,e=[],f=b.element.nextSibling;if(f!==
+d){do if(f!==d)e.push(f);else break;while(f=f.nextSibling)}return e[b.group*c]||d}function Cb(b,c,d){c*=d||1;d=[b];for(var e=1,f=I;eu.maxRepeatSize&&da.pop()}b.length=0}function T(){p.body&&(D?(s["ready!"].state=2,D.checkDeps()):Fb.forEach(function(b){b(avalon)}),T=y)}function Gb(){try{B.doScroll("left"),T()}catch(b){setTimeout(Gb)}}var A=new Date-0,G="$"+A,r=Function("return this")(),Ac=r.require,Bc=r.define,ja=!1,z=/[^, ]+/g,Hb=/\[native code\]/,wa=/^(?:object|array)$/,Ib=/^\[object SVG\w*Element\]$/,Vb=/^\[object (?:Window|DOMWindow|global)\]$/,
+Ia=Object.prototype,O=Ia.hasOwnProperty,ia=Ia.toString,L=Array.prototype,$=L.slice,Y={},w=r.dispatchEvent,B=p.documentElement,J=p.getElementsByTagName("head")[0],I=p.createDocumentFragment(),ea=p.createElement("div"),Jb={};"Boolean Number String Function Array Date RegExp Object Error".replace(z,function(b){Jb["[object "+b+"]"]=b.toLowerCase()});avalon=function(b){return new avalon.init(b)};avalon.init=function(b){this[0]=this.element=b};avalon.fn=avalon.prototype=avalon.init.prototype;avalon.type=
+function(b){return null==b?String(b):"object"===typeof b||"function"===typeof b?Jb[ia.call(b)]||"object":typeof b};var V="object"===typeof alert?function(b){try{return/^\s*\bfunction\b/.test(b+"")}catch(c){return!1}}:function(b){return"[object Function]"==ia.call(b)};avalon.isFunction=V;avalon.isWindow=function(b){return!b?!1:b==b.document&&b.document!=b};Ya(r)&&(avalon.isWindow=Ya);for(var Cc in avalon({}))break;var Dc="0"!==Cc;avalon.isPlainObject=function(b,c){if(!b||"object"!==avalon.type(b)||
+b.nodeType||avalon.isWindow(b))return!1;try{if(b.constructor&&!O.call(b,"constructor")&&!O.call(b.constructor.prototype,"isPrototypeOf"))return!1}catch(d){return!1}if(Dc)for(c in b)return O.call(b,c);for(c in b);return void 0===c||O.call(b,c)};Hb.test(Object.getPrototypeOf)&&(avalon.isPlainObject=function(b){return!!b&&"object"===typeof b&&Object.getPrototypeOf(b)===Ia});avalon.mix=avalon.fn.mix=function(){var b,c,d,e,f,g=arguments[0]||{},h=1,k=arguments.length,l=!1;"boolean"===typeof g&&(l=g,g=arguments[1]||
+{},h++);"object"!==typeof g&&"function"!==avalon.type(g)&&(g={});h===k&&(g=this,h--);for(;h 0 Then","\t\t["+b+'] = [__proxy__]([__data__],"'+b+'")',"\tEnd If","\tOn Error Goto 0","\tEnd Property");f.push("End Class");b=f.join("\r\n");
+b=r.findOrDefineVBClass(e,b);b===e&&r.parseVB(["Function "+e+"Factory(a, b)","\tDim o","\tSet o = (New "+e+")(a, b)","\tSet "+e+"Factory = o","End Function"].join("\r\n"));return r[b+"Factory"](c,Ec)}}if(!"\u53f8\u5f92\u6b63\u7f8e".trim){var Fc=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;String.prototype.trim=function(){return this.replace(Fc,"")}}var Gc=!{toString:null}.propertyIsEnumerable("toString"),Hc=function(){}.propertyIsEnumerable("prototype"),Kb="toString toLocaleString valueOf hasOwnProperty isPrototypeOf propertyIsEnumerable constructor".split(" "),
+Ic=Kb.length;Object.keys||(Object.keys=function(b){var c=[],d=Hc&&"function"===typeof b;if("string"===typeof b||b&&b.callee)for(d=0;d
+arguments.length&&void 0===b)return this;var c=this,d=arguments;return function(){var e=[],f;for(f=1;fe&&(e+=d);ee&&(e=Math.max(0,d+e));0<=e;e--)if(this[e]===b)return e;return-1},forEach:Z("","_",""),filter:Z("r=[],j=0,",
+"if(_)r[j++]=this[i]","return r"),map:Z("r=[],","r[i]=_","return r"),some:Z("","if(_)return true","return false"),every:Z("","if(!_)return false","return true")});B.contains||(Node.prototype.contains=function(b){return!!(this.compareDocumentPosition(b)&16)});p.contains||(p.contains=function(b){return Za(p,b)});if(r.SVGElement){var Lb=p.createElementNS("http://www.w3.org/2000/svg","svg");Lb.innerHTML=' ';if(!Ib.test(Lb.firstChild)){var Ka=function(b,c){if(b&&
+b.childNodes)for(var d=b.childNodes,e=0,f;f=d[e++];)if(f.tagName){var g=p.createElementNS("http://www.w3.org/2000/svg",f.tagName.toLowerCase());L.forEach.call(f.attributes,function(b){g.setAttribute(b.name,b.value)});Ka(f,g);c.appendChild(g)}};Object.defineProperties(SVGElement.prototype,{outerHTML:{enumerable:!0,configurable:!0,get:$a,set:function(b){var c=this.tagName.toLowerCase(),d=this.parentNode;b=avalon.parseHTML(b);"svg"===c?d.insertBefore(b,this):(c=p.createDocumentFragment(),Ka(b,c),d.insertBefore(c,
+this));d.removeChild(this)}},innerHTML:{enumerable:!0,configurable:!0,get:function(){var b=RegExp(""+this.nodeName+">$","i");return this.outerHTML.replace(RegExp("<"+this.nodeName+'\\b(?:(["\'])[^"]*?(\\1)|[^>])*>',"i"),"").replace(b,"")},set:function(b){avalon.clearHTML&&(avalon.clearHTML(this),b=avalon.parseHTML(b),Ka(b,this))}}})}}!B.outerHTML&&r.HTMLElement&&HTMLElement.prototype.__defineGetter__("outerHTML",$a);var P,Q,aa,Mb,vb,Nb=/[-.*+?^${}()|[\]\/\\]/g,D=y,U={loader:function(b){r.define=
+b?D.define:Bc;r.require=b?D:Ac},interpolate:function(b){P=b[0];Q=b[1];if(P===Q)throw new SyntaxError("openTag!==closeTag");if("\x3c!--,--\x3e"===b+"")u.commentInterpolate=!0;else{b=P+"test"+Q;ea.innerHTML=b;if(ea.innerHTML!==b&&0<=ea.innerHTML.indexOf("<"))throw new SyntaxError("\u6b64\u5b9a\u754c\u7b26\u4e0d\u5408\u6cd5");ea.innerHTML=""}b=(P+"").replace(Nb,"\\$&");var c=(Q+"").replace(Nb,"\\$&");aa=RegExp(b+"(.*?)"+c);Mb=RegExp(b+"(.*?)"+c,"g");vb=RegExp(b+".*?"+c+"|\\sms-")}};u.debug=!0;u.plugins=
+U;u.plugins.interpolate(["{{","}}"]);u.paths={};u.shim={};u.maxRepeatSize=100;avalon.config=u;var cb={_toString:function(){var b=this.node.className;return("string"===typeof b?b:b.baseVal).split(/\s+/).join(" ")},_contains:function(b){return-1<(" "+this+" ").indexOf(" "+b+" ")},_add:function(b){this.contains(b)||this._set(this+" "+b)},_remove:function(b){this._set((" "+this+" ").replace(" "+b+" "," ").trim())},__set:function(b){var c=this.node;"string"===typeof c.className?c.className=b:c.setAttribute("class",
+b)}};"add,remove".replace(z,function(b){avalon.fn[b+"Class"]=function(c){var d=this[0];c&&("string"===typeof c&&d&&1===d.nodeType)&&c.replace(/\S+/g,function(c){bb(d)[b](c)});return this}});avalon.fn.mix({hasClass:function(b){var c=this[0]||{};return 1===c.nodeType&&bb(c).contains(b)},toggleClass:function(b,c){for(var d,e=0,f=b.split(/\s+/),g="boolean"===typeof c;d=f[e++];)this[(g?c:!this.hasClass(d))?"addClass":"removeClass"](d);return this},attr:function(b,c){return 2===arguments.length?(this[0].setAttribute(b,
+c),this):this[0].getAttribute(b)},data:function(b,c){b="data-"+ab(b||"");switch(arguments.length){case 2:return this.attr(b,c),this;case 1:var d=this.attr(b);return db(d);case 0:var e={};L.forEach.call(this[0].attributes,function(c){c&&(b=c.name,b.indexOf("data-")||(b=oa(b.slice(5)),e[b]=db(c.value)))});return e}},removeData:function(b){b="data-"+ab(b);this[0].removeAttribute(b);return this},css:function(b,c){if(avalon.isPlainObject(b))for(var d in b)avalon.css(this,d,b[d]);else var e=avalon.css(this,
+b,c);return void 0!==e?e:this},position:function(){var b,c,d=this[0],e={top:0,left:0};if(d)return"fixed"===this.css("position")?c=d.getBoundingClientRect():(b=this.offsetParent(),c=this.offset(),"HTML"!==b[0].tagName&&(e=b.offset()),e.top+=avalon.css(b[0],"borderTopWidth",!0),e.left+=avalon.css(b[0],"borderLeftWidth",!0)),{top:c.top-e.top-avalon.css(d,"marginTop",!0),left:c.left-e.left-avalon.css(d,"marginLeft",!0)}},offsetParent:function(){for(var b=this[0].offsetParent||B;b&&"HTML"!==b.tagName&&
+"static"===avalon.css(b,"position");)b=b.offsetParent;return avalon(b||B)},bind:function(b,c,d){if(this[0])return avalon.bind(this[0],b,c,d)},unbind:function(b,c,d){this[0]&&avalon.unbind(this[0],b,c,d);return this},val:function(b){var c=this[0];if(c&&1===c.nodeType){var d=0===arguments.length,e=d?":get":":set",f=La,g;g=c.tagName.toLowerCase();g="input"===g&&/checkbox|radio/.test(c.type)?"checked":g;if(e=f[g+e])var h=e(c,b);else{if(d)return(c.value||"").replace(/\r/g,"");c.value=b}}return d?h:this}});
+var $b=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,Jc=/^[\],:{}\s]*$/,Kc=/(?:^|:|,)(?:\s*\[)+/g,Lc=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,Mc=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g;avalon.parseJSON=r.JSON?JSON.parse:function(b){if("string"===typeof b){if((b=b.trim())&&Jc.test(b.replace(Lc,"@").replace(Mc,"]").replace(Kc,"")))return(new Function("return "+b))();avalon.error("Invalid JSON: "+b)}};avalon.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){avalon.fn[b]=function(d){var e=
+this[0]||{},f=e.window&&e.document?e:9===e.nodeType?e.defaultView||e.parentWindow:!1,g="scrollTop"===b;if(arguments.length)f?f.scrollTo(!g?d:avalon(f).scrollLeft(),g?d:avalon(f).scrollTop()):e[b]=d;else return f?c in f?f[c]:B[b]:e[b]}});var x=avalon.cssHooks={},Ob=["","-webkit-","-o-","-moz-","-ms-"],Ma={"float":"cssFloat"};avalon.cssNumber=M("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom");avalon.cssName=function(b,c,d){if(Ma[b])return Ma[b];c=c||B.style;
+for(var e=0,f=Ob.length;e=d?"alpha(opacity="+100*d+")":"";c=b.filter||"";b.zoom=1;b.filter=(Pb.test(c)?c.replace(Pb,d):c+" "+d).trim();b.filter||b.removeAttribute("filter")};x["opacity:get"]=function(b){b=b.filters.alpha||b.filters["DXImageTransform.Microsoft.Alpha"];return(b&&b.enabled?b.opacity:100)/100+""}}"top,left".replace(z,function(b){x[b+":get"]=function(c){var d=x["@:get"](c,b);return/px$/.test(d)?d:avalon(c).position()[b]+"px"}});var fb={position:"absolute",visibility:"hidden",display:"block"},
+ac=/^(none|table(?!-c[ea]).+)/;"Width,Height".replace(z,function(b){var c=b.toLowerCase(),d="client"+b,e="scroll"+b,f="offset"+b;x[c+":get"]=function(c,d,e){var l=-4;"number"===typeof e&&(l=e);d="Width"===b?["Left","Right"]:["Top","Bottom"];e=c[f];if(2===l)return e+avalon.css(c,"margin"+d[0],!0)+avalon.css(c,"margin"+d[1],!0);0>l&&(e=e-avalon.css(c,"border"+d[0]+"Width",!0)-avalon.css(c,"border"+d[1]+"Width",!0));-4===l&&(e=e-avalon.css(c,"padding"+d[0],!0)-avalon.css(c,"padding"+d[1],!0));return e};
+x[c+"&get"]=function(b){var d=[];eb(b,d);for(var e=x[c+":get"](b),f=0,m;m=d[f++];){b=m.node;for(var n in m)"string"===typeof m[n]&&(b.style[n]=m[n])}return e};avalon.fn[c]=function(g){var h=this[0];if(0===arguments.length){if(h.setTimeout)return h["inner"+b]||h.document.documentElement[d];if(9===h.nodeType){var k=h.documentElement;return Math.max(h.body[e],k[e],h.body[f],k[f],k[d])}return x[c+"&get"](h)}return this.css(c,g)};avalon.fn["inner"+b]=function(){return x[c+":get"](this[0],void 0,-2)};avalon.fn["outer"+
+b]=function(b){return x[c+":get"](this[0],void 0,!0===b?2:0)}});avalon.fn.offset=function(){var b=this[0],c={left:0,top:0};if(!b||!b.tagName||!b.ownerDocument)return c;var d=b.ownerDocument,e=d.body,f=d.documentElement,d=d.defaultView||d.parentWindow;if(!avalon.contains(f,b))return c;b.getBoundingClientRect&&(c=b.getBoundingClientRect());var b=f.clientTop||e.clientTop,g=f.clientLeft||e.clientLeft,h=Math.max(d.pageYOffset||0,f.scrollTop,e.scrollTop),e=Math.max(d.pageXOffset||0,f.scrollLeft,e.scrollLeft);
+return{top:c.top+h-b,left:c.left+e-g}};var Qc=/^]+))?)*\s+value[\s=]/i,La={"option:get":r.VBArray?function(b){return Qc.test(b.outerHTML)?b.value:b.text.trim()}:function(b){return b.value},"select:get":function(b,c){for(var d,e=b.options,f=b.selectedIndex,g=La["option:get"],h="select-one"===b.type||0>f,k=h?null:[],l=h?f+1:e.length,m=0>f?l:h?f:0;m"],param:[1,""],col:[2,""],legend:[1,""],option:[1,""],thead:[1,""],tr:[2,""],td:[3,""],g:[1,''," "],_default:w?
+[0,""]:[1,"X"]};E.optgroup=E.option;E.tbody=E.tfoot=E.colgroup=E.caption=E.thead;E.th=E.td;"circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use".replace(z,function(b){E[b]=E.g});var Rc=/<([\w:]+)/,Sc=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Qb=w?/[^\d\D]/:/(<(?:script|link|style|meta|noscript))/ig,Tc=M(["","text/javascript","text/ecmascript","application/ecmascript","application/javascript"]),Uc=/<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/,
+Vc=p.createElement("script");avalon.parseHTML=function(b){"string"!==typeof b&&(b+="");b=b.replace(Sc,"<$1>$2>").trim();var c=(Rc.exec(b)||["",""])[1].toLowerCase(),d=E[c]||E._default,e=I.cloneNode(!1),f=ea,g;w||(b=b.replace(Qb,"
$1"));f.innerHTML=d[1]+b+(d[2]||"");b=f.getElementsByTagName("script");if(b.length)for(var h=0,k;k=b[h++];)Tc[k.type]&&(g=Vc.cloneNode(!1),L.forEach.call(k.attributes,function(b){b&&b.specified&&(g[b.name]=b.value,g.setAttribute(b.name,b.value))}),g.text=
+k.text,k.parentNode.replaceChild(g,k));for(h=d[0];h--;f=f.lastChild);if(!w){b=f.getElementsByTagName("br");for(h=0;k=b[h++];)k.className&&"msNoScope"===k.className&&(k.parentNode.removeChild(k),h--);b=f.all;for(h=0;k=b[h++];)gb(k)&&bc(k);if("tr"===c){b=f.children;for(h=0;k=b[h++];)""==k.nodeName&&(k.parentNode.removeChild(k),h--)}}for(;c=f.firstChild;)e.appendChild(c);return e};avalon.innerHTML=function(b,c){if(!w&&!Qb.test(c)&&!Uc.test(c))try{b.innerHTML=c;return}catch(d){}var e=this.parseHTML(c);
+this.clearHTML(b).appendChild(e)};avalon.clearHTML=function(b){for(b.textContent="";b.firstChild;)b.removeChild(b.firstChild);return b};var R={$watch:function(b,c){if("function"===typeof c){var d=this.$events[b];d?d.push(c):this.$events[b]=[c]}else this.$events=this.$watch.backup;return this},$unwatch:function(b,c){var d=arguments.length;if(0===d)this.$watch.backup=this.$events,this.$events={};else if(1===d)this.$events[b]=[];else for(var d=this.$events[b]||[],e=d.length;0>~--e;)if(d[e]===c)return d.splice(e,
+1);return this},$fire:function(b){var c;/^(\w+)!(\S+)$/.test(b)&&(c=RegExp.$1,b=RegExp.$2);var d=this.$events,e=$.call(arguments,1),f=[b].concat(e);if("all"===c)for(var g in avalon.vmodels)e=avalon.vmodels[g],e!==this&&e.$fire.apply(e,f);else if("up"===c||"down"===c){if(d=d.expr&&Rb(d.expr)){for(g in avalon.vmodels)if(e=avalon.vmodels[g],e!==this&&e.$events.expr){var h=Rb(e.$events.expr);if(h&&("down"===c?d.contains(h):h.contains(d)))h._avalon=e}g=p.getElementsByTagName("*");var k=[];Array.prototype.forEach.call(g,
+function(b){b._avalon&&(k.push(b._avalon),b._avalon="",b.removeAttribute("_avalon"))});"up"===c&&k.reverse();for(g=0;(c=k[g++])&&!1!==c.$fire.apply(c,f););}}else{f=d[b]||[];c=d.$all||[];for(g=0;d=f[g++];)V(d)&&d.apply(this,e);for(g=0;d=c[g++];)V(d)&&d.apply(this,arguments)}}},Wc=/(\w+)\[(avalonctrl)="(\S+)"\]/,Rb=p.querySelector?function(b){return p.querySelector(b)}:function(b){b=b.match(Wc);for(var c=p.getElementsByTagName(b[1]),d=0,e;e=c[d++];)if(e.getAttribute(b[2])===b[3])return e},cc=/^(duplex|on)$/,
+S=[],za=0,dc=200,jb=new Date,kb,Oa={};avalon.scanCallback=function(b,c){c=c||"$all";(Oa[c]||(Oa[c]=[])).push(b)};avalon.scan=function(b,c,d){b=b||B;var e=Oa[d||"$all"]||[];c=c?[].concat(c):[];var f=0,g=!1,h,k=!1;c.cb=function(b){f+=b;k=!0;setTimeout(function(){if(0>=f&&!g)for(g=!0;h=e.shift();)h()})};lb(b,c);if(!k)for(;h=e.shift();)h()};var hc=M("AREA,BASE,BASEFONT,BR,COL,COMMAND,EMBED,HR,IMG,INPUT,LINK,META,PARAM,SOURCE,TRACK,WBR,NOSCRIPT,SCRIPT,STYLE,TEXTAREA"),tb=/ms-(\w+)-?(.*)/,ub={"if":10,repeat:90,
+data:100,widget:110,each:1400,"with":1500,duplex:2E3,on:3E3},fc=M("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit"),gc=M("value,title,alt,checked,selected,disabled,readonly,enabled");if(!"1"[0])var Pa=Da(512),Xc=/\s+(ms-[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g,Yc=/^['"]/,Zc=/<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/i,$c=/&/g,sb=function(b){b=b.outerHTML;if(""===b.slice(0,2)||!b.trim())return[];
+b=b.match(Zc)[0];var c=[],d,e;if(Pa[b])return Pa[b];for(;d=Xc.exec(b);)(e=d[2])&&(e=(Yc.test(e)?e.slice(1,-1):e).replace($c,"&")),d=d[1].toLowerCase(),d.match(tb),c.push({name:d,specified:!0,value:e||""});return Pa(b,c)};var lc=/\|\s*(\w+)\s*(\([^)]*\))?/g,kc=/\|\|/g,mc=/U2hvcnRDaXJjdWl0/g,ic=/</g,jc=/>/g,ad=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g,bd=/[^\w$]+/g,cd=RegExp(""+("\\b"+"break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined".replace(/,/g,
+"\\b|\\b")+"\\b"),"g"),dd=/\b\d[^,]*/g,ed=/^,+|,+$/g,Qa=Da(512),pc=function(b){var c=","+b.trim();if(Qa[c])return Qa[c];b=b.replace(ad,"").replace(bd,",").replace(cd,"").replace(dd,"").replace(ed,"").split(/^$|,+/);return Qa(c,wb(b))},Ea=Da(128),qc=/\w\[.*\]|\w\.\w/,oc=/(\$proxy\$[a-z]+)\d+$/,fd={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rc=r.JSON&&JSON.stringify||function(b){return'"'+b.replace(/[\\\"\x00-\x1f]/g,function(b){var d=fd[b];return"string"===typeof d?
+d:"\\u"+("0000"+b.charCodeAt(0).toString(16)).slice(-4)})+'"'};avalon.parseExprProxy=K;var Ra={"accept-charset":"acceptCharset","char":"ch",charoff:"chOff","class":"className","for":"htmlFor","http-equiv":"httpEquiv"};"accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan,dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight,rowSpan,tabIndex,useMap,vSpace,valueType,vAlign".replace(z,function(b){Ra[b.toLowerCase()]=b});var pa=J.insertBefore(document.createElement("avalon"),
+J.firstChild);pa.innerHTML="X";var gd=/
(?:[\s\S]+?)<\/noscript>/img,hd=/([\s\S]+?)<\/noscript>/im,Sa=function(){return new (r.XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP")},fa=function(b,c,d){if(b=b.getAttribute(c)){c=0;for(var e;e=d[c++];)if(e.hasOwnProperty(b)&&"function"===typeof e[b])return e[b]}},Ta=avalon.templateCache={};avalon.contains=Za;var Ua={};"autofocus,autoplay,async,allowTransparency,checked,controls,declare,disabled,defer,defaultChecked,defaultSelectedcontentEditable,isMap,loop,multiple,noHref,noResize,noShade,open,readOnly,selected".replace(z,
+function(b){Ua[b.toLowerCase()]=b});var Fa=avalon.bindingExecutors={attr:function(b,c,d){var e=d.type,f=d.param;if("css"===e)avalon(c).css(f,b);else if("attr"===e){if(Ua[f]&&(e=Ua[f],"boolean"===typeof c[e]))return c[e]=!!b;!w&&Ra[f]&&(f=Ra[f]);if(!1===b||null===b||void 0===b)return c.removeAttribute(f);(Ib.test(c)?0:p.namespaces&&gb(c)||f in c.cloneNode(!1))?c[f]=b:c.setAttribute(f,b)}else if("include"===e&&b){var g=d.vmodels,h=d.includeRendered,k=d.includeLoaded,l=d.includeReplaced?c.parentNode:
+c;g.cb(1);var m=function(b){k&&(b=k.apply(l,[b].concat(g)));for(h&&qa(l,function(){h.call(l)},NaN);;){var c=d.startInclude.nextSibling;if(c&&c!==d.endInclude)l.removeChild(c);else break}b=avalon.parseHTML(b);c=avalon.slice(b.childNodes);l.insertBefore(b,d.endInclude);Aa(c,g);g.cb(-1)};if("src"===d.param)if(Ta[b])avalon.nextTick(function(){m(Ta[b])});else{var n=Sa();n.onreadystatechange=function(){if(4===n.readyState){var c=n.status;if(200<=c&&300>c||304===c||1223===c)m(Ta[b]=n.responseText)}};n.open("GET",
+b,!0);"withCredentials"in n&&(n.withCredentials=!0);n.setRequestHeader("X-Requested-With","XMLHttpRequest");n.send(null)}else{var q=b&&1===b.nodeType?b:p.getElementById(b);if(q){if("NOSCRIPT"===q.tagName&&!q.innerHTML&&!q.fixIE78){n=Sa();n.open("GET",location,!1);n.send(null);c=p.getElementsByTagName("noscript");for(var f=(n.responseText||"").match(gd)||[],e=f.length,t=0;t\u4e0a\u8981\u6c42\u5bf9\u5e94\u4e00\u4e2a\u6570\u7ec4"):b.multiple&&v("ms-duplex\u5728\u4e0d\u80fd\u5bf9\u5e94\u4e00\u4e2a\u6570\u7ec4");d=Array.isArray(d)?d.map(String):d+"";d+""!==b.oldValue&&(e.val(d),
+b.oldValue=d+"")};d.bound("change",function(){if(!1!==e.data("duplex-observe")){var f=e.val(),f=Array.isArray(f)?f.map(function(b){return d.pipe(b,d,"get")}):d.pipe(f,d,"get");f+""!==b.oldValue&&c(f);d.changed.call(b,f,d)}});qa(b,function(){ya(d);d.changed.call(b,c(),d)},NaN)};X.TEXTAREA=X.INPUT;var ga=avalon.eventHooks;"onmouseenter"in B||avalon.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(b,c){ga[b]={type:c,deel:function(c,e){return function(f){var g=f.relatedTarget;if(!g||g!==c&&
+!(c.compareDocumentPosition(g)&16))return delete f.type,f.type=b,e.call(c,f)}}}});avalon.each({AnimationEvent:"animationend",WebKitAnimationEvent:"webkitAnimationEnd"},function(b,c){r[b]&&!ga.animationend&&(ga.animationend={type:c})});"oninput"in p.createElement("input")||(ga.input={type:"propertychange",deel:function(b,c){return function(d){if("value"===d.propertyName)return d.type="input",c.call(b,d)}}});if(void 0===p.onmousewheel){var Ub=void 0!==p.onwheel?"wheel":"DOMMouseScroll",id="wheel"===
+Ub?"deltaY":"detail";ga.mousewheel={type:Ub,deel:function(b,c){return function(d){d.wheelDeltaY=d.wheelDelta=0]*>([\S\s]*?)<\/script\s*>/gim,kd=/\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g,ld=/<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig,md={a:/\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig,img:/\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig,form:/\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig},
+nd=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,od=/([^\#-~| |!])/g,Xa=avalon.filters={uppercase:function(b){return b.toUpperCase()},lowercase:function(b){return b.toLowerCase()},truncate:function(b,c,d){c=c||30;d=void 0===d?"...":d;return b.length>c?b.slice(0,c-d.length)+d:String(b)},camelize:oa,sanitize:function(b){return b.replace(jd,"").replace(ld,function(b,d){var e=b.toLowerCase().match(/<(\w+)\s/);e&&(e=md[e[1]])&&(b=b.replace(e,function(b,c,d){b=d.charAt(0);return c+"="+b+"javascript:void(0)"+b}));return b.replace(kd,
+" ").replace(/\s+/g," ")})},escape:function(b){return String(b).replace(/&/g,"&").replace(nd,function(b){var d=b.charCodeAt(0);b=b.charCodeAt(1);return""+(1024*(d-55296)+(b-56320)+65536)+";"}).replace(od,function(b){return""+b.charCodeAt(0)+";"}).replace(//g,">")},currency:function(b,c){return(c||"\uffe5")+avalon.filters.number(b)},number:function(b,c,d,e){b=(b+"").replace(/[^0-9+\-Ee.]/g,"");b=!isFinite(+b)?0:+b;c=!isFinite(+c)?0:Math.abs(c);e=e||",";d=d||".";var f=
+"",f=function(b,c){var d=Math.pow(10,c);return""+Math.round(b*d)/d},f=(c?f(b,c):""+Math.round(b)).split(".");3b&&(e="-",b=-b);for(b=""+b;b.length-e)g+=e;0===g&&-12===e&&(g=12);return b(g,
+d,f)}}function d(b,c){return function(d,e){var f=d["get"+b](),g=(c?"SHORT"+b:b).toUpperCase();return e[g][f]}}function e(b){var c;if(c=b.match(k)){b=new Date(0);var d=0,e=0,f=c[8]?b.setUTCFullYear:b.setFullYear,g=c[8]?b.setUTCHours:b.setHours;c[9]&&(d=parseInt(c[9]+c[10],10),e=parseInt(c[9]+c[11],10));f.call(b,parseInt(c[1],10),parseInt(c[2],10)-1,parseInt(c[3],10));d=parseInt(c[4]||0,10)-d;e=parseInt(c[5]||0,10)-e;f=parseInt(c[6]||0,10);c=Math.round(1E3*parseFloat("0."+(c[7]||0)));g.call(b,d,e,f,
+c)}return b}var f={yyyy:c("FullYear",4),yy:c("FullYear",2,0,!0),y:c("FullYear",1),MMMM:d("Month"),MMM:d("Month",!0),MM:c("Month",2,1),M:c("Month",1,1),dd:c("Date",2),d:c("Date",1),HH:c("Hours",2),H:c("Hours",1),hh:c("Hours",2,-12),h:c("Hours",1,-12),mm:c("Minutes",2),m:c("Minutes",1),ss:c("Seconds",2),s:c("Seconds",1),sss:c("Milliseconds",3),EEEE:d("Day"),EEE:d("Day",!0),a:function(b,c){return 12>b.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(c){c=-1*c.getTimezoneOffset();return c=(0<=c?"+":"")+(b(Math[0<
+c?"floor":"ceil"](c/60),2)+b(Math.abs(c%60),2))}},g=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,h=/^\d+$/,k=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,l=/^(\d+)\D(\d+)\D(\d+)/;Xa.date=function(b,c){var d=Xa.date.locate,k="",F=[],ua,m;c=c||"mediumDate";c=d[c]||c;"string"===typeof b&&(h.test(b)?b=parseInt(b,10):(b=b.trim().replace(l,function(b,c,d,e){return(4===e.length?[e,c,d]:[c,d,e]).join("/")}),b=e(b)),
+b=new Date(b));"number"===typeof b&&(b=new Date(b));if("date"===avalon.type(b)){for(;c;)(m=g.exec(c))?(F=F.concat(m.slice(1)),c=F.pop()):(F.push(c),c=null);F.forEach(function(c){ua=f[c];k+=ua?ua(b,d):c.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return k}};var m={AMPMS:{"0":"\u4e0a\u5348",1:"\u4e0b\u5348"},DAY:{"0":"\u661f\u671f\u65e5",1:"\u661f\u671f\u4e00",2:"\u661f\u671f\u4e8c",3:"\u661f\u671f\u4e09",4:"\u661f\u671f\u56db",5:"\u661f\u671f\u4e94",6:"\u661f\u671f\u516d"},MONTH:{"0":"1\u6708",1:"2\u6708",
+2:"3\u6708",3:"4\u6708",4:"5\u6708",5:"6\u6708",6:"7\u6708",7:"8\u6708",8:"9\u6708",9:"10\u6708",10:"11\u6708",11:"12\u6708"},SHORTDAY:{"0":"\u5468\u65e5",1:"\u5468\u4e00",2:"\u5468\u4e8c",3:"\u5468\u4e09",4:"\u5468\u56db",5:"\u5468\u4e94",6:"\u5468\u516d"},fullDate:"y\u5e74M\u6708d\u65e5EEEE",longDate:"y\u5e74M\u6708d\u65e5",medium:"yyyy-M-d ah:mm:ss",mediumDate:"yyyy-M-d",mediumTime:"ah:mm:ss","short":"yy-M-d ah:mm",shortDate:"yy-M-d",shortTime:"ah:mm"};m.SHORTMONTH=m.MONTH;Xa.date.locate=m};var s=
+avalon.modules={"ready!":{exports:avalon},avalon:{exports:avalon,state:2}};new function(){function b(b){return(b||"").replace(/[?#].*/,"")}function c(b){var c;try{a.b.c()}catch(d){c=d.stack,!c&&r.opera&&(c=(String(d).match(/of linked script \S+/g)||[]).join(" "))}if(c)return c=c.split(/[@ ]/g).pop(),c="("===c[0]?c.slice(1,-1):c.replace(/\s/,""),c.replace(/(:\d+)?:\d+$/i,"");c=(b?p:J).getElementsByTagName("script");for(var e=c.length,f;f=c[--e];)if((b||f.className===G)&&"interactive"===f.readyState)return f.className=
+f.src}function d(b,c){for(var e in b)if("\u53f8\u5f92\u6b63\u7f8e"===b[e]&&2!==s[e].state&&(e===c||d(s[e].deps,c)))return!0}function e(){var b=l.length,c;a:for(;c=l[--b];){c=s[c];var d=c.deps,f;for(f in d)if(O.call(d,f)&&2!==s[f].state)continue a;2!==c.state&&(l.splice(b,1),k(c.id,c.args,c.factory),e())}}function f(c,d,e){var f=b(c.src);c.onload=c.onreadystatechange=c.onerror=null;if(d||e&&!s[f].state)setTimeout(function(){J.removeChild(c);c=null}),v("debug: \u52a0\u8f7d "+f+" \u5931\u8d25"+d+" "+
+!s[f].state);else return!0}function g(c,d,e,f){if("ready!"===c||s[c]&&2===s[c].state)return c;var g;c=c.replace(/^\w+!/,function(b){g=b.slice(0,-1);return""});g=g||"js";g=U[g]||y;"object"===typeof u.shim[c]&&(f=u.shim[c]);u.paths[c]&&(c=u.paths[c]);if(/^(\w+)(\d)?:.*/.test(c))e=c;else{d=d.substr(0,d.lastIndexOf("/"));var h=c.charAt(0);if("."!==h&&"/"!==h)e=n+c;else if("./"===c.slice(0,2))e=d+c.slice(1);else if(".."===c.slice(0,2))for(e=d+"/"+c;t.test(e);)e=e.replace(t,"");else"/"===h?e=c:avalon.error("\u4e0d\u7b26\u5408\u6a21\u5757\u6807\u8bc6\u89c4\u5219: "+
+c)}c=b(e);(d=g.ext)&&c.slice(0-d.length)!==d&&(e+=d);u.nocache&&(e+=(-1===e.indexOf("?")?"?":"&")+(new Date-0));return g(e,f)}function h(b,c,d){var e=p.createElement("script");e.className=G;e[w?"onload":"onreadystatechange"]=function(){if(w||/loaded|complete/i.test(e.readyState)){var g=m.pop();g&&g.delay(c);d&&d();f(e,!1,!w)&&v("debug: \u5df2\u6210\u529f\u52a0\u8f7d "+b)}};e.onerror=function(){f(e,!0)};e.src=b;J.insertBefore(e,J.firstChild);v("debug: \u6b63\u51c6\u5907\u52a0\u8f7d "+b)}function k(b,
+c,d){for(var e=0,f=[],g;g=c[e++];)f.push(s[g].exports);c=Object(s[b]);d=d.apply(r,f);c.state=2;void 0!==d&&(s[b].exports=d);return d}var l=[],m=[],n;U.js=function(c,d){var e=b(c);s[e]||(s[e]={id:e,exports:{}},d?D(d.deps||"",function(){h(c,e,function(){s[e].state=2;d.exports&&(s[e].exports="function"===typeof d.exports?d.exports():r[d.exports]);D.checkDeps()})}):h(c,e));return e};U.css=function(b){var c=b.replace(/(#.+|\W)/g,"");if(!p.getElementById(c)){var d=p.createElement("link");d.rel="stylesheet";
+d.href=b;d.id=c;J.insertBefore(d,J.firstChild)}};U.css.ext=".css";U.js.ext=".js";U.text=function(b){var c=Sa(),d=b.replace(/[?#].*/,"");s[d]={};c.onreadystatechange=function(){if(4===c.readyState){var e=c.status;399e?avalon.error(b+" \u5bf9\u5e94\u8d44\u6e90\u4e0d\u5b58\u5728\u6216\u6ca1\u6709\u5f00\u542f CORS"):(s[d].state=2,s[d].exports=c.responseText,D.checkDeps())}};c.open("GET",b,!0);"withCredentials"in c&&(c.withCredentials=!0);c.setRequestHeader("X-Requested-With","XMLHttpRequest");
+c.send();return d};var q=c(!0);q||(q=avalon.slice(p.scripts).pop().src);q=b(q);n=u.base=q.slice(0,q.lastIndexOf("/")+1);var t=/\/\w+\/\.\./;D=avalon.require=function(b,c,d){var f={},h=[],m=0,p=0,q=d||"callback"+setTimeout("1");d=d||n;String(b).replace(z,function(b){if(b=g(b,d))m++,s[b]&&2===s[b].state&&p++,f[b]||(h.push(b),f[b]="\u53f8\u5f92\u6b63\u7f8e")});s[q]={id:q,factory:c,deps:f,args:h,state:1};m===p?k(q,h,c):l.unshift(q);e()};D.define=function(e,f,g){var h=$.call(arguments);if("string"===typeof e)var k=
+h.shift();"function"===typeof h[0]&&h.unshift([]);var l=s[k]&&1<=s[k].state?k:b(c());!s[l]&&k&&(s[l]={id:l,factory:g,state:1});g=h[1];g.id=k;g.delay=function(b){h.push(b);var c=!0;try{c=d(s[b].deps,b)}catch(e){}c&&avalon.error(b+"\u6a21\u5757\u4e0e\u4e4b\u524d\u7684\u6a21\u5757\u5b58\u5728\u5faa\u73af\u4f9d\u8d56\uff0c\u8bf7\u4e0d\u8981\u76f4\u63a5\u7528script\u6807\u7b7e\u5f15\u5165"+b+"\u6a21\u5757");delete g.delay;D.apply(null,h)};l?g.delay(l,h):m.push(g)};D.define.amd=s;D.config=u;D.checkDeps=
+e};var Fb=[];"complete"===p.readyState?setTimeout(T):w?p.addEventListener("DOMContentLoaded",T):(p.attachEvent("onreadystatechange",function(){"complete"===p.readyState&&T()}),B.doScroll&&Gb());avalon.bind(r,"load",T);avalon.ready=function(b){D?D("ready!",b):T===y?b(avalon):Fb.push(b)};avalon.config({loader:!0});avalon.ready(function(){avalon.scan(p.body)})})(document);
diff --git a/avalon.modern.js b/avalon.modern.js
index abcf6532d..fa26893fe 100644
--- a/avalon.modern.js
+++ b/avalon.modern.js
@@ -1,10 +1,17 @@
-//==================================================
-// avalon.modern 2014.10.10注意: 只能用于IE10及高版本的标准浏览器
-//==================================================
+/*==================================================
+ Copyright (c) 2013-2014 司徒正美 and other contributors
+ http://www.cnblogs.com/rubylouvre/
+ https://github.com/RubyLouvre
+ http://weibo.com/jslouvre/
+
+ Released under the MIT license
+ avalon 1.3.7 2014.11.17 support IE10 and other latest browsers
+ ==================================================*/
(function(DOC) {
var expose = Date.now()
var subscribers = "$" + expose
- var window = this || (0, eval)('this')
+ //http://stackoverflow.com/questions/3277182/how-to-get-the-global-object-in-javascript
+ var window = Function("return this")()
var otherRequire = window.require
var otherDefine = window.define
var stopRepeatAssign = false
@@ -32,7 +39,7 @@
function log() {
if (avalon.config.debug) {
- // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log
+// http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log
console.log.apply(console, arguments)
}
}
@@ -70,7 +77,7 @@
if (obj == null) {
return String(obj)
}
- // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function
+// 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function
return typeof obj === "object" || typeof obj === "function" ?
class2type[serialize.call(obj)] || "object" :
typeof obj
@@ -208,6 +215,9 @@
name = avalon.cssName(prop) || prop
if (value === void 0 || typeof value === "boolean") { //获取样式
var fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
+ if (name === "background") {
+ name = "backgroundColor"
+ }
var val = fn(node, name)
return value === true ? parseFloat(val) || 0 : val
} else if (value === "") { //请除样式
@@ -386,7 +396,7 @@
if (!$id) {
log("warning: 必须指定$id")
}
- if (VMODELS[id]) {
+ if (VMODELS[$id]) {
log("warning: " + $id + " 已经存在于avalon.vmodels中")
}
if (typeof id === "object") {
@@ -522,7 +532,7 @@
return childVmodel
}
}
- var childVmodel = accessor.child = modelFactory(val, 0, $model[name] )
+ var childVmodel = accessor.child = modelFactory(val, 0, $model[name])
childVmodel.$events[subscribers] = $events[name]
} else {
//第3种对应简单的数据类型,自变量,监控属性
@@ -637,6 +647,7 @@
delete withProxyPool[son.$id]
}
var ret = modelFactory(value)
+ ret.$events[subscribers] = iterators
rebindings[ret.$id] = function(data) {
while (data = iterators.shift()) {
(function(el) {
@@ -677,6 +688,7 @@
function escapeRegExp(target) {
return (target + "").replace(rregexp, "\\$&")
}
+ var innerRequire = noop
var plugins = {
loader: function(builtin) {
window.define = builtin ? innerRequire.define : otherDefine
@@ -870,7 +882,7 @@
if (root.dataset) {
- avalon.data = function(name, val) {
+ avalon.fn.data = function(name, val) {
var dataset = this[0].dataset
switch (arguments.length) {
case 2:
@@ -924,10 +936,9 @@
//=============================css相关==================================
var cssHooks = avalon.cssHooks = {}
- var prefixes = ["", "-webkit-", "-o-", "-moz-", "-ms-"]
+ var prefixes = ["", "-webkit-", "-moz-", "-ms-"]//去掉opera-15的支持
var cssMap = {
- "float": "cssFloat",
- background: "backgroundColor"
+ "float": "cssFloat"
}
avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
@@ -1137,12 +1148,7 @@
/************************************************************************
* HTML处理(parseHTML, innerHTML, clearHTML) *
**************************************************************************/
- var rtagName = /<([\w:]+)/,
- //取得其tagName
- rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
- scriptTypes = oneObject("text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript", "text/vbscript"),
- //需要处理套嵌关系的标签
- rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/
+
//parseHTML的辅助变量
var tagHooks = new function() {
avalon.mix(this, {
@@ -1153,52 +1159,26 @@
tr: DOC.createElement("tbody"),
col: DOC.createElement("colgroup"),
legend: DOC.createElement("fieldset"),
- "*": DOC.createElement("div"),
- "text": DOC.createElementNS("http://www.w3.org/2000/svg", "svg")
+ _default: DOC.createElement("div"),
+ "g": DOC.createElementNS("http://www.w3.org/2000/svg", "svg")
})
this.optgroup = this.option
this.tbody = this.tfoot = this.colgroup = this.caption = this.thead
this.th = this.td
- //处理SVG
- this.circle = this.ellipse = this.line = this.path =
- this.polygon = this.polyline = this.rect = this.text
- }
-
- avalon.clearHTML = function(node) {
- // node.textContent = ""
- while (node.firstChild) {
- node.removeChild(node.firstChild)
- }
- return node
- }
-
- var rtagName = /<([\w:]+)/
- //取得其tagName
- var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
- //需要处理套嵌关系的标签
- var rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/
- //parseHTML的辅助变量
- var tagHooks = {
- area: [1, ""],
- param: [1, ""],
- col: [2, ""],
- legend: [1, ""],
- option: [1, ""],
- thead: [1, ""],
- tr: [2, ""],
- td: [3, ""],
- text: [1, '', ' '],
- //IE6-8在用innerHTML生成节点时,不能直接创建no-scope元素与HTML5的新标签
- _default: [0, ""] //div可以不用闭合
}
tagHooks.optgroup = tagHooks.option
tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead
tagHooks.th = tagHooks.td
-//处理SVG
- tagHooks.circle = tagHooks.ellipse = tagHooks.line = tagHooks.path =
- tagHooks.polygon = tagHooks.polyline = tagHooks.rect = tagHooks.text
+
+ String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function(tag) {
+ tagHooks[tag] = tagHooks.g //处理SVG
+ })
+ var rtagName = /<([\w:]+)/
+ var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
+ var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"])
var script = DOC.createElement("script")
+
avalon.parseHTML = function(html) {
if (typeof html !== "string") {
html = html + ""
@@ -1206,43 +1186,41 @@
html = html.replace(rxhtml, "<$1>$2>").trim()
var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(),
//取得其标签名
- wrap = tagHooks[tag] || tagHooks._default,
+ wrapper = tagHooks[tag] || tagHooks._default,
fragment = hyperspace.cloneNode(false),
- wrapper = cinerator,
- firstChild, neo
-
- wrapper.innerHTML = wrap[1] + html + (wrap[2] || "")
+ firstChild
+ wrapper.innerHTML = html
var els = wrapper.getElementsByTagName("script")
if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性
for (var i = 0, el; el = els[i++]; ) {
- if (!el.type || scriptTypes[el.type]) { //如果script节点的MIME能让其执行脚本
- neo = script.cloneNode(false) //FF不能省略参数
+ if (scriptTypes[el.type]) {
+ var neo = script.cloneNode(false) //FF不能省略参数
ap.forEach.call(el.attributes, function(attr) {
- if (attr && attr.specified) {
- neo[attr.name] = attr.value //复制其属性
- }
+ neo.setAttribute(attr.name, attr.value)
})
- neo.text = el.text //必须指定,因为无法在attributes中遍历出来
- el.parentNode.replaceChild(neo, el) //替换节点
+ neo.text = el.text
+ el.parentNode.replaceChild(neo, el)
}
}
}
- //移除我们为了符合套嵌关系而添加的标签
- for (i = wrap[0]; i--; wrapper = wrapper.lastChild) {
- }
while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上!
fragment.appendChild(firstChild)
}
return fragment
}
+
avalon.innerHTML = function(node, html) {
- if (!/
diff --git a/examples/$fire2.html b/examples/$fire2.html
new file mode 100644
index 000000000..6efecf4cd
--- /dev/null
+++ b/examples/$fire2.html
@@ -0,0 +1,41 @@
+
+
+
+
+ ms-class
+
+
+
+
+
+
+ {{a}}
+ fire
+
+
+
diff --git a/examples/avalon.$events.js b/examples/avalon.$events.js
deleted file mode 100644
index f36aeceb1..000000000
--- a/examples/avalon.$events.js
+++ /dev/null
@@ -1,4922 +0,0 @@
-/*==================================================
- Copyright 2013-2014 司徒正美 and other contributors
- http://www.cnblogs.com/rubylouvre/
- https://github.com/RubyLouvre
- http://weibo.com/jslouvre/
-
- Released under the MIT license
- avalon 1.4 2014.10.5
- ==================================================*/
-(function(DOC) {
- /*********************************************************************
- * 全局变量及方法 *
- **********************************************************************/
- var expose = new Date - 0
- var subscribers = "$" + expose
- //http://addyosmani.com/blog/understanding-mvvm-a-guide-for-javascript-developers/
- var window = this || (0, eval)("this")
- var otherRequire = window.require
- var otherDefine = window.define
- var stopRepeatAssign = false
- var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach
- var rnative = /\[native code\]/ //判定是否原生函数
- var rcomplexType = /^(?:object|array)$/
- var rsvg = /^\[object SVG\w*Element\]$/
- var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/
- var oproto = Object.prototype
- var ohasOwn = oproto.hasOwnProperty
- var serialize = oproto.toString
- var ap = Array.prototype
- var aslice = ap.slice
- var W3C = window.dispatchEvent
- var root = DOC.documentElement
- var head = DOC.getElementsByTagName("head")[0] //HEAD元素
- var hyperspace = DOC.createDocumentFragment()
- var cinerator = DOC.createElement("div")
- var class2type = {}
- "Boolean Number String Function Array Date RegExp Object Error".replace(rword, function(name) {
- class2type["[object " + name + "]"] = name.toLowerCase()
- })
-
- var isFunction = typeof alert === "object" ? function(fn) {
- try {
- return /^\s*\bfunction\b/.test(fn + "")
- } catch (e) {
- return false
- }
- } : function(fn) {
- return serialize.call(fn) == "[object Function]"
- }
-
- function noop() {
- }
-
- function log() {
- if (window.console && avalon.config.debug) {
- // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log
- Function.apply.call(console.log, console, arguments)
- }
- }
-
-
- function oneObject(array, val) {
- if (typeof array === "string") {
- array = array.match(rword) || []
- }
- var result = {},
- value = val !== void 0 ? val : 1
- for (var i = 0, n = array.length; i < n; i++) {
- result[array[i]] = value
- }
- return result
- }
-
-//生成UUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
- function generateID() {
- return "avalon" + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
- }
- /*********************************************************************
- * avalon的静态方法定义区 *
- **********************************************************************/
- avalon = function(el) { //创建jQuery式的无new 实例化结构
- return new avalon.init(el)
- }
-
- avalon.init = function(el) {
- this[0] = this.element = el
- }
- avalon.isFunction = isFunction
- avalon.fn = avalon.prototype = avalon.init.prototype
-
- avalon.type = function(obj) {//取得目标的类型
- if (obj == null) {
- return String(obj)
- }
- // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[serialize.call(obj)] || "object" :
- typeof obj
- }
-
- avalon.isWindow = function(obj) {
- if (!obj)
- return false
- // 利用IE678 window == document为true,document == window竟然为false的神奇特性
- // 标准浏览器及IE9,IE10等使用 正则检测
- return obj == obj.document && obj.document != obj
- }
-
- function isWindow(obj) {
- return rwindow.test(serialize.call(obj))
- }
- if (isWindow(window)) {
- avalon.isWindow = isWindow
- }
- var enu
- for (enu in avalon({})) {
- break
- }
- var enumerateBUG = enu !== "0"//IE6下为true, 其他为false
- /*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/
- avalon.isPlainObject = function(obj, key) {
- if (!obj || avalon.type(obj) !== "object" || obj.nodeType || avalon.isWindow(obj)) {
- return false;
- }
- try {//IE内置对象没有constructor
- if (obj.constructor &&
- !ohasOwn.call(obj, "constructor") &&
- !ohasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
- return false;
- }
- } catch (e) {//IE8 9会在这里抛错
- return false;
- }
- if (enumerateBUG) {
- for (key in obj) {
- return ohasOwn.call(obj, key)
- }
- }
- for (key in obj) {
- }
- return key === void 0 || ohasOwn.call(obj, key);
- }
- if (rnative.test(Object.getPrototypeOf)) {
- avalon.isPlainObject = function(obj) {
- return !!obj && typeof obj === "object" && Object.getPrototypeOf(obj) === oproto
- }
- }
-//与jQuery.extend方法,可用于浅拷贝,深拷贝
- avalon.mix = avalon.fn.mix = function() {
- var options, name, src, copy, copyIsArray, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false
-
- // 如果第一个参数为布尔,判定是否深拷贝
- if (typeof target === "boolean") {
- deep = target
- target = arguments[1] || {}
- i++
- }
-
-//确保接受方为一个复杂的数据类型
- if (typeof target !== "object" && !isFunction(target)) {
- target = {}
- }
-
-//如果只有一个参数,那么新成员添加于mix所在的对象上
- if (i === length) {
- target = this
- i--
- }
-
- for (; i < length; i++) {
-//只处理非空参数
- if ((options = arguments[i]) != null) {
- for (name in options) {
- src = target[name]
- try {
- copy = options[name]//当options为VBS对象时报错
- } catch (e) {
- continue
- }
-
- // 防止环引用
- if (target === copy) {
- continue
- }
- if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
-
- if (copyIsArray) {
- copyIsArray = false
- clone = src && Array.isArray(src) ? src : []
-
- } else {
- clone = src && avalon.isPlainObject(src) ? src : {}
- }
-
- target[name] = avalon.mix(deep, clone, copy)
- } else if (copy !== void 0) {
- target[name] = copy
- }
- }
- }
- }
- return target
- }
-
- function _number(a, len) { //用于模拟slice, splice的效果
- a = Math.floor(a) || 0
- return a < 0 ? Math.max(len + a, 0) : Math.min(a, len);
- }
- avalon.mix({
- rword: rword,
- subscribers: subscribers,
- version: 1.4,
- ui: {},
- log: log,
- slice: W3C ? function(nodes, start, end) {
- return aslice.call(nodes, start, end)
- } : function(nodes, start, end) {
- var ret = []
- var len = nodes.length
- if (end === void 0)
- end = len
- if (typeof end === "number" && isFinite(end)) {
- start = _number(start, len)
- end = _number(end, len)
- for (var i = start; i < end; ++i) {
- ret[i - start] = nodes[i]
- }
- }
- return ret
- },
- noop: noop,
- /*如果不用Error对象封装一下,str在控制台下可能会乱码*/
- error: function(str, e) {
- throw new (e || Error)(str)
- },
- /*将一个以空格或逗号隔开的字符串或数组,转换成一个键值都为1的对象*/
- oneObject: oneObject,
- /* avalon.range(10)
- => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- avalon.range(1, 11)
- => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- avalon.range(0, 30, 5)
- => [0, 5, 10, 15, 20, 25]
- avalon.range(0, -10, -1)
- => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
- avalon.range(0)
- => []*/
- range: function(start, end, step) { // 用于生成整数数组
- step || (step = 1)
- if (end == null) {
- end = start || 0
- start = 0
- }
- var index = -1,
- length = Math.max(0, Math.ceil((end - start) / step)),
- result = Array(length)
- while (++index < length) {
- result[index] = start
- start += step
- }
- return result
- },
- eventHooks: {},
- /*绑定事件*/
- bind: function(el, type, fn, phase) {
- var hooks = avalon.eventHooks
- var hook = hooks[type]
- if (typeof hook === "object") {
- type = hook.type
- if (hook.deel) {
- fn = hook.deel(el, fn)
- }
- }
- var callback = W3C ? fn : function(e) {
- fn.call(el, fixEvent(e));
- }
- if (W3C) {
- el.addEventListener(type, callback, !!phase)
- } else {
- el.attachEvent("on" + type, callback)
- }
- return callback
- },
- /*卸载事件*/
- unbind: function(el, type, fn, phase) {
- var hooks = avalon.eventHooks
- var hook = hooks[type]
- var callback = fn || noop
- if (typeof hook === "object") {
- type = hook.type
- }
- if (W3C) {
- el.removeEventListener(type, callback, !!phase)
- } else {
- el.detachEvent("on" + type, callback)
- }
- },
- /*读写删除元素节点的样式*/
- css: function(node, name, value) {
- if (node instanceof avalon) {
- node = node[0]
- }
- var prop = /[_-]/.test(name) ? camelize(name) : name
- name = avalon.cssName(prop) || prop
- if (value === void 0 || typeof value === "boolean") { //获取样式
- var fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
- var val = fn(node, name)
- return value === true ? parseFloat(val) || 0 : val
- } else if (value === "") { //请除样式
- node.style[name] = ""
- } else { //设置样式
- if (value == null || value !== value) {
- return
- }
- if (isFinite(value) && !avalon.cssNumber[prop]) {
- value += "px"
- }
- fn = cssHooks[prop + ":set"] || cssHooks["@:set"]
- fn(node, name, value)
- }
- },
- /*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/
- each: function(obj, fn) {
- if (obj) { //排除null, undefined
- var i = 0
- if (isArrayLike(obj)) {
- for (var n = obj.length; i < n; i++) {
- fn(i, obj[i])
- }
- } else {
- for (i in obj) {
- if (obj.hasOwnProperty(i)) {
- fn(i, obj[i])
- }
- }
- }
- }
- },
- //收集元素的data-{{prefix}}-*属性,并转换为对象
- getWidgetData: function(elem, prefix) {
- var raw = avalon(elem).data()
- var result = {}
- for (var i in raw) {
- if (i.indexOf(prefix) === 0) {
- result[i.replace(prefix, "").replace(/\w/, function(a) {
- return a.toLowerCase()
- })] = raw[i]
- }
- }
- return result
- },
- Array: {
- /*只有当前数组不存在此元素时只添加它*/
- ensure: function(target, item) {
- if (target.indexOf(item) === -1) {
- return target.push(item)
- }
- },
- /*移除数组中指定位置的元素,返回布尔表示成功与否*/
- removeAt: function(target, index) {
- return !!target.splice(index, 1).length
- },
- /*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/
- remove: function(target, item) {
- var index = target.indexOf(item)
- if (~index)
- return avalon.Array.removeAt(target, index)
- return false
- }
- }
- })
-
- /*判定类数组,如节点集合,纯数组,arguments与拥有非负整数的length属性的纯JS对象*/
- function isArrayLike(obj) {
- if (obj && typeof obj === "object" && !avalon.isWindow(obj)) {
- var n = obj.length
- if (+n === n && !(n % 1) && n >= 0) { //检测length属性是否为非负整数
- try {
- if ({}.propertyIsEnumerable.call(obj, "length") === false) { //如果是原生对象
- return Array.isArray(obj) || /^\s?function/.test(obj.item || obj.callee)
- }
- return true
- } catch (e) { //IE的NodeList直接抛错
- return true
- }
- }
- }
- return false
- }
- //from Q.js
- avalon.nextTick = (function() {
- // linked list of tasks (single, with head node)
- var head = {task: void 0, next: null}
- var tail = head
- var flushing = false
- var requestTick = void 0
-
- function flush() {
- while (head.next) {
- head = head.next
- var task = head.task
- head.task = void 0
- try {
- task()
- } catch (e) {
- // In browsers, uncaught exceptions are not fatal.
- // Re-throw them asynchronously to avoid slow-downs.
- setTimeout(function() {
- throw e
- }, 0)
- }
- }
- flushing = false
- }
-
- nextTick = function(task) {
- tail = tail.next = {
- task: task,
- next: null
- }
- if (!flushing) {
- flushing = true
- requestTick()
- }
- }
- if (typeof setImmediate === "function") {//IE10-11
- requestTick = setImmediate.bind(window, flush)
- } else if (typeof MessageChannel !== "undefined") { // W3C
- // http://www.nonblocking.io/2011/06/windownexttick.html
- var channel = new MessageChannel();
- channel.port1.onmessage = function() {
- requestTick = requestPortTick
- channel.port1.onmessage = flush
- flush()
- }
- var requestPortTick = function() {
- channel.port2.postMessage(0);
- }
- requestTick = function() {
- setTimeout(flush, 0)
- requestPortTick()
- }
- } else if (window.VBArray) {//IE6-9
- requestTick = function() {
- var node = DOC.createElement("script")
- node.onreadystatechange = function() {
- flush() //在interactive阶段就触发
- node.onreadystatechange = null
- head.removeChild(node)
- node = null
- }
- head.appendChild(node)
- }
- } else { // old W3C
- requestTick = function() {
- setTimeout(flush, 0)
- }
- }
- return nextTick
- })()
- /*********************************************************************
- * modelFactory *
- **********************************************************************/
- //avalon最核心的方法的两个方法之一(另一个是avalon.scan),返回一个ViewModel(VM)
- var VMODELS = avalon.vmodels = {}//所有vmodel都储存在这里
- avalon.define = function(id, factory) {
- var $id = id.$id || id
- if (!$id) {
- log("warning: vm必须指定$id")
- }
- if (VMODELS[id]) {
- log("warning: " + $id + " 已经存在于avalon.vmodels中")
- }
- if (typeof id === "object") {
- var model = modelFactory(id)
- } else {
- var scope = {
- $watch: noop
- }
- factory(scope) //得到所有定义
- model = modelFactory(scope) //偷天换日,将scope换为model
- stopRepeatAssign = true
- factory(model)
- stopRepeatAssign = false
- }
- model.$id = $id
- return VMODELS[$id] = model
- }
- //一些不需要被监听的属性
- var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray").match(rword)
- function isObservable(name, value, $skipArray) {
- if (isFunction(value) || value && value.nodeType) {
- return false
- }
- if ($skipArray.indexOf(name) !== -1) {
- return false
- }
- if ($$skipArray.indexOf(name) !== -1) {
- return false
- }
- var $special = $skipArray.$special
- if (name && name.charAt(0) === "$" && !$special[name]) {
- return false
- }
- return true
- }
- var rthis = /\bthis\./g
-
- function modelFactory($scope, $special, $model) {
- if (Array.isArray($scope)) {
- var arr = $scope.concat()
- $scope.length = 0
- var collection = Collection($scope)
- collection.pushArray(arr)
- return collection
- }
- if (typeof $scope.nodeType === "number") {
- return $scope
- }
- if ($scope.$id && $scope.$model && $scope.$events) {//fix IE6-8 createWithProxy $val: val引发的BUG
- return $scope
- }
- if (!Array.isArray($scope.$skipArray)) {
- $scope.$skipArray = []
- }
- $scope.$skipArray.$special = $special || {}//强制要监听的属性
- var $vmodel = {} //要返回的对象, 它在IE6-8下可能被偷龙转凤
- $model = $model || {} //vmodels.$model属性
- var watchedProperties = {} //监控属性
- var computedProperties = [] //计算属性
- var $events = {}
- for (var i in $scope) {
- (function(name, val) {
- $model[name] = val
- if (!isObservable(name, val, $scope.$skipArray)) {
- return //过滤所有非监控属性
- }
- //总共产生三种accessor
- var accessor
- var valueType = avalon.type(val)
- $events[name] = []
- if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) {
- var setter = val.set
- var getter = val.get
- //第1种对应计算属性, 因变量,通过其他监控属性触发其改变
- accessor = function(newValue) {
- var $events = $vmodel.$events
- var oldValue = $model[name]
- if (arguments.length) {
- if (stopRepeatAssign) {
- return
- }
- if (isFunction(setter)) {
- var backup = $events[name]
- $events[name] = [] //清空回调,防止内部冒泡而触发多次$fire
- setter.call($vmodel, newValue)
- $events[name] = backup
- }
- }
- newValue = $model[name] = getter.call($vmodel) //同步$model
- if (!isEqual(oldValue, newValue)) {
- withProxyCount && updateWithProxy($vmodel.$id, name, newValue) //同步循环绑定中的代理VM
- notifySubscribers($events[name]) //同步视图
- safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
- }
- return newValue
- }
- computedProperties.push(function() {
- var data = {
- evaluator: accessor,
- element: head,
- type: "computed::" + name,
- handler: noop,
- args: []
- }
- var vars = getVariables(getter.toString().replace(rthis, "")).concat()
- if (vars.length) {//计算依赖
- addAssign(vars, $vmodel, name, data)
- }
- accessor()//强逼计算自身
- })
- } else if (rcomplexType.test(valueType)) {
- //第2种对应子ViewModel或监控数组
- accessor = function(newValue) {
- var childVmodel = accessor.child
- var oldValue = $model[name]
- if (arguments.length) {
- if (stopRepeatAssign) {
- return
- }
- if (!isEqual(oldValue, newValue)) {
- childVmodel = accessor.child = updateChild($vmodel, name, newValue, valueType)
- newValue = $model[name] = childVmodel.$model //同步$model
- var fn = rebindings[childVmodel.$id]
- fn && fn() //同步视图
- safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
- }
- } else {
- return childVmodel
- }
- }
- var childVmodel = accessor.child = modelFactory(val, 0, $model[name])
- childVmodel.$events[subscribers] = $events[name]
- } else {
- //第3种对应简单的数据类型,自变量,监控属性
- accessor = function(newValue) {
- var oldValue = $model[name]
- if (arguments.length) {
- if (!isEqual(oldValue, newValue)) {
- $model[name] = newValue //同步$model
- withProxyCount && updateWithProxy($vmodel.$id, name, newValue) //同步代理VM
- notifySubscribers($vmodel.$events[name]) //同步视图
- safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
- }
- } else {
- return oldValue
- }
- }
- }
- watchedProperties[name] = accessor
- })(i, $scope[i])
- }
-
- $$skipArray.forEach(function(name) {
- delete $scope[name]
- delete $model[name] //这些特殊属性不应该在$model中出现
- })
-
- $vmodel = defineProperties($vmodel, descriptorFactory(watchedProperties), $scope) //生成一个空的ViewModel
- for (var name in $scope) {
- if (!watchedProperties[name]) {
- $vmodel[name] = $scope[name]
- }
- }
- //添加$id, $model, $events, $watch, $unwatch, $fire
- $vmodel.$id = generateID()
- $vmodel.$model = $model
- $vmodel.$events = $events
- for (var i in EventManager) {
- var fn = EventManager [i]
- if (!W3C) { //在IE6-8下,VB对象的方法里的this并不指向自身,需要用bind处理一下
- fn = fn.bind($vmodel)
- }
- $vmodel[i] = fn
- }
-
- $vmodel.hasOwnProperty = function(name) {
- return name in $vmodel.$model
- }
- computedProperties.forEach(function(collect) {
- collect()//收集依赖
- })
- return $vmodel
- }
-
- //比较两个值是否相等
- var isEqual = Object.is || function(v1, v2) {
- if (v1 === 0 && v2 === 0) {
- return 1 / v1 === 1 / v2
- } else if (v1 !== v1) {
- return v2 !== v2
- } else {
- return v1 === v2
- }
- }
-
- function safeFire(a, b, c, d) {
- if (a.$events) {
- EventManager.$fire.call(a, b, c, d)
- }
- }
- var descriptorFactory = W3C ? function(obj) {
- var descriptors = {}
- for (var i in obj) {
- descriptors[i] = {
- get: obj[i],
- set: obj[i],
- enumerable: true,
- configurable: true
- }
- }
- return descriptors
- } : function(a) {
- return a
- }
-
- //ms-with, ms-repeat绑定生成的代理对象储存池
- var withProxyPool = {}
- var withProxyCount = 0
- var rebindings = {}
-
- function updateWithProxy($id, name, val) {
- var pool = withProxyPool[$id]
- if (pool && pool[name]) {
- pool[name].$val = val
- }
- }
- //应用于第2种accessor
- function updateChild(parent, name, value, valueType) {
- //a为原来的VM, b为新数组或新对象
- var son = parent[name]
- if (valueType === "array") {
- if (!Array.isArray(value) || son === value) {
- return son //fix https://github.com/RubyLouvre/avalon/issues/261
- }
- son.clear()
- son.pushArray(value.concat())
- return son
- } else {
- var iterators = parent.$events[name]
- if (withProxyPool[son.$id]) {
- withProxyCount--
- delete withProxyPool[son.$id]
- }
- var ret = modelFactory(value)
- rebindings[ret.$id] = function(data) {
- while (data = iterators.shift()) {
- (function(el) {
- if (el.type) { //重新绑定
- avalon.nextTick(function() {
- el.rollback && el.rollback() //还原 ms-with ms-on
- bindingHandlers[el.type](el, el.vmodels)
- })
- }
- })(data)
- }
- delete rebindings[ret.$id]
- }
- return ret
- }
- }
-
- //===================修复浏览器对Object.defineProperties的支持=================
- var defineProperty = Object.defineProperty
- //如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
- //标准浏览器使用__defineGetter__, __defineSetter__实现
- try {
- defineProperty({}, "_", {
- value: "x"
- })
- var defineProperties = Object.defineProperties
- } catch (e) {
- if ("__defineGetter__" in avalon) {
- defineProperty = function(obj, prop, desc) {
- if ('value' in desc) {
- obj[prop] = desc.value
- }
- if ("get" in desc) {
- obj.__defineGetter__(prop, desc.get)
- }
- if ('set' in desc) {
- obj.__defineSetter__(prop, desc.set)
- }
- return obj
- }
- defineProperties = function(obj, descs) {
- for (var prop in descs) {
- if (descs.hasOwnProperty(prop)) {
- defineProperty(obj, prop, descs[prop])
- }
- }
- return obj
- }
- }
- }
- //IE6-8使用VBScript类的set get语句实现
- if (!defineProperties && window.VBArray) {
- window.execScript([
- "Function parseVB(code)",
- "\tExecuteGlobal(code)",
- "End Function",
- "Dim VBClassBodies",
- "Set VBClassBodies=CreateObject(\"Scripting.Dictionary\")",
- "Function findOrDefineVBClass(name,body)",
- "\tDim found",
- "\tfound=\"\"",
- "\tFor Each key in VBClassBodies",
- "\t\tIf body=VBClassBodies.Item(key) Then",
- "\t\t\tfound=key",
- "\t\t\tExit For",
- "\t\tEnd If",
- "\tnext",
- "\tIf found=\"\" Then",
- "\t\tparseVB(\"Class \" + name + body)",
- "\t\tVBClassBodies.Add name, body",
- "\t\tfound=name",
- "\tEnd If",
- "\tfindOrDefineVBClass=found",
- "End Function"
- ].join("\n"), "VBScript")
-
- function VBMediator(accessingProperties, name, value) {
- var accessor = accessingProperties[name]
- if (typeof accessor === "function") {
- if (arguments.length === 3) {
- accessor(value)
- } else {
- return accessor()
- }
- }
- }
- defineProperties = function(name, accessors, properties) {
- var className = "VBClass" + setTimeout("1"),
- buffer = []
- buffer.push(
- "\r\n\tPrivate [__data__], [__proxy__]",
- "\tPublic Default Function [__const__](d, p)",
- "\t\tSet [__data__] = d: set [__proxy__] = p",
- "\t\tSet [__const__] = Me", //链式调用
- "\tEnd Function")
- //添加普通属性,因为VBScript对象不能像JS那样随意增删属性,必须在这里预先定义好
- for (name in properties) {
- if (!accessors.hasOwnProperty(name)) {
- buffer.push("\tPublic [" + name + "]")
- }
- }
- $$skipArray.forEach(function(name) {
- if (!accessors.hasOwnProperty(name)) {
- buffer.push("\tPublic [" + name + "]")
- }
- })
- buffer.push("\tPublic [" + 'hasOwnProperty' + "]")
- //添加访问器属性
- for (name in accessors) {
- buffer.push(
- //由于不知对方会传入什么,因此set, let都用上
- "\tPublic Property Let [" + name + "](val" + expose + ")", //setter
- "\t\tCall [__proxy__]([__data__], \"" + name + "\", val" + expose + ")",
- "\tEnd Property",
- "\tPublic Property Set [" + name + "](val" + expose + ")", //setter
- "\t\tCall [__proxy__]([__data__], \"" + name + "\", val" + expose + ")",
- "\tEnd Property",
- "\tPublic Property Get [" + name + "]", //getter
- "\tOn Error Resume Next", //必须优先使用set语句,否则它会误将数组当字符串返回
- "\t\tSet[" + name + "] = [__proxy__]([__data__],\"" + name + "\")",
- "\tIf Err.Number <> 0 Then",
- "\t\t[" + name + "] = [__proxy__]([__data__],\"" + name + "\")",
- "\tEnd If",
- "\tOn Error Goto 0",
- "\tEnd Property")
-
- }
-
- buffer.push("End Class")
- var code = buffer.join("\r\n"),
- realClassName = window['findOrDefineVBClass'](className, code) //如果该VB类已定义,返回类名。否则用className创建一个新类。
- if (realClassName === className) {
- window.parseVB([
- "Function " + className + "Factory(a, b)", //创建实例并传入两个关键的参数
- "\tDim o",
- "\tSet o = (New " + className + ")(a, b)",
- "\tSet " + className + "Factory = o",
- "End Function"
- ].join("\r\n"))
- }
- var ret = window[realClassName + "Factory"](accessors, VBMediator) //得到其产品
- return ret //得到其产品
- }
- }
- /*********************************************************************
- * javascript 底层补丁 *
- **********************************************************************/
- if (!"司徒正美".trim) {
- var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
- String.prototype.trim = function() {
- return this.replace(rtrim, "")
- }
- }
- var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
- hasProtoEnumBug = (function() {
- }).propertyIsEnumerable('prototype'),
- dontEnums = [
- "toString",
- "toLocaleString",
- "valueOf",
- "hasOwnProperty",
- "isPrototypeOf",
- "propertyIsEnumerable",
- "constructor"
- ],
- dontEnumsLength = dontEnums.length;
- if (!Object.keys) {
- Object.keys = function(object) { //ecma262v5 15.2.3.14
- var theKeys = [];
- var skipProto = hasProtoEnumBug && typeof object === "function"
- if (typeof object === "string" || (object && object.callee)) {
- for (var i = 0; i < object.length; ++i) {
- theKeys.push(String(i))
- }
- } else {
- for (var name in object) {
- if (!(skipProto && name === "prototype") && ohasOwn.call(object, name)) {
- theKeys.push(String(name))
- }
- }
- }
-
- if (hasDontEnumBug) {
- var ctor = object.constructor,
- skipConstructor = ctor && ctor.prototype === object;
- for (var j = 0; j < dontEnumsLength; j++) {
- var dontEnum = dontEnums[j]
- if (!(skipConstructor && dontEnum === "constructor") && ohasOwn.call(object, dontEnum)) {
- theKeys.push(dontEnum)
- }
- }
- }
- return theKeys
- }
- }
- if (!Array.isArray) {
- Array.isArray = function(a) {
- return serialize.call(a) === "[object Array]"
- }
- }
-
- if (!noop.bind) {
- Function.prototype.bind = function(scope) {
- if (arguments.length < 2 && scope === void 0)
- return this
- var fn = this,
- argv = arguments
- return function() {
- var args = [],
- i
- for (i = 1; i < argv.length; i++)
- args.push(argv[i])
- for (i = 0; i < arguments.length; i++)
- args.push(arguments[i])
- return fn.apply(scope, args)
- }
- }
- }
-
- function iterator(vars, body, ret) {
- var fun = 'for(var ' + vars + 'i=0,n = this.length; i < n; i++){' + body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))') + '}' + ret
- return Function("fn,scope", fun)
- }
- if (!rnative.test([].map)) {
- avalon.mix(ap, {
- //定位操作,返回数组中第一个等于给定参数的元素的索引值。
- indexOf: function(item, index) {
- var n = this.length,
- i = ~~index
- if (i < 0)
- i += n
- for (; i < n; i++)
- if (this[i] === item)
- return i
- return -1
- },
- //定位操作,同上,不过是从后遍历。
- lastIndexOf: function(item, index) {
- var n = this.length,
- i = index == null ? n - 1 : index
- if (i < 0)
- i = Math.max(0, n + i)
- for (; i >= 0; i--)
- if (this[i] === item)
- return i
- return -1
- },
- //迭代操作,将数组的元素挨个儿传入一个函数中执行。Prototype.js的对应名字为each。
- forEach: iterator("", '_', ""),
- //迭代类 在数组中的每个项上运行一个函数,如果此函数的值为真,则此元素作为新数组的元素收集起来,并返回新数组
- filter: iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'),
- //收集操作,将数组的元素挨个儿传入一个函数中执行,然后把它们的返回值组成一个新数组返回。Prototype.js的对应名字为collect。
- map: iterator('r=[],', 'r[i]=_', 'return r'),
- //只要数组中有一个元素满足条件(放进给定函数返回true),那么它就返回true。Prototype.js的对应名字为any。
- some: iterator("", 'if(_)return true', 'return false'),
- //只有数组中的元素都满足条件(放进给定函数返回true),它才返回true。Prototype.js的对应名字为all。
- every: iterator("", 'if(!_)return false', 'return true')
- })
- }
- /*********************************************************************
- * DOM 底层补丁 *
- **********************************************************************/
- function fixContains(a, b) {
- if (b) {
- while ((b = b.parentNode)) {
- if (b === a) {
- return true;
- }
- }
- }
- return false;
- }
- //safari5+是把contains方法放在Element.prototype上而不是Node.prototype
- if (!root.contains) {
- Node.prototype.contains = function(arg) {
- return !!(this.compareDocumentPosition(arg) & 16)
- }
- }
- //IE6-11的文档对象没有contains
- if (!DOC.contains) {
- DOC.contains = function(b) {
- return fixContains(DOC, b)
- }
- }
- function outerHTML() {
- return new XMLSerializer().serializeToString(this)
- }
-
-
- if (window.SVGElement) {
- var svgns = "http://www.w3.org/2000/svg"
- var svg = document.createElementNS(svgns, "svg")
- svg.innerHTML = ' '
- if (!rsvg.test(svg.firstChild)) {// #409
- function enumerateNode(node, targetNode) {
- if (node && node.childNodes) {
- var nodes = node.childNodes
- for (var i = 0, el; el = nodes[i++]; ) {
- if (el.tagName) {
- var svg = document.createElementNS(svgns,
- el.tagName.toLowerCase())
- ap.forEach.call(el.attributes, function(attr) {
- svg.setAttribute(attr.name, attr.value)//复制属性
- })
- // 递归处理子节点
- enumerateNode(el, svg)
- targetNode.appendChild(svg)
- }
- }
- }
- }
- Object.defineProperties(SVGElement.prototype, {
- "outerHTML": {//IE9-11,firefox不支持SVG元素的innerHTML,outerHTML属性
- enumerable: true,
- configurable: true,
- get: outerHTML,
- set: function(html) {
- var tagName = this.tagName.toLowerCase(),
- par = this.parentNode,
- frag = avalon.parseHTML(html)
- // 操作的svg,直接插入
- if (tagName === "svg") {
- par.insertBefore(frag, this)
- // svg节点的子节点类似
- } else {
- var newFrag = document.createDocumentFragment()
- enumerateNode(frag, newFrag)
- par.insertBefore(newFrag, this)
- }
- par.removeChild(this)
- }
- },
- "innerHTML": {
- enumerable: true,
- configurable: true,
- get: function() {
- var s = this.outerHTML
- var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i")
- var rclose = new RegExp("<\/" + this.nodeName + ">$", "i")
- return s.replace(ropen, "").replace(rclose, "")
- },
- set: function(html) {
- if (avalon.clearHTM) {
- avalon.clearHTML(this)
- var frag = avalon.parseHTML(html)
- enumerateNode(frag, this)
- }
- }
- }
- })
- }
- }
- if (!root.outerHTML && window.HTMLElement) { //firefox 到11时才有outerHTML
- HTMLElement.prototype.__defineGetter__("outerHTML", outerHTML);
- }
-
- /*********************************************************************
- * LRU缓存工厂,代替之前的createCache *
- **********************************************************************/
- var avalonCaches = {}
- function cacheFactory(cacheId, capacity) {
- if (cacheId in avalonCaches) {
- throw Error(cacheId + "已经存在")
- }
- var size = 0,
- data = {},
- lruHash = {},
- freshEnd = null,
- staleEnd = null
- capacity = typeof capacity === "number" ? capacity : Number.MAX_VALUE
- //生成一个LRU缓体实体
- return avalonCaches[cacheId] = {
- set: function(key, value) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key] || (lruHash[key] = {key: key})
- refresh(lruEntry)
- }
-
- if (value === void 0)
- return
- if (!(key in data))
- size++
- data[key] = value
- if (size > capacity) {
- this.remove(staleEnd.key)
- }
-
- return value
- },
- get: function(key) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key]
- if (!lruEntry)
- return
- refresh(lruEntry)
- }
-
- return data[key]
- },
- remove: function(key) {
- if (capacity < Number.MAX_VALUE) {
- var lruEntry = lruHash[key]
- if (!lruEntry)
- return
- if (lruEntry == freshEnd)
- freshEnd = lruEntry.p
- if (lruEntry == staleEnd)
- staleEnd = lruEntry.n
- link(lruEntry.n, lruEntry.p)
- delete lruHash[key]
- }
-
- delete data[key]
- size--
- }
- };
-
- function refresh(entry) {
- if (entry != freshEnd) {
- if (!staleEnd) {
- staleEnd = entry
- } else if (staleEnd == entry) {
- staleEnd = entry.n
- }
-
- link(entry.n, entry.p)
- link(entry, freshEnd)
- freshEnd = entry
- freshEnd.n = null
- }
- }
-
- function link(nextEntry, prevEntry) {
- if (nextEntry != prevEntry) {
- if (nextEntry)
- nextEntry.p = prevEntry //p stands for previous, 'prev' didn't minify
- if (prevEntry)
- prevEntry.n = nextEntry //n stands for next, 'next' didn't minify
- }
- }
- }
-
-
- /*********************************************************************
- * 配置系统 *
- **********************************************************************/
- function kernel(settings) {
- for (var p in settings) {
- if (!ohasOwn.call(settings, p))
- continue
- var val = settings[p]
- if (typeof kernel.plugins[p] === "function") {
- kernel.plugins[p](val)
- } else if (typeof kernel[p] === "object") {
- avalon.mix(kernel[p], val)
- } else {
- kernel[p] = val
- }
- }
- return this
- }
- var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g
-
- function escapeRegExp(target) {
- //http://stevenlevithan.com/regex/xregexp/
- //将字符串安全格式化为正则表达式的源码
- return (target + "").replace(rregexp, "\\$&")
- }
- var plugins = {
- loader: function(builtin) {
- window.define = builtin ? innerRequire.define : otherDefine
- window.require = builtin ? innerRequire : otherRequire
- },
- interpolate: function(array) {
- openTag = array[0]
- closeTag = array[1]
- if (openTag === closeTag) {
- throw new SyntaxError("openTag!==closeTag")
- } else if (array + "" === "") {
- kernel.commentInterpolate = true
- } else {
- var test = openTag + "test" + closeTag
- cinerator.innerHTML = test
- if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") >= 0) {
- throw new SyntaxError("此定界符不合法")
- }
- cinerator.innerHTML = ""
- }
- var o = escapeRegExp(openTag),
- c = escapeRegExp(closeTag)
- rexpr = new RegExp(o + "(.*?)" + c)
- rexprg = new RegExp(o + "(.*?)" + c, "g")
- rbind = new RegExp(o + ".*?" + c + "|\\sms-")
- }
- }
-
- kernel.debug = true
- kernel.plugins = plugins
- kernel.plugins['interpolate'](["{{", "}}"])
- kernel.paths = {}
- kernel.shim = {}
- kernel.maxRepeatSize = 100
- avalon.config = kernel
-
- /*********************************************************************
- * avalon的原型方法定义区 *
- **********************************************************************/
-
- function hyphen(target) {
- //转换为连字符线风格
- return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase()
- }
-
- function camelize(target) {
- //转换为驼峰风格
- if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
- return target //提前判断,提高getStyle等的效率
- }
- return target.replace(/[-_][^-_]/g, function(match) {
- return match.charAt(1).toUpperCase()
- })
- }
-
- var ClassListMethods = {
- _toString: function() {
- var node = this.node//IE6,7元素节点不存在hasAttribute方法
- var cls = node.className
- var str = typeof cls === "string" ? cls : cls.baseVal
- return str.split(/\s+/).join(" ")
- },
- _contains: function(cls) {
- return (" " + this + " ").indexOf(" " + cls + " ") > -1
- },
- _add: function(cls) {
- if (!this.contains(cls)) {
- this._set(this + " " + cls)
- }
- },
- _remove: function(cls) {
- this._set((" " + this + " ").replace(" " + cls + " ", " ").trim())
- },
- __set: function(cls) {
- var node = this.node
- if (typeof node.className === "string") {
- node.className = cls
- } else {//SVG元素的className是一个对象 SVGAnimatedString { baseVal="", animVal=""},只能通过set/getAttribute操作
- node.setAttribute("class", cls)
- }
- }//toggle存在版本差异,因此不使用它
- }
- function ClassList(node) {
- if (!("classList" in node)) {
- node.classList = {
- node: node
- }
- for (var k in ClassListMethods) {
- node.classList[k.slice(1)] = ClassListMethods[k]
- }
- }
- return node.classList
- }
-
-
- "add,remove".replace(rword, function(method) {
- avalon.fn[method + "Class"] = function(cls) {
- var el = this[0]
- //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
- if (cls && typeof cls === "string" && el && el.nodeType === 1) {
- cls.replace(/\S+/g, function(c) {
- ClassList(el)[method](c)
- })
- }
- return this
- }
- })
- avalon.fn.mix({
- hasClass: function(cls) {
- var el = this[0] || {}
- return el.nodeType === 1 && ClassList(el).contains(cls)
- },
- toggleClass: function(value, stateVal) {
- var className, i = 0
- var classNames = value.split(/\s+/)
- var isBool = typeof stateVal === "boolean"
- while ((className = classNames[i++])) {
- var state = isBool ? stateVal : !this.hasClass(className)
- this[state ? "addClass" : "removeClass"](className)
- }
- return this
- },
- attr: function(name, value) {
- if (arguments.length === 2) {
- this[0].setAttribute(name, value)
- return this
- } else {
- return this[0].getAttribute(name)
- }
- },
- data: function(name, value) {
- name = "data-" + hyphen(name || "")
- switch (arguments.length) {
- case 2:
- this.attr(name, value)
- return this
- case 1:
- var val = this.attr(name)
- return parseData(val)
- case 0:
- var ret = {}
- ap.forEach.call(this[0].attributes, function(attr) {
- if (attr) {
- name = attr.name
- if (!name.indexOf("data-")) {
- name = camelize(name.slice(5))
- ret[name] = parseData(attr.value)
- }
- }
- })
- return ret
- }
- },
- removeData: function(name) {
- name = "data-" + hyphen(name)
- this[0].removeAttribute(name)
- return this
- },
- css: function(name, value) {
- if (avalon.isPlainObject(name)) {
- for (var i in name) {
- avalon.css(this, i, name[i])
- }
- } else {
- var ret = avalon.css(this, name, value)
- }
- return ret !== void 0 ? ret : this
- },
- position: function() {
- var offsetParent, offset,
- elem = this[0],
- parentOffset = {
- top: 0,
- left: 0
- }
- if (!elem) {
- return
- }
- if (this.css("position") === "fixed") {
- offset = elem.getBoundingClientRect()
- } else {
- offsetParent = this.offsetParent() //得到真正的offsetParent
- offset = this.offset() // 得到正确的offsetParent
- if (offsetParent[0].tagName !== "HTML") {
- parentOffset = offsetParent.offset()
- }
- parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true)
- parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true)
- }
- return {
- top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true),
- left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true)
- }
- },
- offsetParent: function() {
- var offsetParent = this[0].offsetParent || root
- while (offsetParent && (offsetParent.tagName !== "HTML") && avalon.css(offsetParent, "position") === "static") {
- offsetParent = offsetParent.offsetParent
- }
- return avalon(offsetParent || root)
- },
- bind: function(type, fn, phase) {
- if (this[0]) { //此方法不会链
- return avalon.bind(this[0], type, fn, phase)
- }
- },
- unbind: function(type, fn, phase) {
- if (this[0]) {
- avalon.unbind(this[0], type, fn, phase)
- }
- return this
- },
- val: function(value) {
- var node = this[0]
- if (node && node.nodeType === 1) {
- var get = arguments.length === 0
- var access = get ? ":get" : ":set"
- var fn = valHooks[getValType(node) + access]
- if (fn) {
- var val = fn(node, value)
- } else if (get) {
- return (node.value || "").replace(/\r/g, "")
- } else {
- node.value = value
- }
- }
- return get ? val : this
- }
- })
-
- function parseData(data) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? avalon.parseJSON(data) : data
- } catch (e) {
- }
- return data
- }
- var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g
- avalon.parseJSON = window.JSON ? JSON.parse : function(data) {
- if (typeof data === "string") {
- data = data.trim()
- if (data) {
- if (rvalidchars.test(data.replace(rvalidescape, "@")
- .replace(rvalidtokens, "]")
- .replace(rvalidbraces, ""))) {
- return (new Function("return " + data))()
- }
- }
- avalon.error("Invalid JSON: " + data)
- }
- }
-
- //生成avalon.fn.scrollLeft, avalon.fn.scrollTop方法
- avalon.each({
- scrollLeft: "pageXOffset",
- scrollTop: "pageYOffset"
- }, function(method, prop) {
- avalon.fn[method] = function(val) {
- var node = this[0] || {}, win = getWindow(node),
- top = method === "scrollTop"
- if (!arguments.length) {
- return win ? (prop in win) ? win[prop] : root[method] : node[method]
- } else {
- if (win) {
- win.scrollTo(!top ? val : avalon(win).scrollLeft(), top ? val : avalon(win).scrollTop())
- } else {
- node[method] = val
- }
- }
- }
- })
-
- function getWindow(node) {
- return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false
- }
- //=============================css相关=======================
- var cssHooks = avalon.cssHooks = {}
- var prefixes = ["", "-webkit-", "-o-", "-moz-", "-ms-"]
- var cssMap = {
- "float": "cssFloat",
- background: "backgroundColor"
- }
- avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
-
- avalon.cssName = function(name, host, camelCase) {
- if (cssMap[name]) {
- return cssMap[name]
- }
- host = host || root.style
- for (var i = 0, n = prefixes.length; i < n; i++) {
- camelCase = camelize(prefixes[i] + name)
- if (camelCase in host) {
- return (cssMap[name] = camelCase)
- }
- }
- return null
- }
- cssHooks["@:set"] = function(node, name, value) {
- try { //node.style.width = NaN;node.style.width = "xxx";node.style.width = undefine 在旧式IE下会抛异常
- node.style[name] = value
- } catch (e) {
- }
- }
- if (window.getComputedStyle) {
- cssHooks["@:get"] = function(node, name) {
- if (!node || !node.style) {
- throw new Error("getComputedStyle要求传入一个节点 " + node)
- }
- var ret, computed = getComputedStyle(node, null)
- if (computed) {
- ret = name === "filter" ? computed.getPropertyValue(name) : computed[name]
- if (ret === "") {
- ret = node.style[name] //其他浏览器需要我们手动取内联样式
- }
- }
- return ret
- }
- cssHooks["opacity:get"] = function(node) {
- var ret = cssHooks["@:get"](node, "opacity")
- return ret === "" ? "1" : ret
- }
- } else {
- var rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i
- var rposition = /^(top|right|bottom|left)$/
- var ie8 = !!window.XDomainRequest
- var salpha = "DXImageTransform.Microsoft.Alpha"
- var border = {
- thin: ie8 ? '1px' : '2px',
- medium: ie8 ? '3px' : '4px',
- thick: ie8 ? '5px' : '6px'
- }
- cssHooks["@:get"] = function(node, name) {
- //取得精确值,不过它有可能是带em,pc,mm,pt,%等单位
- var currentStyle = node.currentStyle
- var ret = currentStyle[name]
- if ((rnumnonpx.test(ret) && !rposition.test(ret))) {
- //①,保存原有的style.left, runtimeStyle.left,
- var style = node.style,
- left = style.left,
- rsLeft = node.runtimeStyle.left
- //②由于③处的style.left = xxx会影响到currentStyle.left,
- //因此把它currentStyle.left放到runtimeStyle.left,
- //runtimeStyle.left拥有最高优先级,不会style.left影响
- node.runtimeStyle.left = currentStyle.left
- //③将精确值赋给到style.left,然后通过IE的另一个私有属性 style.pixelLeft
- //得到单位为px的结果;fontSize的分支见http://bugs.jquery.com/ticket/760
- style.left = name === 'fontSize' ? '1em' : (ret || 0)
- ret = style.pixelLeft + "px"
- //④还原 style.left,runtimeStyle.left
- style.left = left
- node.runtimeStyle.left = rsLeft
- }
- if (ret === "medium") {
- name = name.replace("Width", "Style")
- //border width 默认值为medium,即使其为0"
- if (currentStyle[name] === "none") {
- ret = "0px"
- }
- }
- return ret === "" ? "auto" : border[ret] || ret
- }
- cssHooks["opacity:set"] = function(node, name, value) {
- var style = node.style
- var filter = style.filter || ""
- if (filter.indexOf(salpha) === -1) {
- style.filter += "progid:" + salpha + "(opacity=100)"
- }
- var alpha = node.filters[salpha] || {}
- if (value <= 1 && isFinite(value)) {
- style.zoom = alpha.enabled = 1
- alpha.opacity = value * 100
- } else {
- alpha.enabled = 0
- }
- }
- cssHooks["opacity:get"] = function(node) {
- //这是最快的获取IE透明值的方式,不需要动用正则了!
- var alpha = node.filters.alpha || node.filters[salpha],
- op = alpha && alpha.enabled ? alpha.opacity : 100
- return (op / 100) + "" //确保返回的是字符串
- }
- }
-
- "top,left".replace(rword, function(name) {
- cssHooks[name + ":get"] = function(node) {
- var computed = cssHooks["@:get"](node, name)
- return /px$/.test(computed) ? computed :
- avalon(node).position()[name] + "px"
- }
- })
-
- var cssShow = {
- position: "absolute",
- visibility: "hidden",
- display: "block"
- }
-
- var rdisplayswap = /^(none|table(?!-c[ea]).+)/
-
- function showHidden(node, array) {
- //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
- if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
- if (rdisplayswap.test(cssHooks["@:get"](node, "display"))) {
- var obj = {
- node: node
- }
- for (var name in cssShow) {
- obj[name] = node.style[name]
- node.style[name] = cssShow[name]
- }
- array.push(obj)
- }
- var parent = node.parentNode
- if (parent && parent.nodeType === 1) {
- showHidden(parent, array)
- }
- }
- }
- "Width,Height".replace(rword, function(name) {//fix 481
- var method = name.toLowerCase(),
- clientProp = "client" + name,
- scrollProp = "scroll" + name,
- offsetProp = "offset" + name
- cssHooks[method + ":get"] = function(node, which, override) {
- var boxSizing = -4
- if (typeof override === "number") {
- boxSizing = override
- }
- which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
- var ret = node[offsetProp] // border-box 0
- if (boxSizing === 2) { // margin-box 2
- return ret
- + avalon.css(node, "margin" + which[0], true)
- + avalon.css(node, "margin" + which[1], true)
- }
- if (boxSizing < 0) { // padding-box -2
- ret = ret
- - avalon.css(node, "border" + which[0] + "Width", true)
- - avalon.css(node, "border" + which[1] + "Width", true)
- }
- if (boxSizing === -4) { // content-box -4
- ret = ret
- - avalon.css(node, "padding" + which[0], true)
- - avalon.css(node, "padding" + which[1], true)
- }
- return ret
- }
- cssHooks[method + "&get"] = function(node) {
- var hidden = []
- showHidden(node, hidden)
- var val = cssHooks[method + ":get"](node)
- for (var i = 0, obj; obj = hidden[i++]; ) {
- node = obj.node
- for (var n in obj) {
- if (typeof obj[n] === "string") {
- node.style[n] = obj[n]
- }
- }
- }
- return val
- }
- avalon.fn[method] = function(value) { //会忽视其display
- var node = this[0]
- if (arguments.length === 0) {
- if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
- return node["inner" + name] || node.document.documentElement[clientProp]
- }
- if (node.nodeType === 9) { //取得页面尺寸
- var doc = node.documentElement
- //FF chrome html.scrollHeight< body.scrollHeight
- //IE 标准模式 : html.scrollHeight> body.scrollHeight
- //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
- return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
- }
- return cssHooks[method + "&get"](node)
- } else {
- return this.css(method, value)
- }
- }
- avalon.fn["inner" + name] = function() {
- return cssHooks[method + ":get"](this[0], void 0, -2)
- }
- avalon.fn["outer" + name] = function(includeMargin) {
- return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
- }
- })
- avalon.fn.offset = function() { //取得距离页面左右角的坐标
- var node = this[0], box = {
- left: 0,
- top: 0
- }
- if (!node || !node.tagName || !node.ownerDocument) {
- return box
- }
- var doc = node.ownerDocument,
- body = doc.body,
- root = doc.documentElement,
- win = doc.defaultView || doc.parentWindow
- if (!avalon.contains(root, node)) {
- return box
- }
- //http://hkom.blog1.fc2.com/?mode=m&no=750 body的偏移量是不包含margin的
- //我们可以通过getBoundingClientRect来获得元素相对于client的rect.
- //http://msdn.microsoft.com/en-us/library/ms536433.aspx
- if (node.getBoundingClientRect) {
- box = node.getBoundingClientRect() // BlackBerry 5, iOS 3 (original iPhone)
- }
- //chrome/IE6: body.scrollTop, firefox/other: root.scrollTop
- var clientTop = root.clientTop || body.clientTop,
- clientLeft = root.clientLeft || body.clientLeft,
- scrollTop = Math.max(win.pageYOffset || 0, root.scrollTop, body.scrollTop),
- scrollLeft = Math.max(win.pageXOffset || 0, root.scrollLeft, body.scrollLeft)
- // 把滚动距离加到left,top中去。
- // IE一些版本中会自动为HTML元素加上2px的border,我们需要去掉它
- // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx
- return {
- top: box.top + scrollTop - clientTop,
- left: box.left + scrollLeft - clientLeft
- }
- }
-
- //==================================val相关============================
-
- function getValType(el) {
- var ret = el.tagName.toLowerCase()
- return ret === "input" && /checkbox|radio/.test(el.type) ? "checked" : ret
- }
- var roption = /^]+))?)*\s+value[\s=]/i
- var valHooks = {
- "option:get": function(node) {
- //在IE11及W3C,如果没有指定value,那么node.value默认为node.text(存在trim作),但IE9-10则是取innerHTML(没trim操作)
- if (node.hasAttribute) {
- return node.hasAttribute("value") ? node.value : node.text.trim()
- }
- //specified并不可靠,因此通过分析outerHTML判定用户有没有显示定义value
- return roption.test(node.outerHTML) ? node.value : node.text
- },
- "select:get": function(node, value) {
- var option, options = node.options,
- index = node.selectedIndex,
- getter = valHooks["option:get"],
- one = node.type === "select-one" || index < 0,
- values = one ? null : [],
- max = one ? index + 1 : options.length,
- i = index < 0 ? max : one ? index : 0
- for (; i < max; i++) {
- option = options[i]
- //旧式IE在reset后不会改变selected,需要改用i === index判定
- //我们过滤所有disabled的option元素,但在safari5下,如果设置select为disable,那么其所有孩子都disable
- //因此当一个元素为disable,需要检测其是否显式设置了disable及其父节点的disable情况
- if ((option.selected || i === index) && !option.disabled) {
- value = getter(option)
- if (one) {
- return value
- }
- //收集所有selected值组成数组返回
- values.push(value)
- }
- }
- return values
- },
- "select:set": function(node, values, optionSet) {
- values = [].concat(values) //强制转换为数组
- var getter = valHooks["option:get"]
- for (var i = 0, el; el = node.options[i++]; ) {
- if ((el.selected = values.indexOf(getter(el)) >= 0)) {
- optionSet = true
- }
- }
- if (!optionSet) {
- node.selectedIndex = -1
- }
- }
- }
-
- /************************************************************************
- * HTML处理(parseHTML, innerHTML, clearHTML) *
- ************************************************************************/
- var rtagName = /<([\w:]+)/,
- //取得其tagName
- rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
- rcreate = W3C ? /[^\d\D]/ : /(<(?:script|link|style|meta|noscript))/ig,
- scriptTypes = oneObject("text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript", "text/vbscript"),
- //需要处理套嵌关系的标签
- rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/
- //parseHTML的辅助变量
- var tagHooks = {
- area: [1, ""],
- param: [1, ""],
- col: [2, ""],
- legend: [1, ""],
- option: [1, ""],
- thead: [1, ""],
- tr: [2, ""],
- td: [3, ""],
- text: [1, '', ' '],
- //IE6-8在用innerHTML生成节点时,不能直接创建no-scope元素与HTML5的新标签
- _default: W3C ? [0, ""] : [1, "X"] //div可以不用闭合
- }
- tagHooks.optgroup = tagHooks.option
- tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead
- tagHooks.th = tagHooks.td
- tagHooks.circle = tagHooks.ellipse = tagHooks.line = tagHooks.path = //处理SVG
- tagHooks.polygon = tagHooks.polyline = tagHooks.rect = tagHooks.text
- var script = DOC.createElement("script")
- avalon.parseHTML = function(html) {
- if (typeof html !== "string") {
- html = html + ""
- }
- html = html.replace(rxhtml, "<$1>$2>").trim()
- var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(),
- //取得其标签名
- wrap = tagHooks[tag] || tagHooks._default,
- fragment = hyperspace.cloneNode(false),
- wrapper = cinerator,
- firstChild, neo
- if (!W3C) { //fix IE
- html = html.replace(rcreate, "
$1") //在link style script等标签之前添加一个补丁
- }
- wrapper.innerHTML = wrap[1] + html + (wrap[2] || "")
- var els = wrapper.getElementsByTagName("script")
- if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性
- for (var i = 0, el; el = els[i++]; ) {
- if (!el.type || scriptTypes[el.type]) { //如果script节点的MIME能让其执行脚本
- neo = script.cloneNode(false) //FF不能省略参数
- ap.forEach.call(el.attributes, function(attr) {
- if (attr && attr.specified) {
- neo[attr.name] = attr.value //复制其属性
- }
- })
- neo.text = el.text //必须指定,因为无法在attributes中遍历出来
- el.parentNode.replaceChild(neo, el) //替换节点
- }
- }
- }
- //移除我们为了符合套嵌关系而添加的标签
- for (i = wrap[0]; i--; wrapper = wrapper.lastChild) {
- }
- if (!W3C) { //fix IE
- for (els = wrapper["getElementsByTagName"]("br"), i = 0; el = els[i++]; ) {
- if (el.className && el.className === "msNoScope") {
- el.parentNode.removeChild(el)
- }
- }
- for (els = wrapper.all, i = 0; el = els[i++]; ) {//fix VML
- if (isVML(el)) {
- fixVML(el)
- }
- }
- }
- while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上!
- fragment.appendChild(firstChild)
- }
- return fragment
- }
-
- function isVML(src) {
- var nodeName = src.nodeName
- return nodeName.toLowerCase() === nodeName && src.scopeName && src.outerText === ""
- }
- function fixVML(node) {
- if (node.currentStyle.behavior !== "url(#default#VML)") {
- node.style.behavior = "url(#default#VML)"
- node.style.display = "inline-block"
- node.style.zoom = 1 //hasLayout
- }
- }
- avalon.innerHTML = function(node, html) {
- if (!W3C && (!rcreate.test(html) && !rnest.test(html))) {
- try {
- node.innerHTML = html
- return
- } catch (e) {
- }
- }
- var a = this.parseHTML(html)
- this.clearHTML(node).appendChild(a)
- }
- avalon.clearHTML = function(node) {
- while (node.firstChild) {
- node.removeChild(node.firstChild)
- }
- return node
- }
- /*********************************************************************
- * 事件管理器 *
- **********************************************************************/
- var EventManager = {
- $watch: function(type, callback) {
- if (typeof callback === "function") {
- var callbacks = this.$events[type]
- if (callbacks) {
- callbacks.push(callback)
- } else {
- this.$events[type] = [callback]
- }
- } else { //重新开始监听此VM的第一重简单属性的变动
- this.$events = this.$watch.backup
- }
- return this
- },
- $unwatch: function(type, callback) {
- var n = arguments.length
- if (n === 0) { //让此VM的所有$watch回调无效化
- this.$watch.backup = this.$events
- this.$events = {}
- } else if (n === 1) {
- this.$events[type] = []
- } else {
- var callbacks = this.$events[type] || []
- var i = callbacks.length
- while (~--i < 0) {
- if (callbacks[i] === callback) {
- return callbacks.splice(i, 1)
- }
- }
- }
- return this
- },
- $fire: function(type) {
- var special
- if (/^(\w+)!(\S+)$/.test(type)) {
- special = RegExp.$1
- type = RegExp.$2
- }
- var events = this.$events
- var callbacks = events[type] || []
- var all = events.$all || []
- var args = aslice.call(arguments, 1)
- for (var i = 0, callback; callback = callbacks[i++]; ) {
- if (typeof callback === "function")
- callback.apply(this, args)
- }
- for (var i = 0, callback; callback = all[i++]; ) {
- if (typeof callback === "function")
- callback.apply(this, arguments)
- }
- var element = events.expr && findNode(events.expr)
- if (element) {
- var detail = [type].concat(args)
- if (special === "up" || special === "down" || special === "all") {
- for (var i in avalon.vmodels) {
- var v = avalon.vmodels[i]
- if (v && v.$events && v.$events.expr) {
- if (v !== this) {
- var node = findNode(v.$events.expr)
- if (!node) {
- continue
- }
- var ok = special === "all" ? 1 : //全局广播
- special === "down" ? element.contains(node) : //向下捕获
- node.contains(element)//向上冒泡
- if (ok) {
- node._avalon = v//符合条件的加一个标识
- }
- }
- }
- }
- var nodes = document.getElementsByTagName("*")//实现节点排序
- var alls = []
- Array.prototype.forEach.call(nodes, function(el) {
- if (el._avalon) {
- alls.push(el._avalon)
- el._avalon = ""
- el.removeAttribute("_avalon")
- }
- })
- if (special === "up") {
- alls.reverse()
- }
- alls.forEach(function(v) {
- v.$fire.apply(v, detail)
- })
- }
- }
- }
- }
- var ravalon = /(\w+)\[(avalonid)="(\S+)"\]/
- var findNode = document.querySelector ? function(str) {
- return document.querySelector(str)
- } : function(str) {
- var match = str.match(ravalon)
- var all = document.getElementsByTagName(match[1])
- for (var i = 0, el; el = all[i++]; ) {
- if (el.getAttribute(match[2]) === match[3]) {
- return el
- }
- }
- }
- /*********************************************************************
- * 依赖调度系统 *
- **********************************************************************/
-
- var ronduplex = /^(duplex|on)$/
- function registerSubscriber(data, val) {
- var fn = data.evaluator
- if (fn) { //如果是求值函数
- try {
- var c = ronduplex.test(data.type) ? data : fn.apply(0, data.args)
- data.handler(c, data.element, data)
- } catch (e) {
- log("warning:exception throwed in [registerSubscriber] " + e)
- delete data.evaluator
- var node = data.element
- if (node.nodeType === 3) {
- var parent = node.parentNode
- if (kernel.commentInterpolate) {
- parent.replaceChild(DOC.createComment(data.value), node)
- } else {
- node.data = openTag + data.value + closeTag
- }
- }
- }
- }
- }
-
- function collectSubscribers(scope, prop, data) {//收集依赖于这个访问器的订阅者
- var obj = scope.$events
- if (obj) {
- var list = obj[prop] || (obj[prop] = [])
- if (avalon.Array.ensure(list, data) && data.element) {
- $$subscribers.push({
- data: data, list: list
- })
- }
- }
- }
-
-
- var $$subscribers = [], $startIndex = 0, $maxIndex = 300
- function removeSubscribers() {
- for (var i = $startIndex, n = $startIndex + $maxIndex; i < n; i++) {
- var obj = $$subscribers[i]
- if (!obj) {
- break
- }
- var data = obj.data
- var el = data.element
- var remove = el === null ? 1 : (el.nodeType === 1 ? typeof el.sourceIndex === "number" ?
- el.sourceIndex === 0 : !root.contains(el) : !avalon.contains(root, el))
- if (remove) { //如果它没有在DOM树
- $$subscribers.splice(i, 1)
- avalon.Array.remove(obj.list, data)
- // log("debug: remove " + data.type)
- if (data.type === "if" && data.template && data.template.parentNode === head) {
- head.removeChild(data.template)
- }
- for (var key in data) {
- data[key] = null
- }
- obj.data = obj.list = null
- i--
- n--
- }
- }
- obj = $$subscribers[i]
- if (obj) {
- $startIndex = n
- } else {
- $startIndex = 0
- }
- }
-
- var beginTime = new Date(), removeID
- function notifySubscribers(list) {
- clearTimeout(removeID)
- if (new Date() - beginTime > 333) {
- removeSubscribers()
- beginTime = new Date()
- } else {
- removeID = setTimeout(removeSubscribers, 333)
- }
- if (list && list.length) {
- var args = aslice.call(arguments, 1)
- for (var i = list.length, fn; fn = list[--i]; ) {
- if (fn.$repeat) {
- fn.handler.apply(fn, args) //处理监控数组的方法
- } else if (fn.element && fn.type !== "on") {//事件绑定只能由用户触发,不能由程序触发
- var fun = fn.evaluator || noop
- fn.handler(fun.apply(0, fn.args || []), fn.element, fn)
- }
- }
- }
- }
-
- /*********************************************************************
- * 扫描系统 *
- **********************************************************************/
- avalon.scan = function(elem, vmodel) {
- elem = elem || root
- var vmodels = vmodel ? [].concat(vmodel) : []
- scanTag(elem, vmodels)
- }
-
- //http://www.w3.org/TR/html5/syntax.html#void-elements
- var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase())
-
- //确保元素的内容被完全扫描渲染完毕才调用回调
- var interval = W3C ? 15 : 50
-
- function checkScan(elem, callback) {
- var innerHTML = NaN,
- id = setInterval(function() {
- var currHTML = elem.innerHTML
- if (currHTML === innerHTML) {
- clearInterval(id)
- callback()
- } else {
- innerHTML = currHTML
- }
- }, interval)
- }
- function addId(elem, value) {
- if (typeof elem.getAttribute("avalonid") !== "string") {
- elem.setAttribute("avalonid", value)
- }
- }
-
- function scanTag(elem, vmodels, node) {
- //扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
- //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
- var a = elem.getAttribute("ms-skip")
- //#360 在旧式IE中 Object标签在引入Flash等资源时,可能出现没有getAttributeNode,innerHTML的情形
- if (!elem.getAttributeNode) {
- return log("warning " + elem.tagName + " no getAttributeNode method")
- }
- var b = elem.getAttributeNode("ms-important")
- var c = elem.getAttributeNode("ms-controller")
- if (typeof a === "string") {
- return
- } else if (node = b || c) {
- var newVmodel = VMODELS[node.value]
- if (!newVmodel) {
- return
- }
- //ms-important不包含父VM,ms-controller相反
- vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
- var name = node.name
- elem.removeAttribute(name) //removeAttributeNode不会刷新[ms-controller]样式规则
- addId(elem, node.value)
- newVmodel.$events.expr = elem.tagName + '[avalonid="' + node.value + '"]'
- avalon(elem).removeClass(name)
-
- }
- scanAttr(elem, vmodels) //扫描特性节点
- }
-
- function scanNodeList(parent, vmodels) {
- var node = parent.firstChild
- while (node) {
- var nextNode = node.nextSibling
- scanNode(node, node.nodeType, vmodels)
- node = nextNode
- }
- }
- function scanNodeArray(nodes, vmodels) {
- for (var i = 0, node; node = nodes[i++]; ) {
- scanNode(node, node.nodeType, vmodels)
- }
- }
- function scanNode(node, nodeType, vmodels) {
- if (nodeType === 1) {
- scanTag(node, vmodels) //扫描元素节点
- } else if (nodeType === 3 && rexpr.test(node.data)) {
- scanText(node, vmodels) //扫描文本节点
- } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) {
- scanText(node, vmodels) //扫描注释节点
- }
- }
- function scanText(textNode, vmodels) {
- var bindings = []
- if (textNode.nodeType === 8) {
- var leach = []
- var value = trimFilter(textNode.nodeValue, leach)
- var token = {
- expr: true,
- value: value
- }
- if (leach.length) {
- token.filters = leach
- }
- var tokens = [token]
- } else {
- tokens = scanExpr(textNode.data)
- }
- if (tokens.length) {
- for (var i = 0, token; token = tokens[i++]; ) {
- var node = DOC.createTextNode(token.value) //将文本转换为文本节点,并替换原来的文本节点
- if (token.expr) {
- var filters = token.filters
- var binding = {
- type: "text",
- element: node,
- value: token.value,
- filters: filters
- }
- if (filters && filters.indexOf("html") !== -1) {
- avalon.Array.remove(filters, "html")
- binding.type = "html"
- binding.group = 1
- if (!filters.length) {
- delete bindings.filters
- }
- }
- bindings.push(binding) //收集带有插值表达式的文本
- }
- hyperspace.appendChild(node)
- }
- textNode.parentNode.replaceChild(hyperspace, textNode)
- if (bindings.length)
- executeBindings(bindings, vmodels)
- }
- }
-
- var rmsAttr = /ms-(\w+)-?(.*)/
- var priorityMap = {
- "if": 10,
- "repeat": 90,
- "data": 100,
- "widget": 110,
- "each": 1400,
- "with": 1500,
- "duplex": 2000,
- "on": 3000
- }
- var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit")
- function bindingSorter(a, b) {
- return a.priority - b.priority
- }
- function scanAttr(elem, vmodels) {
- //防止setAttribute, removeAttribute时 attributes自动被同步,导致for循环出错
- var attributes = getAttributes ? getAttributes(elem) : avalon.slice(elem.attributes)
- var bindings = [],
- msData = {},
- match
- for (var i = 0, attr; attr = attributes[i++]; ) {
- if (attr.specified) {
- if (match = attr.name.match(rmsAttr)) {
- //如果是以指定前缀命名的
- var type = match[1]
- var param = match[2] || ""
- var value = attr.value
- var name = attr.name
- msData[name] = value
- if (events[type]) {
- param = type
- type = "on"
- } else if (type === "enabled") {//吃掉ms-enabled绑定,用ms-disabled代替
- type = "disabled"
- value = "!(" + value + ")"
- }
- //吃掉以下几个绑定,用ms-attr-*绑定代替
- if (type === "checked" || type === "selected" || type === "disabled" || type === "readonly") {
- param = type
- type = "attr"
- elem.removeAttribute(name)
- name = "ms-attr-" + param
- elem.setAttribute(name, value)
- match = [name]
- msData[name] = value
- }
- if (typeof bindingHandlers[type] === "function") {
- var binding = {
- type: type,
- param: param,
- element: elem,
- name: match[0],
- value: value,
- priority: type in priorityMap ? priorityMap[type] : type.charCodeAt(0) * 10 + (Number(param) || 0)
- }
- if (type === "if" && param.indexOf("loop") > -1) {
- binding.priority += 100
- }
- if (vmodels.length) {
- bindings.push(binding)
- if (type === "widget") {
- elem.msData = elem.msData || msData
- }
- }
- }
- }
- }
- }
- bindings.sort(bindingSorter)
- if (msData["ms-checked"] && msData["ms-duplex"]) {
- log("warning!一个元素上不能同时定义ms-checked与ms-duplex")
- }
- var firstBinding = bindings[0] || {}
- switch (firstBinding.type) {
- case "if":
- case "repeat":
- case "widget":
- executeBindings([firstBinding], vmodels)
- break
- default:
- executeBindings(bindings, vmodels)
- if (!stopScan[elem.tagName] && rbind.test(elem.innerHTML.replace(rlt, "<").replace(rgt, ">"))) {
- scanNodeList(elem, vmodels) //扫描子孙元素
- }
- break
- }
-
- }
- //IE67下,在循环绑定中,一个节点如果是通过cloneNode得到,自定义属性的specified为false,无法进入里面的分支,
- //但如果我们去掉scanAttr中的attr.specified检测,一个元素会有80+个特性节点(因为它不区分固有属性与自定义属性),很容易卡死页面
- if (!"1" [0]) {
- var cacheAttrs = cacheFactory("attrs", 256)
- var rattrs = /\s+(ms-[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g,
- rquote = /^['"]/,
- rtag = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/i,
- ramp = /&/g
- //IE6-8解析HTML5新标签,会将它分解两个元素节点与一个文本节点
- //
- // window.onload = function() {
- // var body = document.body
- // for (var i = 0, el; el = body.children[i++]; ) {
- // avalon.log(el.outerHTML)
- // }
- // }
- //依次输出
- var getAttributes = function(elem) {
- var html = elem.outerHTML
- //处理IE6-8解析HTML5新标签的情况,及
等半闭合标签outerHTML为空的情况
- if (html.slice(0, 2) === "" || !html.trim()) {
- return []
- }
- var str = html.match(rtag)[0]
- var attributes = [],
- match,
- k, v
- var has = cacheAttrs.get(str)
- if (has !== void 0) {
- return has
- }
- while (k = rattrs.exec(str)) {
- v = k[2]
- if (v) {
- v = (rquote.test(v) ? v.slice(1, -1) : v).replace(ramp, "&")
- }
- var name = k[1].toLowerCase()
- match = name.match(rmsAttr)
- var binding = {
- name: name,
- specified: true,
- value: v || ""
- }
- attributes.push(binding)
- }
- return cacheAttrs.set(str, attributes)
- }
- }
-
- function executeBindings(bindings, vmodels) {
- for (var i = 0, data; data = bindings[i++]; ) {
- data.vmodels = vmodels
- bindingHandlers[data.type](data, vmodels)
- if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数据绑定,防止被二次解析
- //chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99
- data.element.removeAttribute(data.name)
- }
- }
- bindings.length = 0
- }
-
-
- var rfilters = /\|\s*(\w+)\s*(\([^)]*\))?/g,
- r11a = /\|\|/g,
- r11b = /U2hvcnRDaXJjdWl0/g,
- rlt = /</g,
- rgt = />/g
- function trimFilter(value, leach) {
- if (value.indexOf("|") > 0) { // 抽取过滤器 先替换掉所有短路与
- value = value.replace(r11a, "U2hvcnRDaXJjdWl0") //btoa("ShortCircuit")
- value = value.replace(rfilters, function(c, d, e) {
- leach.push(d + (e || ""))
- return ""
- })
- value = value.replace(r11b, "||") //还原短路与
- }
- return value
- }
-
- function scanExpr(str) {
- var tokens = [],
- value, start = 0,
- stop
- do {
- stop = str.indexOf(openTag, start)
- if (stop === -1) {
- break
- }
- value = str.slice(start, stop)
- if (value) { // {{ 左边的文本
- tokens.push({
- value: value,
- expr: false
- })
- }
- start = stop + openTag.length
- stop = str.indexOf(closeTag, start)
- if (stop === -1) {
- break
- }
- value = str.slice(start, stop)
- if (value) { //处理{{ }}插值表达式
- var leach = []
- value = trimFilter(value, leach)
- tokens.push({
- value: value,
- expr: true,
- filters: leach.length ? leach : void 0
- })
- }
- start = stop + closeTag.length
- } while (1)
- value = str.slice(start)
- if (value) { //}} 右边的文本
- tokens.push({
- value: value,
- expr: false
- })
- }
-
- return tokens
- }
- /*********************************************************************
- * 编译系统 *
- **********************************************************************/
- var keywords =
- // 关键字
- "break,case,catch,continue,debugger,default,delete,do,else,false"
- + ",finally,for,function,if,in,instanceof,new,null,return,switch,this"
- + ",throw,true,try,typeof,var,void,while,with"
- // 保留字
- + ",abstract,boolean,byte,char,class,const,double,enum,export,extends"
- + ",final,float,goto,implements,import,int,interface,long,native"
- + ",package,private,protected,public,short,static,super,synchronized"
- + ",throws,transient,volatile"
- // ECMA 5 - use strict
- + ",arguments,let,yield"
- + ",undefined"
- var robjectProperty = /([\w\.\_$])\s*\[['"]([^'"]+)['"]\]/
- //处理注释及字符串
- var rstringComment = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'/g
- //处理加减乘除小括号等运算符
- var roperator = /[^\w\.$]+/g
- //处理数字
- var rnumber = /\b\d[^,]*/g
- //处理最前面或最后面逗号
- var rcommaOfFirstOrLast = /^,+|,+$/g
- //处理位于中间的逗号
- var rcommaInMiddle = /,+/
- //去掉所有关键字保留字
- var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g')
- var cacheVars = cacheFactory("vars", 128)
- var getVariables = function(str) {
- var key = "," + str.trim()
- var has = cacheVars.get(key)
- if (has !== void 0) {
- return has
- }
- while (robjectProperty.test(str)) {
- str = str.replace(robjectProperty, function(match, obj, prop) {
- return obj + '.' + prop
- })
- }
- var vars = str.replace(rstringComment, "")
- .replace(roperator, ",")
- .replace(rkeywords, ",")
- .replace(rnumber, ",")
- .replace(rcommaOfFirstOrLast, "")
- .split(rcommaInMiddle)
- return cacheVars.set(key, uniqSet(vars))
- }
-
- function uniqSet(array) {
- var ret = [], unique = {}
- for (var i = 0; i < array.length; i++) {
- var el = array[i]
- var id = el && typeof el.$id === "string" ? el.$id : el
- if (!unique[id]) {
- unique[id] = ret.push(el)
- }
- }
- return ret
- }
-
- void function() {
- var test = [1, 2, 3, 1]
- if (typeof Set === "function" && (new Set(test)).size === 3) {
- var uniqSet = function(arr) {//重写uniqSet
- var set = new Set(arr), ret = []
- set.forEach(function(el) {
- ret.push(el)
- })
- return ret
- }
- }
- }()
-
-
- function inObject(obj, array) {
- if (!obj.hasOwnProperty(array[0])) {
- return 0
- }
- for (var i = 1, el; el = array[i++]; ) {
- if (!obj.hasOwnProperty(el)) {
- return (obj && typeof obj === "object") ? 1 : 0
- } else {
- obj = obj[el]
- }
- }
- return 2
- }
- /*添加赋值语句*/
- var rvariable = /[$\w][$\w]*\./g
- function addAssign(vars, scope, name, data) {
- var ret = [],
- prefix = " = " + name + "."
- for (var i = vars.length, path; path = vars[--i]; ) {
- var arr = path.split(".")
- var flag = inObject(scope, arr)
- if (flag) {
- var prop = arr.shift()
- if (typeof scope[prop] === "function") {
- var _vars = getVariables(scope[prop].toString().replace(rvariable, "")).concat()
- avalon.Array.remove(_vars, prop)
- addAssign(_vars, scope, name, data)
- } else {
- collectSubscribers(scope, prop, data)
- }
- ret.push(prop + prefix + prop)
- if (data.type === "duplex") {
- vars.get = name + "." + prop
- }
- var subscope = scope
- do {//处理子对象
- var parentList = scope.$events[prop]
- var parentName = prop
- subscope = subscope[prop]
- if (subscope && typeof subscope === "object") {
- prop = arr.shift()
- if ((prop === void 0 || prop === "length") && Array.isArray(subscope)) {
- var sonEvents = subscope.$events
- if (!sonEvents)
- continue
-// var sonList = sonEvents[subscribers]
-// if (sonList !== parentList) {
-// if (sonList && sonList.length) {
-// for (var j = 0, fn; fn = sonList[j++]; ) {
-// avalon.Array.ensure(parentList, fn)
-// }
-// }
-// sonEvents[subscribers] = parentList
-// prop = subscribers
-// }
- prop = subscribers
- }
- collectSubscribers(subscope, prop, data)
- } else {
- break
- }
- } while (arr.length)
- if (flag > 0)
- vars.splice(i, 1)
- }
- }
- return ret
- }
-
-
- //缓存求值函数,以便多次利用
- var cacheExprs = cacheFactory("epxrs", 124)
- //取得求值函数及其传参
- var rduplex = /\w\[.*\]|\w\.\w/
- var rproxy = /(\$proxy\$[a-z]+)\d+$/
-
- function parseExpr(code, scopes, data) {
- var dataType = data.type
- var filters = data.filters ? data.filters.join("") : ""
- var exprId = scopes.map(function(el) {
- return el.$id.replace(rproxy, "$1")
- }) + code + dataType + filters
- var vars = getVariables(code).concat(),
- assigns = [],
- names = [],
- args = [],
- prefix = ""
- //args 是一个对象数组, names 是将要生成的求值函数的参数
- scopes = uniqSet(scopes)
- for (var i = 0, sn = scopes.length; i < sn; i++) {
- if (vars.length) {
- var name = "vm" + expose + "_" + i
- names.push(name)
- args.push(scopes[i])
- assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data))
- }
- }
- if (!assigns.length && dataType === "duplex") {
- return
- }
- //---------------args----------------
- if (filters) {
- args.push(avalon.filters)
- }
- data.args = args
- //---------------cache----------------
- var fn = cacheExprs.get(exprId) //直接从缓存,免得重复生成
- if (fn) {
- data.evaluator = fn
- return
- }
- var prefix = assigns.join(", ")
- if (prefix) {
- prefix = "var " + prefix
- }
- if (filters) { //文本绑定,双工绑定才有过滤器
- code = "\nvar ret" + expose + " = " + code
- var textBuffer = [],
- fargs
- textBuffer.push(code, "\r\n")
- for (var i = 0, fname; fname = data.filters[i++]; ) {
- var start = fname.indexOf("(")
- if (start !== -1) {
- fargs = fname.slice(start + 1, fname.lastIndexOf(")")).trim()
- fargs = "," + fargs
- fname = fname.slice(0, start).trim()
- } else {
- fargs = ""
- }
- textBuffer.push(" if(filters", expose, ".", fname, "){\n\ttry{\nret", expose,
- " = filters", expose, ".", fname, "(ret", expose, fargs, ")\n\t}catch(e){} \n}\n")
- }
- code = textBuffer.join("")
- code += "\nreturn ret" + expose
- names.push("filters" + expose)
- } else if (dataType === "duplex") { //双工绑定
- var _body = "'use strict';\nreturn function(vvv){\n\t" +
- prefix +
- ";\n\tif(!arguments.length){\n\t\treturn " +
- code +
- "\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) +
- "= vvv;\n} "
- try {
- fn = Function.apply(noop, names.concat(_body))
- data.evaluator = cacheExprs.set(exprId, fn)
-
- } catch (e) {
- log("debug: parse error," + e.message)
- }
- return
- } else if (dataType === "on") { //事件绑定
- if (code.indexOf("(") === -1) {
- code += ".call(this, $event)"
- } else {
- code = code.replace("(", ".call(this,")
- }
- names.push("$event")
- code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需要Function("return ;")
- var lastIndex = code.lastIndexOf("\nreturn")
- var header = code.slice(0, lastIndex)
- var footer = code.slice(lastIndex)
- code = header + "\n" + footer
- } else { //其他绑定
- code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需要Function("return ;")
- }
- try {
- fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code))
- data.evaluator = cacheExprs.set(exprId, fn)
- } catch (e) {
- log("debug: parse error," + e.message)
- } finally {
- vars = textBuffer = names = null //释放内存
- }
- }
-
- var meta = {
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"': '\\"',
- '\\': '\\\\'
- };
- var quote = window.JSON && JSON.stringify || function(str) {
- return '"' + str.replace(/[\\\"\x00-\x1f]/g, function(a) {
- var c = meta[a]
- return typeof c === 'string' ? c :
- '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)
- }) + '"'
- }
- //parseExpr的智能引用代理
- function parseExprProxy(code, scopes, data, tokens) {
- if (Array.isArray(tokens)) {
- code = tokens.map(function(el) {
- return el.expr ? "(" + el.value + ")" : quote(el.value)
- }).join(" + ")
- }
- parseExpr(code, scopes, data)
- if (data.evaluator) {
- data.handler = bindingExecutors[data.handlerName || data.type]
- data.evaluator.toString = function() {
- return data.type + " binding to eval(" + code + ")"
- }
- //方便调试
- //这里非常重要,我们通过判定视图刷新函数的element是否在DOM树决定
- //将它移出订阅者列表
- registerSubscriber(data)
- }
- }
-
-
- avalon.parseExprProxy = parseExprProxy
- /*********************************************************************
- * 绑定处理系统 *
- **********************************************************************/
- var propMap = {//属性名映射
- "accept-charset": "acceptCharset",
- "char": "ch",
- "charoff": "chOff",
- "class": "className",
- "for": "htmlFor",
- "http-equiv": "httpEquiv"
- }
-
- var anomaly = "accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan,"
- + "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight,"
- + "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
- anomaly.replace(rword, function(name) {
- propMap[name.toLowerCase()] = name
- })
-
- var cssText = ""
- head.insertBefore(avalon.parseHTML(cssText), head.firstChild) //避免IE6 base标签BUG
- var rnoscripts = /
(?:[\s\S]+?)<\/noscript>/img
- var rnoscriptText = /([\s\S]+?)<\/noscript>/im
-
- var getXHR = function() {
- return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")
- }
- var getBindingCallback = function(elem, name, vmodels) {
- var callback = elem.getAttribute(name)
- if (callback) {
- for (var i = 0, vm; vm = vmodels[i++]; ) {
- if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") {
- return vm[callback]
- }
- }
- }
- }
- var cacheTmpls = avalon.templateCache = {}
- avalon.contains = fixContains
- var bools = "autofocus,autoplay,async,allowTransparency,checked,controls,declare,disabled,defer,defaultChecked,defaultSelected" +
- "contentEditable,isMap,loop,multiple,noHref,noResize,noShade,open,readOnly,selected"
- var boolMap = {}
- bools.replace(rword, function(name) {
- boolMap[name.toLowerCase()] = name
- })
-
- //这里的函数每当VM发生改变后,都会被执行(操作方为notifySubscribers)
- var bindingExecutors = avalon.bindingExecutors = {
- "attr": function(val, elem, data) {
- var method = data.type,
- attrName = data.param
- if (method === "css") {
- avalon(elem).css(attrName, val)
- } else if (method === "attr") {
- // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc
- // ms-attr-class="xxx" vm.xxx=false 清空元素的所有类名
- // ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性
- if (boolMap[attrName]) {
- var bool = boolMap[attrName]
- if (typeof elem[bool] === "boolean") {
- return elem[bool] = !!val
- }
- }
- var toRemove = (val === false) || (val === null) || (val === void 0)
- if (!W3C && propMap[attrName]) {//旧式IE下需要进行名字映射
- attrName = propMap[attrName]
- var isInnate = true
- }
- if (toRemove) {
- return elem.removeAttribute(attrName)
- }
- if (window.VBArray && !isInnate) {//IE下需要区分固有属性与自定义属性
- if (isVML(elem)) {
- isInnate = true
- } else if (!rsvg.test(elem)) {
- var attrs = elem.attributes || {}
- var attr = attrs[attrName]
- isInnate = attr ? attr.expando === false : attr === null
- }
- }
- if (isInnate) {
- elem[attrName] = val
- } else {
- elem.setAttribute(attrName, val)
- }
- } else if (method === "include" && val) {
- var vmodels = data.vmodels
- var rendered = getBindingCallback(elem, "data-include-rendered", vmodels)
- var loaded = getBindingCallback(elem, "data-include-loaded", vmodels)
-
- function scanTemplate(text) {
- if (loaded) {
- text = loaded.apply(elem, [text].concat(vmodels))
- }
- avalon.innerHTML(elem, text)
- scanNodeList(elem, vmodels)
- rendered && checkScan(elem, function() {
- rendered.call(elem)
- })
- }
- if (data.param === "src") {
- if (cacheTmpls[val]) {
- scanTemplate(cacheTmpls[val])
- } else {
- var xhr = getXHR()
- xhr.onreadystatechange = function() {
- if (xhr.readyState === 4) {
- var s = xhr.status
- if (s >= 200 && s < 300 || s === 304 || s === 1223) {
- scanTemplate(cacheTmpls[val] = xhr.responseText)
- }
- }
- }
- xhr.open("GET", val, true)
- if ("withCredentials" in xhr) {
- xhr.withCredentials = true
- }
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
- xhr.send(null)
- }
- } else {
- //IE系列与够新的标准浏览器支持通过ID取得元素(firefox14+)
- //http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/
- var el = val && val.nodeType === 1 ? val : DOC.getElementById(val)
- if (el) {
- if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法取得其内容,IE6能取得其innerHTML
- var xhr = getXHR() //IE9-11与chrome的innerHTML会得到转义的内容,它们的innerText可以
- xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构
- xhr.send(null)
- //http://bbs.csdn.net/topics/390349046?page=1#post-393492653
- var noscripts = DOC.getElementsByTagName("noscript")
- var array = (xhr.responseText || "").match(rnoscripts) || []
- var n = array.length
- for (var i = 0; i < n; i++) {
- var tag = noscripts[i]
- if (tag) { //IE6-8中noscript标签的innerHTML,innerText是只读的
- tag.style.display = "none" //http://haslayout.net/css/noscript-Ghost-Bug
- tag.fixIE78 = (array[i].match(rnoscriptText) || ["", " "])[1]
- }
- }
- }
- avalon.nextTick(function() {
- scanTemplate(el.fixIE78 || el.value || el.innerText || el.innerHTML)
- })
- }
- }
- } else {
- if (!root.hasAttribute && typeof val === "string" && (method === "src" || method === "href")) {
- val = val.replace(/&/g, "&") //处理IE67自动转义的问题
- }
- elem[method] = val
- if (window.chrome && elem.tagName === "EMBED") {
- var parent = elem.parentNode//#525 chrome1-37下embed标签动态设置src不能发生请求
- var comment = document.createComment("ms-src")
- parent.replaceChild(comment, elem)
- parent.replaceChild(elem, comment)
- }
- }
- },
- "class": function(val, elem, data) {
- var $elem = avalon(elem),
- method = data.type
- if (method === "class" && data.oldStyle) { //如果是旧风格
- $elem.toggleClass(data.oldStyle, !!val)
- } else {
- //如果存在冒号就有求值函数
- data.toggleClass = data._evaluator ? !!data._evaluator.apply(elem, data._args) : true
- data.newClass = data.immobileClass || val
- if (data.oldClass && data.newClass !== data.oldClass) {
- $elem.removeClass(data.oldClass)
- }
- data.oldClass = data.newClass
- switch (method) {
- case "class":
- $elem.toggleClass(data.newClass, data.toggleClass)
- break
- case "hover":
- case "active":
- if (!data.hasBindEvent) { //确保只绑定一次
- var activate = "mouseenter" //在移出移入时切换类名
- var abandon = "mouseleave"
- if (method === "active") {//在聚焦失焦中切换类名
- elem.tabIndex = elem.tabIndex || -1
- activate = "mousedown"
- abandon = "mouseup"
- $elem.bind("mouseleave", function() {
- data.toggleClass && $elem.removeClass(data.newClass)
- })
- }
- $elem.bind(activate, function() {
- data.toggleClass && $elem.addClass(data.newClass)
- })
- $elem.bind(abandon, function() {
- data.toggleClass && $elem.removeClass(data.newClass)
- })
- data.hasBindEvent = true
- }
- break
- }
- }
- },
- "data": function(val, elem, data) {
- var key = "data-" + data.param
- if (val && typeof val === "object") {
- elem[key] = val
- } else {
- elem.setAttribute(key, String(val))
- }
- },
- "html": function(val, elem, data) {
- val = val == null ? "" : val
- var parent = "group" in data ? elem.parentNode : elem
- if ("group" in data) {
- var fragment, nodes
- //将值转换为文档碎片,原值可以为元素节点,文档碎片,NodeList,字符串
- if (val.nodeType === 11) {
- fragment = val
- } else if (val.nodeType === 1 || val.item) {
- nodes = val.nodeType === 1 ? val.childNodes : val.item ? val : []
- fragment = hyperspace.cloneNode(true)
- while (nodes[0]) {
- fragment.appendChild(nodes[0])
- }
- } else {
- fragment = avalon.parseHTML(val)
- }
- nodes = avalon.slice(fragment.childNodes)
- if (nodes.length == 0) {
- var comment = DOC.createComment("ms-html")
- fragment.appendChild(comment)
- nodes = [comment]
- }
- parent.insertBefore(fragment, elem) //fix IE6-8 insertBefore的第2个参数只能为节点或null
- var length = data.group
- while (elem) {
- var nextNode = elem.nextSibling
- parent.removeChild(elem)
- length--
- if (length == 0 || nextNode === null)
- break
- elem = nextNode
- }
- data.element = nodes[0]
- data.group = nodes.length
- } else {
- avalon.innerHTML(parent, val)
- }
- avalon.nextTick(function() {
- scanNodeList(parent, data.vmodels)
- })
- },
- "if": function(val, elem, data) {
- if (val) { //插回DOM树
- if (elem.nodeType === 8) {
- elem.parentNode.replaceChild(data.template, elem)
- elem = data.element = data.template
- }
- if (elem.getAttribute(data.name)) {
- elem.removeAttribute(data.name)
- scanAttr(elem, data.vmodels)
- }
- } else { //移出DOM树,并用注释节点占据原位置
- if (elem.nodeType === 1) {
- var node = data.element = DOC.createComment("ms-if")
- elem.parentNode.replaceChild(node, elem)
- data.template = elem
- head.appendChild(elem)
- }
- }
- },
- "on": function(callback, elem, data) {
- data.type = "on"
- var fn = data.evaluator || noop
- callback = function(e) {
- // var fn = data.evaluator || noop
- return fn.apply(this, data.args.concat(e))
- }
- var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
- if (eventType === "scan") {
- callback.call(elem, {type: eventType})
- } else if (typeof data.specialBind === "function") {
- data.specialBind(elem, callback)
- } else {
- var removeFn = avalon.bind(elem, eventType, callback)
- }
- data.rollback = function() {
- if (typeof data.specialUnbind === "function") {
- data.specialUnbind()
- } else {
- avalon.unbind(elem, eventType, removeFn)
- }
- }
- data.evaluator = data.handler = noop
- },
- "text": function(val, elem) {
- val = val == null ? "" : val //不在页面上显示undefined null
- if (elem.nodeType === 3) { //绑定在文本节点上
- try {//IE对游离于DOM树外的节点赋值会报错
- elem.data = val
- } catch (e) {
- }
- } else { //绑定在特性节点上
- if ("textContent" in elem) {
- elem.textContent = val
- } else {
- elem.innerText = val
- }
- }
- },
- "visible": function(val, elem, data) {
- elem.style.display = val ? data.display : "none"
- },
- "widget": noop
- }
-
- var rdash = /\(([^)]*)\)/
- function parseDisplay(nodeName, val) {
- //用于取得此类标签的默认display值
- var key = "_" + nodeName
- if (!parseDisplay[key]) {
- var node = DOC.createElement(nodeName)
- root.appendChild(node)
- if (W3C) {
- val = getComputedStyle(node, null).display
- } else {
- val = node.currentStyle.display
- }
- root.removeChild(node)
- parseDisplay[key] = val
- }
- return parseDisplay[key]
- }
-
- avalon.parseDisplay = parseDisplay
- //这里的函数只会在第一次被扫描后被执行一次,并放进行对应VM属性的subscribers数组内(操作方为registerSubscriber)
- var bindingHandlers = avalon.bindingHandlers = {
- //这是一个字符串属性绑定的范本, 方便你在title, alt, src, href, include, css添加插值表达式
- //
- "attr": function(data, vmodels) {
- var text = data.value.trim(),
- simple = true
- if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) {
- simple = false
- if (rexpr.test(text) && RegExp.rightContext === "" && RegExp.leftContext === "") {
- simple = true
- text = RegExp.$1
- }
- }
- data.handlerName = "attr" //handleName用于处理多种绑定共用同一种bindingExecutor的情况
- parseExprProxy(text, vmodels, data, (simple ? null : scanExpr(data.value)))
- },
- //根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
- //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
- "class": function(data, vmodels) {
- var oldStyle = data.param,
- text = data.value,
- rightExpr
- data.handlerName = "class"
- if (!oldStyle || isFinite(oldStyle)) {
- data.param = "" //去掉数字
- var noExpr = text.replace(rexprg, function(a) {
- return Math.pow(10, a.length - 1) //将插值表达式插入10的N-1次方来占位
- })
- var colonIndex = noExpr.indexOf(":") //取得第一个冒号的位置
- if (colonIndex === -1) { // 比如 ms-class="aaa bbb ccc" 的情况
- var className = text
- } else { // 比如 ms-class-1="ui-state-active:checked" 的情况
- className = text.slice(0, colonIndex)
- rightExpr = text.slice(colonIndex + 1)
- parseExpr(rightExpr, vmodels, data) //决定是添加还是删除
- if (!data.evaluator) {
- log("debug: ms-class '" + (rightExpr || "").trim() + "' 不存在于VM中")
- return false
- } else {
- data._evaluator = data.evaluator
- data._args = data.args
- }
- }
- var hasExpr = rexpr.test(className) //比如ms-class="width{{w}}"的情况
- if (!hasExpr) {
- data.immobileClass = className
- }
- parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : null))
- } else {
- data.immobileClass = data.oldStyle = data.param
- parseExprProxy(text, vmodels, data)
- }
- },
- "duplex": function(data, vmodels) {
- var elem = data.element,
- tagName = elem.tagName
- if (typeof duplexBinding[tagName] === "function") {
- data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
- //由于情况特殊,不再经过parseExprProxy
- parseExpr(data.value, vmodels, data)
- if (data.evaluator && data.args) {
- var form = elem.form
- if (form && form.msValidate) {
- form.msValidate(elem)
- }
- data.msType = data.param || ""
- if (data.msType === "bool") {
- data.msType = "boolean"
- log("ms-duplex-bool已经更名为ms-duplex-boolean")
- } else if (data.msType === "text") {
- data.msType = "string"
- log("ms-duplex-text已经更名为ms-duplex-string")
- }
- if (data.msType === "radio") {
- log("ms-duplex-radio将在2.0废掉,请尽量不要用")
- }
- if (!/boolean|string|number/.test(data.msType)) {
- data.msType = ""
- }
- data.bound = function(type, callback) {
- if (elem.addEventListener) {
- elem.addEventListener(type, callback, false)
- } else {
- elem.attachEvent("on" + type, callback)
- }
- var old = data.rollback
- data.rollback = function() {
- avalon.unbind(elem, type, callback)
- old && old()
- }
- }
- duplexBinding[elem.tagName](elem, data.evaluator.apply(null, data.args), data)
- }
- }
- },
- "repeat": function(data, vmodels) {
- var type = data.type
- parseExpr(data.value, vmodels, data)
- data.proxies = []
- try {
- var $repeat = data.$repeat = data.evaluator.apply(0, data.args || [])
- var xtype = avalon.type($repeat)
- if (xtype !== "object" && xtype !== "array") {
- return avalon.log("warning:" + data.value + "对应类型不正确")
- }
- } catch (e) {
- return avalon.log("warning:" + data.value + "编译出错")
- }
- var elem = data.element
- elem.removeAttribute(data.name)
- data.sortedCallback = getBindingCallback(elem, "data-with-sorted", vmodels)
- data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels)
-
- var comment = data.element = DOC.createComment("ms-repeat")
- if (type === "each" || type == "with") {
- data.template = elem.innerHTML.trim()
- avalon.clearHTML(elem).appendChild(comment)
- } else {
- data.template = elem.outerHTML.trim()
- data.group = 1
- elem.parentNode.replaceChild(comment, elem)
- }
-
- data.rollback = function() {//只用于list为对象的情况
- bindingExecutors.repeat.call(data, "clear")
- var elem = data.element
- var parentNode = elem.parentNode
- var content = avalon.parseHTML(data.template)
- var target = content.firstChild
- parentNode.replaceChild(content, elem)
- target = data.element = data.type === "repeat" ? target : parentNode
- data.group = null
- target.setAttribute(data.name, data.value)
- }
-
- data.handler = bindingExecutors.repeat
- data.$outer = {}
- var check0 = "$key",
- check1 = "$val"
- if (Array.isArray($repeat)) {
- check0 = "$first"
- check1 = "$last"
- }
- for (var i = 0, p; p = vmodels[i++]; ) {
- if (p.hasOwnProperty(check0) && p.hasOwnProperty(check1)) {
- data.$outer = p
- break
- }
- }
-
- if (!Array.isArray($repeat) && type !== "each") {
- var pool = withProxyPool[$repeat.$id]
- if (!pool) {
- withProxyCount++
- pool = withProxyPool[$repeat.$id] = {}
- for (var key in $repeat) {
- if ($repeat.hasOwnProperty(key) && key !== "hasOwnProperty") {
- (function(k, v) {
- pool[k] = createWithProxy(k, v, {})
- pool[k].$watch("$val", function(val) {
- $repeat[k] = val //#303
- })
- })(key, $repeat[key])
- }
- }
- }
- data.handler("append", $repeat, pool)
- } else {
- data.handler("add", 0, $repeat)
- }
- },
- "html": function(data, vmodels) {
- parseExprProxy(data.value, vmodels, data)
- },
- "on": function(data, vmodels) {
- var value = data.value
- var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10
- if (typeof bindingHandlers.on[eventType + "Hook"] === "function") {
- bindingHandlers.on[eventType + "Hook"](data)
- }
- if (value.indexOf("(") > 0 && value.indexOf(")") > -1) {
- var matched = (value.match(rdash) || ["", ""])[1].trim()
- if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理
- value = value.replace(rdash, "")
- }
- }
- parseExprProxy(value, vmodels, data)
- },
- "visible": function(data, vmodels) {
- var elem = avalon(data.element)
- var display = elem.css("display")
- if (display === "none") {
- var style = elem[0].style
- var has = /visibility/i.test(style.cssText)
- var visible = elem.css("visibility")
- style.display = ""
- style.visibility = "hidden"
- display = elem.css("display")
- if (display === "none") {
- display = parseDisplay(elem[0].nodeName)
- }
- style.visibility = has ? visible : ""
- }
- data.display = display
- parseExprProxy(data.value, vmodels, data)
- },
- "widget": function(data, vmodels) {
- var args = data.value.match(rword)
- var elem = data.element
- var widget = args[0]
- if (args[1] === "$" || !args[1]) {
- args[1] = widget + setTimeout("1")
- }
- data.value = args.join(",")
- var constructor = avalon.ui[widget]
- if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname"
- vmodels = elem.vmodels || vmodels
- var optName = args[2] || widget //尝试获得配置项的名字,没有则取widget的名字
- for (var i = 0, v; v = vmodels[i++]; ) {
- if (v.hasOwnProperty(optName) && typeof v[optName] === "object") {
- var nearestVM = v
- break
- }
- }
- if (nearestVM) {
- var vmOptions = nearestVM[optName]
- vmOptions = vmOptions.$model || vmOptions
- var id = vmOptions[widget + "Id"]
- if (typeof id === "string") {
- args[1] = id
- }
- }
- var widgetData = avalon.getWidgetData(elem, args[0]) //抽取data-tooltip-text、data-tooltip-attr属性,组成一个配置对象
- data[widget + "Id"] = args[1]
- data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData)
- elem.removeAttribute("ms-widget")
- var vmodel = constructor(elem, data, vmodels) || {} //防止组件不返回VM
- data.evaluator = noop
- elem.msData["ms-widget-id"] = vmodel.$id || ""
- if (vmodel.hasOwnProperty("$init")) {
- vmodel.$init()
- }
- if (vmodel.hasOwnProperty("$remove")) {
- function offTree() {
- if (!elem.msRetain && !root.contains(elem)) {
- vmodel.$remove()
- elem.msData = {}
- delete VMODELS[vmodel.$id]
- return false
- }
- }
- if (window.chrome) {
- elem.addEventListener("DOMNodeRemovedFromDocument", function() {
- setTimeout(offTree)
- })
- } else {
- avalon.tick(offTree)
- }
- }
- } else if (vmodels.length) { //如果该组件还没有加载,那么保存当前的vmodels
- elem.vmodels = vmodels
- }
- }
- }
- //============================ class preperty binding =======================
- "hover,active".replace(rword, function(method) {
- bindingHandlers[method] = bindingHandlers["class"]
- })
- "with,each".replace(rword, function(name) {
- bindingHandlers[name] = bindingHandlers.repeat
- })
- bindingHandlers["if"] = bindingHandlers.data = bindingHandlers.text = bindingHandlers.html
- //============================= string preperty binding =======================
- //与href绑定器 用法差不多的其他字符串属性的绑定器
- //建议不要直接在src属性上修改,这样会发出无效的请求,请使用ms-src
- "title,alt,src,value,css,include,href".replace(rword, function(name) {
- bindingHandlers[name] = bindingHandlers.attr
- })
- //============================= model binding =======================
-
- //将模型中的字段与input, textarea的value值关联在一起
- var duplexBinding = bindingHandlers.duplex
- //如果一个input标签添加了model绑定。那么它对应的字段将与元素的value连结在一起
- //字段变,value就变;value变,字段也跟着变。默认是绑定input事件,
- duplexBinding.INPUT = function(element, evaluator, data) {
- var type = element.type,
- bound = data.bound,
- $elem = avalon(element),
- firstTigger = false,
- composing = false
- function callback(value) {
- firstTigger = true
- data.changed.call(this, value)
- }
- function compositionStart() {
- composing = true
- }
- function compositionEnd() {
- composing = false
- }
- //当value变化时改变model的值
- function updateVModel() {
- if (composing)//处理中文输入法在minlengh下引发的BUG
- return
- var val = element.oldValue = element.value //防止递归调用形成死循环
- var typedVal = getTypedValue(data, val) //尝式转换为正确的格式
- if ($elem.data("duplex-observe") !== false) {
- evaluator(typedVal)
- callback.call(element, typedVal)
- if ($elem.data("duplex-focus")) {
- avalon.nextTick(function() {
- element.focus()
- })
- }
- }
- }
-
- //当model变化时,它就会改变value的值
- data.handler = function() {
- var val = evaluator()
- val = val == null ? "" : val + ""
- if (val !== element.value) {
- element.value = val
- }
- }
-
- if (type === "checkbox" && data.param === "radio") {
- type = "radio"
- }
- if (type === "radio") {
- var IE6 = !window.XMLHttpRequest
- updateVModel = function() {
- if ($elem.data("duplex-observe") !== false) {
- var val = element.value
- var typedValue = data.msType ? getTypedValue(data, val) : !element.oldValue
- evaluator(typedValue)
- callback.call(element, typedValue)
- }
- }
- data.handler = function() {
- var val = evaluator()
- var checked = data.msType ? val + "" === element.value : !!val
- element.oldValue = checked
- if (IE6) {
- setTimeout(function() {
- //IE8 checkbox, radio是使用defaultChecked控制选中状态,
- //并且要先设置defaultChecked后设置checked
- //并且必须设置延迟
- element.defaultChecked = checked
- element.checked = checked
- }, 100)
- } else {
- element.checked = checked
- }
- }
- bound(IE6 ? "mouseup" : "click", updateVModel)
- } else if (type === "checkbox") {
- updateVModel = function() {
- if ($elem.data("duplex-observe") !== false) {
- var method = element.checked ? "ensure" : "remove"
- var array = evaluator()
- if (!Array.isArray(array)) {
- log("ms-duplex应用于checkbox上要对应一个数组")
- array = [array]
- }
- var typedValue = getTypedValue(data, element.value)
- avalon.Array[method](array, typedValue)
- callback.call(element, array)
- }
- }
-
- data.handler = function() {
- var array = [].concat(evaluator()) //强制转换为数组
- element.checked = array.indexOf(getTypedValue(data, element.value)) >= 0
- }
- bound(W3C ? "change" : "click", updateVModel)
- } else {
- var event = element.attributes["data-duplex-event"] || element.attributes["data-event"] || {}
- event = event.value
- if (event === "change") {
- bound("change", updateVModel)
- } else {
- if (W3C) { //IE9+, W3C
- bound("input", updateVModel)
- bound("compositionstart", compositionStart)
- bound("compositionend", compositionEnd)
- if ("onselectionchange"in DOC) {//fix IE9 http://www.matts411.com/post/internet-explorer-9-oninput/
- function selectionchange(e) {
- if (e.type === "focus") {
- DOC.addEventListener("selectionchange", updateVModel, false);
- } else {
- DOC.removeEventListener("selectionchange", updateVModel, false);
- }
- }
- bound("focus", selectionchange)
- bound("blur", selectionchange)
- }
- } else {
- var events = ["keyup", "paste", "cut", "change"]
-
- function removeFn(e) {
- var key = e.keyCode
- // command modifiers arrows
- if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40))
- return
- if (e.type === "cut") {
- avalon.nextTick(updateVModel)
- } else {
- updateVModel()
- }
- }
-
- events.forEach(function(type) {
- element.attachEvent("on" + type, removeFn)
- })
-
- data.rollback = function() {
- events.forEach(function(type) {
- element.detachEvent("on" + type, removeFn)
- })
- }
- }
- }
- }
- element.oldValue = element.value
- launch(function() {
- if (avalon.contains(root, element)) {
- onTree.call(element)
- } else if (!element.msRetain) {
- return false
- }
- })
- registerSubscriber(data)
- var timer = setTimeout(function() {
- if (!firstTigger) {
- callback.call(element, element.value)
- }
- clearTimeout(timer)
- }, 31)
- }
- var TimerID, ribbon = [],
- launch = noop
- function W3CFire(el, name, detail) {
- var event = DOC.createEvent("Events")
- event.initEvent(name, true, true)
- if (detail) {
- event.detail = detail
- }
- el.dispatchEvent(event)
- }
-
- function onTree() { //disabled状态下改动不触发input事件
- if (!this.disabled && this.oldValue !== this.value) {
- if (W3C) {
- W3CFire(this, "input")
- } else {
- this.fireEvent("onchange")
- }
- }
- }
-
- function getTypedValue(data, val) {
- switch (data.msType) {
- case "boolean":
- return val === "true"
- case "number":
- return isFinite(val) || val === "" ? parseFloat(val) || 0 : val
- default:
- return val
- }
- }
-
- avalon.tick = function(fn) {
- if (ribbon.push(fn) === 1) {
- TimerID = setInterval(ticker, 60)
- }
- }
- function ticker() {
- for (var n = ribbon.length - 1; n >= 0; n--) {
- var el = ribbon[n]
- if (el() === false) {
- ribbon.splice(n, 1)
- }
- }
- if (!ribbon.length) {
- clearInterval(TimerID)
- }
- }
-
- function newSetter(newValue) {
- oldSetter.call(this, newValue)
- if (newValue !== this.oldValue) {
- W3CFire(this, "input")
- }
- }
- try {
- var inputProto = HTMLInputElement.prototype
- Object.getOwnPropertyNames(inputProto)//故意引发IE6-8等浏览器报错
- var oldSetter = Object.getOwnPropertyDescriptor(inputProto, "value").set //屏蔽chrome, safari,opera
- Object.defineProperty(inputProto, "value", {
- set: newSetter
- })
- } catch (e) {
- launch = avalon.tick
- }
-
- duplexBinding.SELECT = function(element, evaluator, data) {
- var $elem = avalon(element)
- function updateVModel() {
- if ($elem.data("duplex-observe") !== false) {
- var val = $elem.val() //字符串或字符串数组
- if (Array.isArray(val)) {
- val = val.map(function(v) {
- return getTypedValue(data, v)
- })
- } else {
- val = getTypedValue(data, val)
- }
- if (val + "" !== element.oldValue) {
- evaluator(val)
- }
- data.changed.call(element, val)
- }
- }
- data.handler = function() {
- var val = evaluator()
- val = val && val.$model || val
- //必须变成字符串后才能比较
- if (Array.isArray(val)) {
- if (!element.multiple) {
- log("ms-duplex在上要求对应一个数组")
- }
- } else {
- if (element.multiple) {
- log("ms-duplex在不能对应一个数组")
- }
- }
- val = Array.isArray(val) ? val.map(String) : val + ""
- if (val + "" !== element.oldValue) {
- $elem.val(val)
- element.oldValue = val + ""
- }
- }
- data.bound("change", updateVModel)
- var innerHTML = NaN
- var id = setInterval(function() {
- var currHTML = element.innerHTML
- if (currHTML === innerHTML) {
- clearInterval(id)
- //先等到select里的option元素被扫描后,才根据model设置selected属性
- registerSubscriber(data)
- data.changed.call(element, evaluator())
- } else {
- innerHTML = currHTML
- }
- }, 20)
- }
- duplexBinding.TEXTAREA = duplexBinding.INPUT
- //============================= event binding =======================
-
- function fixEvent(event) {
- var ret = {}
- for (var i in event) {
- ret[i] = event[i]
- }
- var target = ret.target = event.srcElement
- if (event.type.indexOf("key") === 0) {
- ret.which = event.charCode != null ? event.charCode : event.keyCode
- } else if (/mouse|click/.test(event.type)) {
- var doc = target.ownerDocument || DOC
- var box = doc.compatMode === "BackCompat" ? doc.body : doc.documentElement
- ret.pageX = event.clientX + (box.scrollLeft >> 0) - (box.clientLeft >> 0)
- ret.pageY = event.clientY + (box.scrollTop >> 0) - (box.clientTop >> 0)
- ret.wheelDeltaY = ret.wheelDelta
- ret.wheelDeltaX = 0
- }
- ret.timeStamp = new Date - 0
- ret.originalEvent = event
- ret.preventDefault = function() { //阻止默认行为
- event.returnValue = false
- }
- ret.stopPropagation = function() { //阻止事件在DOM树中的传播
- event.cancelBubble = true
- }
- return ret
- }
-
- var eventHooks = avalon.eventHooks
- //针对firefox, chrome修正mouseenter, mouseleave
- if (!("onmouseenter" in root)) {
- avalon.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
- }, function(origType, fixType) {
- eventHooks[origType] = {
- type: fixType,
- deel: function(elem, fn) {
- return function(e) {
- var t = e.relatedTarget
- if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) {
- delete e.type
- e.type = origType
- return fn.call(elem, e)
- }
- }
- }
- }
- })
- }
- //针对IE9+, w3c修正animationend
- avalon.each({
- AnimationEvent: "animationend",
- WebKitAnimationEvent: "webkitAnimationEnd"
- }, function(construct, fixType) {
- if (window[construct] && !eventHooks.animationend) {
- eventHooks.animationend = {
- type: fixType
- }
- }
- })
- //针对IE6-8修正input
- if (!("oninput" in document.createElement("input"))) {
- eventHooks.input = {
- type: "propertychange",
- deel: function(elem, fn) {
- return function(e) {
- if (e.propertyName === "value") {
- e.type = "input"
- return fn.call(elem, e)
- }
- }
- }
- }
- }
- if (document.onmousewheel === void 0) {
- /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120
- firefox DOMMouseScroll detail 下3 上-3
- firefox wheel detlaY 下3 上-3
- IE9-11 wheel deltaY 下40 上-40
- chrome wheel deltaY 下100 上-100 */
- var fixWheelType = document.onwheel !== void 0 ? "wheel" : "DOMMouseScroll"
- var fixWheelDelta = fixWheelType === "wheel" ? "deltaY" : "detail"
- eventHooks.mousewheel = {
- type: fixWheelType,
- deel: function(elem, fn) {
- return function(e) {
- e.wheelDeltaY = e.wheelDelta = e[fixWheelDelta] > 0 ? -120 : 120
- e.wheelDeltaX = 0
- if (Object.defineProperty) {
- Object.defineProperty(e, "type", {
- value: "mousewheel"
- })
- }
- fn.call(elem, e)
- }
- }
- }
- }
-
- /*********************************************************************
- * 监控数组(与ms-each, ms-repeat配合使用) *
- **********************************************************************/
-
- function Collection(model) {
- var array = []
- array.$id = generateID() //它在父VM中的名字
- array.$model = model //数据模型
- array.$events = {}
- array.$events[subscribers] = []
- //在监控数组中,它没有用处,只是基于VM的规范全部统一添加
- array._ = modelFactory({
- size: model.length
- })
- array._.$watch("size", function(a, b) {
- array.$fire("length", a, b)
- })
- for (var i in EventManager) {
- array[i] = EventManager[i]
- }
- avalon.mix(array, CollectionPrototype)
- return array
- }
-
- var _splice = ap.splice
- var CollectionPrototype = {
- _splice: _splice,
- _fire: function(method, a, b) {
- notifySubscribers(this.$events[subscribers], method, a, b)
- },
- _add: function(arr, pos) { //在第pos个位置上,添加一组元素
- var oldLength = this.length
- pos = typeof pos === "number" ? pos : oldLength
- var added = []
- for (var i = 0, n = arr.length; i < n; i++) {
- added[i] = convert(arr[i], this.$model[i])
- }
- _splice.apply(this, [pos, 0].concat(added))
- this._fire("add", pos, added)
- if (!this._stopFireLength) {
- return this._.size = this.length
- }
- },
- _del: function(pos, n) { //在第pos个位置上,删除N个元素
- var ret = this._splice(pos, n)
- if (ret.length) {
- this._fire("del", pos, n)
- if (!this._stopFireLength) {
- this._.size = this.length
- }
- }
- return ret
- },
- push: function() {
- ap.push.apply(this.$model, arguments)
- var n = this._add(arguments)
- this._fire("index", n > 2 ? n - 2 : 0)
- return n
- },
- pushArray: function(array) {
- return this.push.apply(this, array)
- },
- unshift: function() {
- ap.unshift.apply(this.$model, arguments)
- this._add(arguments, 0)
- this._fire("index", arguments.length)
- return this.$model.length //IE67的unshift不会返回长度
- },
- shift: function() {
- var el = this.$model.shift()
- this._del(0, 1)
- this._fire("index", 0)
- return el //返回被移除的元素
- },
- pop: function() {
- var el = this.$model.pop()
- this._del(this.length - 1, 1)
- return el //返回被移除的元素
- },
- splice: function(a, b) {
- // 必须存在第一个参数,需要大于-1, 为添加或删除元素的基点
- a = _number(a, this.length)
- var removed = _splice.apply(this.$model, arguments),
- ret = [], change
- this._stopFireLength = true //确保在这个方法中 , $watch("length",fn)只触发一次
- if (removed.length) {
- ret = this._del(a, removed.length)
- change = true
- }
- if (arguments.length > 2) {
- this._add(aslice.call(arguments, 2), a)
- change = true
- }
- this._stopFireLength = false
- this._.size = this.length
- if (change) {
- this._fire("index", 0)
- }
- return ret //返回被移除的元素
- },
- contains: function(el) { //判定是否包含
- return this.indexOf(el) !== -1
- },
- size: function() { //取得数组长度,这个函数可以同步视图,length不能
- return this._.size
- },
- remove: function(el) { //移除第一个等于给定值的元素
- return this.removeAt(this.indexOf(el))
- },
- removeAt: function(index) { //移除指定索引上的元素
- return index >= 0 ? this.splice(index, 1) : []
- },
- clear: function() {
- this.$model.length = this.length = this._.size = 0 //清空数组
- this._fire("clear", 0)
- return this
- },
- removeAll: function(all) { //移除N个元素
- if (Array.isArray(all)) {
- all.forEach(function(el) {
- this.remove(el)
- }, this)
- } else if (typeof all === "function") {
- for (var i = this.length - 1; i >= 0; i--) {
- var el = this[i]
- if (all(el, i)) {
- this.splice(i, 1)
- }
- }
- } else {
- this.clear()
- }
- },
- ensure: function(el) {
- if (!this.contains(el)) { //只有不存在才push
- this.push(el)
- }
- return this
- },
- set: function(index, val) {
- if (index >= 0) {
- var valueType = avalon.type(val)
- if (val && val.$model) {
- val = val.$model
- }
- var target = this[index]
- if (valueType === "object") {
- for (var i in val) {
- if (target.hasOwnProperty(i)) {
- target[i] = val[i]
- }
- }
- } else if (valueType === "array") {
- target.clear().push.apply(target, val)
- } else if (target !== val) {
- this[index] = val
- this.$model[index] = val
- this._fire("set", index, val)
- }
- }
- return this
- }
- }
- "sort,reverse".replace(rword, function(method) {
- CollectionPrototype[method] = function() {
- var aaa = this.$model,
- bbb = aaa.slice(0),
- sorted = false
- ap[method].apply(aaa, arguments) //先移动model
- for (var i = 0, n = bbb.length; i < n; i++) {
- var a = aaa[i],
- b = bbb[i]
- if (!isEqual(a, b)) {
- sorted = true
- var index = bbb.indexOf(a, i)
- var remove = this._splice(index, 1)[0]
- var remove2 = bbb.splice(index, 1)[0]
- this._splice(i, 0, remove)
- bbb.splice(i, 0, remove2)
- this._fire("move", index, i)
- }
- }
- bbb = void 0
- if (sorted) {
- this._fire("index", 0)
- }
- return this
- }
- })
-
- function convert(val, $model) {
- if (rcomplexType.test(avalon.type(val))) {
- val = val.$id ? val : modelFactory(val, 0, $model)
- }
- return val
- }
-
-
- bindingExecutors.repeat = function(method, pos, el) {
- if (method) {
- var data = this
- var parent = data.element.parentNode
- var proxies = data.proxies
- var transation = hyperspace.cloneNode(false)
- if (method === "del" || method === "move") {
- var locatedNode = locateFragment(data, pos)
- }
- var group = data.group
- switch (method) {
- case "add": //在pos位置后添加el数组(pos为数字,el为数组)
- var arr = el
- var last = data.$repeat.length - 1
- var fragments = []
- for (var i = 0, n = arr.length; i < n; i++) {
- var ii = i + pos
- var proxy = getEachProxy(ii, arr[i], data, last)
- proxies.splice(ii, 0, proxy)
- shimController(data, transation, proxy, fragments)
- }
-
- locatedNode = locateFragment(data, pos)
- parent.insertBefore(transation, locatedNode)
-
- for (var i = 0, fragment; fragment = fragments[i++]; ) {
- scanNodeArray(fragment.nodes, fragment.vmodels)
- fragment.nodes = fragment.vmodels = null
- }
- calculateFragmentGroup(data)
- break
- case "del": //将pos后的el个元素删掉(pos, el都是数字)
- var removed = proxies.splice(pos, el)
- var transation = removeFragment(locatedNode, group, el)
- avalon.clearHTML(transation)
- recycleEachProxies(removed)
- break
- case "index": //将proxies中的第pos个起的所有元素重新索引(pos为数字,el用作循环变量)
- var last = proxies.length - 1
- for (; el = proxies[pos]; pos++) {
- el.$index = pos
- el.$first = pos === 0
- el.$last = pos === last
- }
- break
- case "clear":
- var size = "proxySize" in data ? data.proxySize : proxies.length
- if (size) {
- var n = size * group, k = 0
- while (true) {
- var nextNode = data.element.nextSibling
- if (nextNode && k < n) {
- parent.removeChild(nextNode)
- k++
- } else {
- break
- }
- }
- recycleEachProxies(proxies)
- }
- break
- case "move": //将proxies中的第pos个元素移动el位置上(pos, el都是数字)
- var t = proxies.splice(pos, 1)[0]
- if (t) {
- proxies.splice(el, 0, t)
- transation = removeFragment(locatedNode, group)
- locatedNode = locateFragment(data, el)
- parent.insertBefore(transation, locatedNode)
- }
- break
- case "set": //将proxies中的第pos个元素的VM设置为el(pos为数字,el任意)
- var proxy = proxies[pos]
- if (proxy) {
- proxy[proxy.$itemName] = el
- }
- break
- case "append": //将pos的键值对从el中取出(pos为一个普通对象,el为预先生成好的代理VM对象池)
- var pool = el
- var keys = []
- var fragments = []
- for (var key in pos) { //得到所有键名
- if (pos.hasOwnProperty(key) && key !== "hasOwnProperty") {
- keys.push(key)
- }
- }
- if (data.sortedCallback) { //如果有回调,则让它们排序
- var keys2 = data.sortedCallback.call(parent, keys)
- if (keys2 && Array.isArray(keys2) && keys2.length) {
- keys = keys2
- }
- }
- for (var i = 0, key; key = keys[i++]; ) {
- if (key !== "hasOwnProperty") {
- shimController(data, transation, pool[key], fragments)
- }
- }
- data.proxySize = keys.length
- parent.insertBefore(transation, data.element.nextSibling)
- for (var i = 0, fragment; fragment = fragments[i++]; ) {
- scanNodeArray(fragment.nodes, fragment.vmodels)
- fragment.nodes = fragment.vmodels = null
- }
- calculateFragmentGroup(data)
- break
- }
- var callback = data.renderedCallback || noop, args = arguments
- checkScan(parent, function() {
- callback.apply(parent, args)
- if (parent.oldValue && parent.tagName === "SELECT" && method === "index") {//fix #503
- avalon(parent).val(parent.oldValue.split(","))
- }
- })
- }
- }
-
- //============ each/repeat/with binding 用到的辅助函数与对象 ======================
- function shimController(data, transation, proxy, fragments) {
- var dom = avalon.parseHTML(data.template)
- var nodes = avalon.slice(dom.childNodes)
- transation.appendChild(dom)
- proxy.$outer = data.$outer
- var fragment = {
- nodes: nodes,
- vmodels: [proxy].concat(data.vmodels)
- }
- fragments.push(fragment)
- }
- // 取得用于定位的节点。比如group = 3, 结构为
- //
- // 当pos为0时,返回 br#first
- // 当pos为1时,返回 br#second
- // 当pos为2时,返回 null
- function locateFragment(data, pos) {
- if (data.type == "repeat") {//ms-repeat,group为1
- var node = data.element.nextSibling
- for (var i = 0, n = pos; i < n; i++) {
- if (node) {
- node = node.nextSibling
- } else {
- break
- }
- }
- } else {
- var nodes = avalon.slice(data.element.parentNode.childNodes, 1)
- var group = data.group || nodes.length / data.proxies.length
- node = nodes[group * pos]
- }
- return node || null
- }
-
- function removeFragment(node, group, pos) {
- var n = group * (pos || 1)
- var nodes = [node], i = 1
- var view = hyperspace
- while (i < n) {
- node = node.nextSibling
- if (node) {
- nodes[i++] = node
- }
- }
- for (var i = 0; node = nodes[i++]; ) {
- view.appendChild(node)
- }
- return view
- }
- function calculateFragmentGroup(data) {
- if (!isFinite(data.group)) {
- var nodes = avalon.slice(data.element.parentNode.childNodes, 1)
- var n = "proxySize" in data ? data.proxySize : data.proxies.length
- data.group = nodes.length / n
- }
- }
- // 为ms-each, ms-repeat创建一个代理对象,通过它们能使用一些额外的属性与功能($index,$first,$last,$remove,$key,$val,$outer)
- var watchEachOne = oneObject("$index,$first,$last")
-
- function createWithProxy(key, val, $outer) {
- var proxy = modelFactory({
- $key: key,
- $outer: $outer,
- $val: val
- }, {
- $val: 1,
- $key: 1
- })
- proxy.$id = ("$proxy$with" + Math.random()).replace(/0\./, "")
- return proxy
- }
- var eachProxyPool = []
- function getEachProxy(index, item, data, last) {
- var param = data.param || "el", proxy
- var source = {
- $remove: function() {
- return data.$repeat.removeAt(proxy.$index)
- },
- $itemName: param,
- $index: index,
- $outer: data.$outer,
- $first: index === 0,
- $last: index === last
- }
- source[param] = item
- for (var i = 0, n = eachProxyPool.length; i < n; i++) {
- var proxy = eachProxyPool[i]
- if (proxy.hasOwnProperty(param)) {
- for (var k in source) {
- proxy[k] = source[k]
- }
- eachProxyPool.splice(i, 1)
- return proxy
- }
- }
- if (rcomplexType.test(avalon.type(item))) {
- source.$skipArray = [param]
- }
- proxy = modelFactory(source, watchEachOne)
- proxy.$watch(param, function(val) {
- data.$repeat.set(proxy.$index, val)
- })
- proxy.$id = ("$proxy$" + data.type + Math.random()).replace(/0\./, "")
- return proxy
- }
- function recycleEachProxies(array) {
- for (var i = 0, el; el = array[i++]; ) {
- recycleEachProxy(el)
- }
- array.length = 0
- }
-
- function recycleEachProxy(proxy) {
- for (var i in proxy.$events) {
- if (Array.isArray(proxy.$events[i])) {
- proxy.$events[i].length = 0
- }
- }
- if (eachProxyPool.unshift(proxy) > kernel.maxRepeatSize) {
- eachProxyPool.pop()
- }
- }
- /*********************************************************************
- * 自带过滤器 *
- **********************************************************************/
- var rscripts = /
diff --git a/examples/css3.html b/examples/css3.html
index 2113a0ff0..d82823860 100644
--- a/examples/css3.html
+++ b/examples/css3.html
@@ -37,6 +37,8 @@ 在旧式IE下,如果父元素是定位元素,但没有设置它的top, le
+
+