Skip to content

Commit

Permalink
添加ms-repeat绑定
Browse files Browse the repository at this point in the history
  • Loading branch information
qincheng committed Nov 16, 2013
1 parent f280468 commit 7450715
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 43 deletions.
79 changes: 61 additions & 18 deletions avalon.js
Original file line number Diff line number Diff line change
Expand Up @@ -2119,7 +2119,10 @@
},
//https://github.com/RubyLouvre/avalon/issues/27
"with": function(data, vmodels) {
bindingHandlers.each(data, vmodels, true)
bindingHandlers.each(data, vmodels, "with")
},
"repeat": function(data, vmodels) {
bindingHandlers.each(data, vmodels, "repeat")
},
"widget": function(data, vmodels) {
var args = data.value.match(rword)
Expand Down Expand Up @@ -2613,7 +2616,7 @@
},
clear: function() {
this.$model.length = this.length = this._.length = 0 //清空数组
notifySubscribers(this, "clear")
notifySubscribers(this, "clear", 0)
return this
},
removeAll: function(all) { //移除N个元素
Expand Down Expand Up @@ -2703,18 +2706,30 @@
}

var withMapper = {}
bindingHandlers["each"] = function(data, vmodels) {
bindingHandlers["each"] = function(data, vmodels, name) {
var elem = data.element,
list, updateView
var array = parseExpr(data.value, vmodels, data)

function getter() {
return array[0].apply(0, array[1])
}

data.parent = elem
var view = documentFragment.cloneNode(false)
while (elem.firstChild) {
view.appendChild(elem.firstChild)
if (name === "repeat") {
var startRepeat = document.createComment("@startRepeat")
var endRepeat = document.createComment("@endRepeat")
data.element = data.parent = elem.parentNode
data.startRepeat = startRepeat
data.endRepeat = endRepeat
elem.removeAttribute(data.node.name)
data.parent.replaceChild(endRepeat, elem)
data.parent.insertBefore(startRepeat, endRepeat)
view.appendChild(elem.cloneNode(true))
} else {
while (elem.firstChild) {
view.appendChild(elem.firstChild)
}
}
data.template = view
data.vmodels = vmodels
Expand All @@ -2730,7 +2745,6 @@
// 然后通过updateView这个虚拟代理来内部调用它
if (Array.isArray(list)) {
data.mapper = []
data.state = data.state || {}
updateView = function(method, pos, el) {
eachIterator(method, pos, el, data, getter)
}
Expand All @@ -2742,18 +2756,26 @@
updateView.data = data
updateView.vmodels = vmodels
updateView.rollback = function() {
avalon.clearChild(elem).appendChild(view)
if (name == "repeat") {
updateView("clear", 0)
data.element = view.firstChild
data.parent.replaceChild(data.element, data.startRepeat)
data.parent.removeChild(data.endRepeat)
} else {
avalon.clearChild(elem).appendChild(view)
}

}
list[subscribers] && list[subscribers].push(updateView)
updateView("add", list, 0)
}

var deleteRange = document.createRange && document.createRange()
function eachIterator(method, pos, el, data, getter) {
var group = data.group
var parent = data.element
var parent = data.parent
var mapper = data.mapper
if (method == "del" || method == "move") {
var locatedNode = getLocatedNode(parent, group, pos)
if (method == "del" || method == "move" || (!deleteRange && method == "clear")) {
var locatedNode = getLocatedNode(parent, data, pos)
}
switch (method) {
case "add":
Expand Down Expand Up @@ -2783,7 +2805,7 @@
transation.appendChild(tview)
}
//得到插入位置 IE6-10要求insertBefore的第2个参数为节点或null,不能为undefined
locatedNode = getLocatedNode(parent, group, pos)
locatedNode = getLocatedNode(parent, data, pos)
parent.insertBefore(transation, locatedNode)
break
case "del":
Expand All @@ -2796,15 +2818,25 @@
}
break
case "clear":
if (data.startRepeat) {
if (deleteRange) {
deleteRange.setStartAfter(data.startRepeat);
deleteRange.setEndBefore(data.endRepeat);
deleteRange.deleteContents();
} else {
removeView(locatedNode, group, mapper.length)
}
} else {
avalon.clearChild(parent)
}
mapper.length = 0
avalon.clearChild(parent)
break
case "move":
var t = mapper.splice(pos, 1)[0]
if (t) {
mapper.splice(el, 0, t)
var moveNode = removeView(locatedNode, group)
locatedNode = getLocatedNode(parent, group, el)
locatedNode = getLocatedNode(parent, data, el)
parent.insertBefore(moveNode, locatedNode)
}
break
Expand All @@ -2820,7 +2852,7 @@

function withIterator(method, object, group, data, getter) {
group = data.group
var parent = data.element
var parent = data.parent
var transation = documentFragment.cloneNode(false)
switch (method) {
case "add":
Expand Down Expand Up @@ -2861,8 +2893,19 @@
// 这时该元素的孩子将分为N等分,每等份的第一个节点就是这个用于定位的节点,
// 方便我们根据它算出整个等分的节点们,然后整体移除或移动它们。

function getLocatedNode(parent, group, pos) {
return parent.childNodes[group * pos] || null
function getLocatedNode(parent, data, pos) {
if (data.startRepeat) {
var ret = data.startRepeat, end = data.endRepeat;
pos += 1
for (var i = 0; i < pos; i++) {
ret = ret.nextSibling
if (ret == end)
return end
}
return ret
} else {
return parent.childNodes[data.group * pos] || null
}
}

function removeView(node, group, n) {
Expand Down
80 changes: 55 additions & 25 deletions avalon.mobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,10 @@
},
//https://github.com/RubyLouvre/avalon/issues/27
"with": function(data, vmodels) {
bindingHandlers.each(data, vmodels, true)
bindingHandlers.each(data, vmodels, "with")
},
"repeat": function(data, vmodels) {
bindingHandlers.each(data, vmodels, "repeat")
},
"widget": function(data, vmodels) {
var args = data.value.match(rword)
Expand Down Expand Up @@ -2163,7 +2166,7 @@
},
clear: function() {
this.$model.length = this.length = this._.length = 0 //清空数组
notifySubscribers(this, "clear")
notifySubscribers(this, "clear", 0)
return this
},
removeAll: function(all) { //移除N个元素
Expand Down Expand Up @@ -2247,28 +2250,31 @@
return array
}
//========================= each binding ====================
function markMsIf(fragment, collection) {
var all = fragment.querySelectorAll("[ms-if]")
Array.prototype.forEach.call(all, function(el) {
if (!rmsInEach.test(el.className)) {
el.classList.add("msInEach")
collection.push(el)
}
})
}
var withMapper = {}
bindingHandlers["each"] = function(data, vmodels) {
bindingHandlers["each"] = function(data, vmodels,name) {
var elem = data.element,
list, updateView
var array = parseExpr(data.value, vmodels, data)

function getter() {
return array[0].apply(0, array[1])
}

data.parent = elem
var view = documentFragment.cloneNode(false)
while (elem.firstChild) {
view.appendChild(elem.firstChild)
if (name === "repeat") {
var startRepeat = document.createComment("@startRepeat")
var endRepeat = document.createComment("@endRepeat")
data.element = data.parent = elem.parentNode
data.startRepeat = startRepeat
data.endRepeat = endRepeat
elem.removeAttribute(data.node.name)
data.parent.replaceChild(endRepeat, elem)
data.parent.insertBefore(startRepeat, endRepeat)
view.appendChild(elem.cloneNode(true))
} else {
while (elem.firstChild) {
view.appendChild(elem.firstChild)
}
}
data.template = view
data.vmodels = vmodels
Expand All @@ -2295,19 +2301,27 @@
updateView.data = data
updateView.vmodels = vmodels
updateView.rollback = function() {
elem.innerHTML = ""
elem.appendChild(view)
if (name == "repeat") {
updateView("clear", 0)
data.element = view.firstChild
data.parent.replaceChild(data.element, data.startRepeat)
data.parent.removeChild(data.endRepeat)
} else {
elem.innerHTML = ""
elem.appendChild(view)
}

}
list[subscribers] && list[subscribers].push(updateView)
updateView("add", list, 0)
}

var deleteRange = document.createRange()
function eachIterator(method, pos, el, data, getter) {
var group = data.group
var parent = data.element
var mapper = data.mapper
if (method == "del" || method == "move") {
var locatedNode = getLocatedNode(parent, group, pos)
var locatedNode = getLocatedNode(parent, data, pos)
}
switch (method) {
case "add":
Expand Down Expand Up @@ -2336,7 +2350,7 @@
transation.appendChild(tview)
}
//得到插入位置 IE6-10要求insertBefore的第2个参数为节点或null,不能为undefined
locatedNode = getLocatedNode(parent, group, pos)
locatedNode = getLocatedNode(parent, data, pos)
parent.insertBefore(transation, locatedNode)
break
case "del":
Expand All @@ -2349,15 +2363,21 @@
}
break
case "clear":
if (data.startRepeat) {
deleteRange.setStartAfter(data.startRepeat);
deleteRange.setEndBefore(data.endRepeat);
deleteRange.deleteContents();
} else {
avalon.clearChild(parent)
}
mapper.length = 0
avalon.clearChild(parent)
break
case "move":
var t = mapper.splice(pos, 1)[0]
if (t) {
mapper.splice(el, 0, t)
var moveNode = removeView(locatedNode, group)
locatedNode = getLocatedNode(parent, group, el)
locatedNode = getLocatedNode(parent, data, el)
parent.insertBefore(moveNode, locatedNode)
}
break
Expand Down Expand Up @@ -2413,9 +2433,19 @@
// 然后如果它的元素有多少个(ms-each)或键值对有多少双(ms-with),就将它复制多少份(多少为N),再经过扫描后,重新插入该元素中。
// 这时该元素的孩子将分为N等分,每等份的第一个节点就是这个用于定位的节点,
// 方便我们根据它算出整个等分的节点们,然后整体移除或移动它们。

function getLocatedNode(parent, group, pos) {
return parent.childNodes[group * pos] || null
function getLocatedNode(parent, data, pos) {
if (data.startRepeat) {
var ret = data.startRepeat, end = data.endRepeat;
pos += 1
for (var i = 0; i < pos; i++) {
ret = ret.nextSibling
if (ret == end)
return end
}
return ret
} else {
return parent.childNodes[data.group * pos] || null
}
}

function removeView(node, group, n) {
Expand Down

0 comments on commit 7450715

Please sign in to comment.