diff --git a/static/src/js/lib/avalon/avalon.js b/static/src/js/lib/avalon/avalon.js index bb809d5..48c2021 100644 --- a/static/src/js/lib/avalon/avalon.js +++ b/static/src/js/lib/avalon/avalon.js @@ -3,9 +3,9 @@ http://www.cnblogs.com/rubylouvre/ https://github.com/RubyLouvre http://weibo.com/jslouvre/ - + Released under the MIT license - avalon.shim.js 1.5.4 built in 2015.10.15 + avalon.shim.js 1.5.4 built in 2015.10.18 support IE6+ and other browsers ==================================================*/ (function(global, factory) { @@ -954,7 +954,7 @@ function $watch(expr, binding) { } binding.wildcard = /\*/.test(expr) } - + if (!binding.update) { if (/\w\.*\B/.test(expr)) { binding.getter = noop @@ -1489,7 +1489,7 @@ if (!canHideOwn) { //添加普通属性,因为VBScript对象不能像JS那样随意增删属性,必须在这里预先定义好 var uniq = {} - //添加访问器属性 + //添加访问器属性 for (name in accessors) { uniq[name] = true buffer.push( @@ -1593,7 +1593,7 @@ var newProto = { if (all.indexOf(this[i]) !== -1) { _splice.call(this.$track, i, 1) _splice.call(this, i, 1) - + } } } else if (typeof all === "function") { @@ -1602,7 +1602,7 @@ var newProto = { if (all(el, i)) { _splice.call(this.$track, i, 1) _splice.call(this, i, 1) - + } } } else { @@ -2517,7 +2517,7 @@ function showHidden(node, array) { var node = this[0] if (arguments.length === 0) { if (node.setTimeout) { //取得窗口尺寸 - return node["inner" + name] || + return node["inner" + name] || node.document.documentElement[clientProp] || node.document.body[clientProp] //IE6下前两个分别为undefined,0 } @@ -2972,7 +2972,7 @@ function executeBindings(bindings, vmodels) { for (var i = 0, binding; binding = bindings[i++]; ) { binding.vmodels = vmodels directives[binding.type].init(binding) - + avalon.injectBinding(binding) if (binding.getter && binding.element.nodeType === 1) { //移除数据绑定,防止被二次解析 //chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99 @@ -3169,9 +3169,6 @@ function scanNodeArray(nodes, vmodels) { switch (node.nodeType) { case 1: var elem = node, fn - - scanTag(node, vmodels) //扫描元素节点 - if (!elem.msResolved && elem.parentNode && elem.parentNode.nodeType === 1) { var library = isWidget(elem) if (library) { @@ -3190,6 +3187,7 @@ function scanNodeArray(nodes, vmodels) { } } } + scanTag(node, vmodels) //扫描元素节点 if (node.msHasEvent) { avalon.fireDom(node, "datasetchanged", { bubble: node.msHasEvent @@ -3232,7 +3230,7 @@ function scanTag(elem, vmodels, node) { avalon(elem).removeClass(name) createSignalTower(elem, newVmodel) } - + scanAttr(elem, vmodels) //扫描特性节点 } @@ -3424,6 +3422,7 @@ avalon.component = function (name, opts) { elem.msResolved = 1 vmodel.$init(vmodel, elem) global.$init(vmodel, elem) + console.log("init") var nodes = elem.childNodes //收集插入点 var slots = {}, snode @@ -3483,11 +3482,11 @@ avalon.component = function (name, opts) { e.stopPropagation() } } - + console.log("dependencies "+dependencies) if (dependencies === 0) { var id1 = setTimeout(function () { clearTimeout(id1) - + vmodel.$ready(vmodel, elem, host.vmodels) global.$ready(vmodel, elem, host.vmodels) }, children ? Math.max(children * 17, 100) : 17) @@ -3510,9 +3509,10 @@ avalon.component = function (name, opts) { } }) - scanTag(elem, [vmodel].concat(host.vmodels)) + scanTag(elem, [vmodel].concat(host.vmodels)) avalon.vmodels[vmodel.$id] = vmodel + avalon.log("添加组件VM: "+vmodel.$id) if (!elem.childNodes.length) { avalon.fireDom(elem, "datasetchanged", {library: library, vm: vmodel, childReady: -1}) } else { @@ -3585,7 +3585,7 @@ function isWidget(el) { //如果为自定义标签,返回UI库的名字 if(el.scopeName && el.scopeName !== "HTML" ){ return el.scopeName } - var fullName = el.nodeName.toLowerCase() + var fullName = el.nodeName.toLowerCase() var index = fullName.indexOf(":") if (index > 0) { return fullName.slice(0, index) @@ -3794,7 +3794,7 @@ avalon.directive("data", { //双工绑定 var rduplexType = /^(?:checkbox|radio)$/ var rduplexParam = /^(?:radio|checked)$/ -var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio)$/ +var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/ var duplexBinding = avalon.directive("duplex", { priority: 2000, init: function (binding, hasCast) { @@ -3949,15 +3949,26 @@ var duplexBinding = avalon.directive("duplex", { } } }) + binding.bound("datasetchanged", function (e) { + if (e.bubble === "selectDuplex") { + var value = binding._value + var curValue = Array.isArray(value) ? value.map(String) : value + "" + avalon(elem).val(curValue) + elem.oldValue = curValue + "" + binding.changed.call(elem, curValue) + } + }) break } - binding.bound("focus", function() { - elem.msFocus = true - }) - binding.bound("blur", function() { - elem.msFocus = false - }) if (binding.xtype === "input" && !rnoduplexInput.test(elem.type)) { + if (elem.type !== "hidden") { + binding.bound("focus", function () { + elem.msFocus = true + }) + binding.bound("blur", function () { + elem.msFocus = false + }) + } elem.avalonSetter = updateVModel //#765 watchValueInTimer(function () { if (elem.contains(elem)) { @@ -3987,7 +3998,18 @@ var duplexBinding = avalon.directive("duplex", { case "change": curValue = this.pipe(value, this, "set") //fix #673 if (curValue !== this.oldValue) { + var fixCaret = false + if (elem.msFocus) { + var pos = getCaret(elem) + if (pos.start === pos.end) { + pos = pos.start + fixCaret = true + } + } elem.value = this.oldValue = curValue + if (fixCaret) { + setCaret(element, pos, pos) + } } break case "radio": @@ -4012,18 +4034,14 @@ var duplexBinding = avalon.directive("duplex", { case "select": //必须变成字符串后才能比较 binding._value = value - elem.msHasEvent = "selectDuplex" - //必须等到其孩子准备好才触发 - avalon.bind(elem, "datasetchanged", function (e) { - if (e.bubble === "selectDuplex") { - var value = binding._value - var curValue = Array.isArray(value) ? value.map(String) : value + "" - avalon(elem).val(curValue) - elem.oldValue = curValue + "" - binding.changed.call(elem, curValue) - } - }) - + if(!elem.msHasEvent){ + elem.msHasEvent = "selectDuplex" + //必须等到其孩子准备好才触发 + }else{ + avalon.fireDom(elem, "datasetchanged", { + bubble: elem.msHasEvent + }) + } break } if (binding.xtype !== "select") { @@ -4121,7 +4139,7 @@ new function () { // jshint ignore:line var bproto = HTMLTextAreaElement.prototype function newSetter(value) { // jshint ignore:line setters[this.tagName].call(this, value) - if (!this.msFocus && this.avalonSetter && this.oldValue !== value) { + if (!this.msFocus && this.avalonSetter && this.oldValue !== value) { this.avalonSetter() } } @@ -4143,6 +4161,34 @@ new function () { // jshint ignore:line watchValueInTimer = avalon.tick } } // jshint ignore:line +function getCaret(ctrl, start, end) { + if (ctrl.setSelectionRange) { + start = ctrl.selectionStart + end = ctrl.selectionEnd + } else if (document.selection && document.selection.createRange) { + var range = document.selection.createRange() + start = 0 - range.duplicate().moveStart('character', -100000) + end = start + range.text.length + } + return { + start: start, + end: end + } +} +function setCaret(ctrl, begin, end) { + if (!ctrl.value || ctrl.readOnly) + return + if (ctrl.setSelectionRange) { + ctrl.selectionStart = begin + ctrl.selectionEnd = end + } else { + var range = ctrl.createTextRange() + range.collapse(true); + range.moveStart("character", begin) + range.moveEnd("character", end - begin) + range.select() + } +} avalon.directive("effect", { priority: 5, @@ -4326,7 +4372,7 @@ function upperFirstChar(str) { } var effectBuffer = new Buffer() function Effect() { -}// 动画实例,做成类的形式,是为了共用所有原型方法 +}// 动画实例,做成类的形式,是为了共用所有原型方法 Effect.prototype = { contrustor: Effect, @@ -4349,7 +4395,7 @@ Effect.prototype = { callEffectHook(me, "abort" + upperFirstChar(oppositeName)) callEffectHook(me, "before" + upperFirstChar(name)) if (!isLeave) - before(el) //  这里可能做插入DOM树的操作,因此必须在修改类名前执行 + before(el) // 这里可能做插入DOM树的操作,因此必须在修改类名前执行 var cssCallback = function (cancel) { el.removeEventListener(me.cssEvent, me.cssCallback) if (isLeave) { @@ -4576,7 +4622,7 @@ avalon.directive("if", { elem.required = false elem.setAttribute("_required", "true") } - try {// 如果不支持querySelectorAll或:required,可以直接无视 + try {// 如果不支持querySelectorAll或:required,可以直接无视 avalon.each(elem.querySelectorAll(":required"), function (el) { elem.required = false el.setAttribute("_required", "true") @@ -4679,7 +4725,7 @@ avalon.directive("include", { leaveEl.className = effectClass target.insertBefore(leaveEl, binding.start) // 插入到start之前,防止被错误的移动 } - + // cache or animate,移动节点 (templateCache || {})[lastID] = leaveEl var fragOnDom = binding.recoverNodes() // 恢复动画中的节点 @@ -4733,7 +4779,7 @@ avalon.directive("include", { return nodesToFrag(nodes) } } else { - before = function () {// 新添加元素的动画  + before = function () {// 新添加元素的动画 target.insertBefore(fragment, binding.end) scanNodeArray(nodes, vmodels) } @@ -4827,7 +4873,7 @@ var onDir = avalon.directive("on", { var fn = binding.getter || noop return fn.apply(this, binding.args.concat(e)) } - + var eventType = binding.param.replace(/-\d+$/, "") // ms-on-mousemove-10 if (eventType === "scan") { callback.call(elem, { @@ -4860,7 +4906,7 @@ avalon.directive("repeat", { effectBinding(elem, binding) binding.param = binding.param || "el" binding.sortedCallback = getBindingCallback(elem, "data-with-sorted", binding.vmodels) - // binding.renderedCallback = + // binding.renderedCallback = var rendered = getBindingCallback(elem, "data-" + type + "-rendered", binding.vmodels) var signature = generateID(type) @@ -4965,7 +5011,7 @@ avalon.directive("repeat", { } //重写proxy - if (this.enterCount === 1) {// 防止多次进入,导致位置不对 + if (this.enterCount === 1) {// 防止多次进入,导致位置不对 proxy.$active = false proxy.$oldIndex = proxy.$index proxy.$active = true @@ -4978,7 +5024,7 @@ avalon.directive("repeat", { proxy.$last = i === length - 1 // proxy[param] = value[i] } else { - proxy.$val = toJson(value[keyOrId]) // 这里是处理vm.object = newObject的情况 + proxy.$val = toJson(value[keyOrId]) // 这里是处理vm.object = newObject的情况 } proxies.push(proxy) } @@ -5029,7 +5075,7 @@ avalon.directive("repeat", { } else if (proxy.$index !== proxy.$oldIndex) { (function (proxy2, preElement) { staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () { - var curNode = removeItem(proxy2.$anchor)// 如果位置被挪动了 + var curNode = removeItem(proxy2.$anchor)// 如果位置被挪动了 var inserted = avalon.slice(curNode.childNodes) parent.insertBefore(curNode, preElement.nextSibling) animateRepeat(inserted, 1, binding) @@ -5410,7 +5456,7 @@ var filters = avalon.filters = { truncate: function(str, length, truncation) { //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串 length = length || 30 - truncation = typeof truncation === "string" ? truncation : "..." + truncation = typeof truncation === "string" ? truncation : "..." return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str) }, $filter: function(val) { @@ -5426,7 +5472,7 @@ var filters = avalon.filters = { }, camelize: camelize, //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet - // chrome + // chrome // chrome // IE67chrome // IE67chrome @@ -5447,7 +5493,7 @@ var filters = avalon.filters = { }) }, escape: function(str) { - //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 < + //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 < return String(str). replace(/&/g, '&'). replace(rsurrogate, function(value) { @@ -5489,7 +5535,7 @@ var filters = avalon.filters = { 'a': am/pm marker 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200) format string can also be one of the following predefined localizable formats: - + 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm) 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm) 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010)