mirror of
https://github.com/phfroidmont/scalive.git
synced 2025-12-25 05:26:59 +01:00
Fix splitBy ordering, properly this time
This commit is contained in:
parent
d011477d9e
commit
4c9dfb2533
2 changed files with 95 additions and 5 deletions
|
|
@ -37,7 +37,7 @@ sealed trait Dyn[T]:
|
||||||
private[scalive] def callOnEveryChild(f: T => Unit): Unit
|
private[scalive] def callOnEveryChild(f: T => Unit): Unit
|
||||||
|
|
||||||
extension [T](parent: Dyn[List[T]])
|
extension [T](parent: Dyn[List[T]])
|
||||||
def splitBy[Key: Ordering](key: T => Key)(project: (Key, Dyn[T]) => HtmlElement): Mod =
|
def splitBy[Key](key: T => Key)(project: (Key, Dyn[T]) => HtmlElement): Mod =
|
||||||
Mod.Content.DynSplit(
|
Mod.Content.DynSplit(
|
||||||
new SplitVar(
|
new SplitVar(
|
||||||
parent,
|
parent,
|
||||||
|
|
@ -90,13 +90,15 @@ private class DerivedVar[I, O] private[scalive] (parent: Var[I], f: I => O) exte
|
||||||
|
|
||||||
private[scalive] def callOnEveryChild(f: O => Unit): Unit = f(currentValue)
|
private[scalive] def callOnEveryChild(f: O => Unit): Unit = f(currentValue)
|
||||||
|
|
||||||
private class SplitVar[I, O, Key: Ordering](
|
private class SplitVar[I, O, Key](
|
||||||
parent: Dyn[List[I]],
|
parent: Dyn[List[I]],
|
||||||
key: I => Key,
|
key: I => Key,
|
||||||
project: (Key, Dyn[I]) => O):
|
project: (Key, Dyn[I]) => O):
|
||||||
|
|
||||||
private val memoized: mutable.Map[Key, (Var[I], O)] =
|
private val memoized: mutable.Map[Key, (Var[I], O)] =
|
||||||
mutable.TreeMap.empty
|
mutable.Map.empty
|
||||||
|
|
||||||
|
private var orderedKeys = List.empty[Key]
|
||||||
|
|
||||||
private var previousKeysToIndex: Map[Key, Int] = Map.empty
|
private var previousKeysToIndex: Map[Key, Int] = Map.empty
|
||||||
|
|
||||||
|
|
@ -105,9 +107,10 @@ private class SplitVar[I, O, Key: Ordering](
|
||||||
private[scalive] def sync(): Unit =
|
private[scalive] def sync(): Unit =
|
||||||
parent.sync()
|
parent.sync()
|
||||||
if parent.changed then
|
if parent.changed then
|
||||||
previousKeysToIndex = memoized.keys.zipWithIndex.toMap
|
previousKeysToIndex = orderedKeys.zipWithIndex.toMap
|
||||||
// We keep track of the keys to remove deleted ones afterwards
|
// We keep track of the keys to remove deleted ones afterwards
|
||||||
val nextKeys = mutable.HashSet.empty[Key]
|
val nextKeys = mutable.HashSet.empty[Key]
|
||||||
|
orderedKeys = parent.currentValue.map(key)
|
||||||
parent.currentValue.foreach(input =>
|
parent.currentValue.foreach(input =>
|
||||||
val entryKey = key(input)
|
val entryKey = key(input)
|
||||||
nextKeys += entryKey
|
nextKeys += entryKey
|
||||||
|
|
@ -138,7 +141,8 @@ private class SplitVar[I, O, Key: Ordering](
|
||||||
if parent.changed || !trackUpdates then
|
if parent.changed || !trackUpdates then
|
||||||
Some(
|
Some(
|
||||||
(
|
(
|
||||||
changeList = memoized.zipWithIndex
|
changeList = orderedKeys
|
||||||
|
.map(k => (k, memoized(k))).zipWithIndex
|
||||||
.map { case ((key, (entryVar, output)), index) =>
|
.map { case ((key, (entryVar, output)), index) =>
|
||||||
(index, previousKeysToIndex.get(key).filterNot(_ == index), entryVar, output)
|
(index, previousKeysToIndex.get(key).filterNot(_ == index), entryVar, output)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -550,5 +550,91 @@ object LiveViewSpec extends TestSuite:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("splitBy ordering") {
|
||||||
|
val initModel = TestModel(
|
||||||
|
items = List(
|
||||||
|
NestedModel("c", 20),
|
||||||
|
NestedModel("a", 10),
|
||||||
|
NestedModel("b", 15)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val model = Var(initModel)
|
||||||
|
val el =
|
||||||
|
div(
|
||||||
|
ul(
|
||||||
|
model(_.items).splitBy(_.name)((_, elem) =>
|
||||||
|
li(
|
||||||
|
"Nom: ",
|
||||||
|
elem(_.name),
|
||||||
|
" Age: ",
|
||||||
|
elem(_.age.toString)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
el.syncAll()
|
||||||
|
el.setAllUnchanged()
|
||||||
|
|
||||||
|
test("init should preserve list order") {
|
||||||
|
assertEqualsDiff(
|
||||||
|
el,
|
||||||
|
Json
|
||||||
|
.Obj(
|
||||||
|
"s" -> Json.Arr(Json.Str("<div><ul>"), Json.Str("</ul></div>")),
|
||||||
|
"0" -> Json.Obj(
|
||||||
|
"s" -> Json.Arr(
|
||||||
|
Json.Str("<li>Nom: "),
|
||||||
|
Json.Str(" Age: "),
|
||||||
|
Json.Str("</li>")
|
||||||
|
),
|
||||||
|
"k" -> Json.Obj(
|
||||||
|
"0" -> Json.Obj(
|
||||||
|
"0" -> Json.Str("c"),
|
||||||
|
"1" -> Json.Str("20")
|
||||||
|
),
|
||||||
|
"1" -> Json.Obj(
|
||||||
|
"0" -> Json.Str("a"),
|
||||||
|
"1" -> Json.Str("10")
|
||||||
|
),
|
||||||
|
"2" -> Json.Obj(
|
||||||
|
"0" -> Json.Str("b"),
|
||||||
|
"1" -> Json.Str("15")
|
||||||
|
),
|
||||||
|
"kc" -> Json.Num(3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
trackChanges = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("reorder items") {
|
||||||
|
model.update(
|
||||||
|
_.copy(items =
|
||||||
|
List(
|
||||||
|
NestedModel("b", 15), // Should be at index 0
|
||||||
|
NestedModel("a", 10), // Should be at index 1
|
||||||
|
NestedModel("c", 20) // Should be at index 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertEqualsDiff(
|
||||||
|
el,
|
||||||
|
Json.Obj(
|
||||||
|
"0" ->
|
||||||
|
Json
|
||||||
|
.Obj(
|
||||||
|
"k" -> Json.Obj(
|
||||||
|
"0" -> Json.Num(2),
|
||||||
|
"2" -> Json.Num(0),
|
||||||
|
"kc" -> Json.Num(3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
end LiveViewSpec
|
end LiveViewSpec
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue