|
|
@@ -222,30 +222,67 @@ case class RecipeVar(recipe: Option[RecipeNode])
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private def _presentFoodNode(idx: Int)(ingredientSig: Signal[Ingredient]) =
|
|
|
- li(children <-- ingredientSig.flatMap { (ingredient: Ingredient) =>
|
|
|
- Signal.fromFuture(ingredient.food).optionMap { (food) =>
|
|
|
- Seq(
|
|
|
- span(cls := "ui-icon ui-icon-pencil",
|
|
|
- onClick --> { (e: Event) =>
|
|
|
- _editIngredient(ingredient) { (in) =>
|
|
|
- _ingredients.update(_.updated(idx, in))
|
|
|
- Future.successful(())
|
|
|
- }
|
|
|
+ private def _presentFoodNode(ingredient: Ingredient, idx: Int) =
|
|
|
+ li(children <-- Signal.fromFuture(ingredient.food).optionMap({ (food) =>
|
|
|
+ Seq(
|
|
|
+ span(cls := "ui-icon ui-icon-pencil",
|
|
|
+ onClick --> { (e: Event) =>
|
|
|
+ _editIngredient(ingredient) { (in) =>
|
|
|
+ _ingredients.update(_.updated(idx, in))
|
|
|
+ Future.successful(())
|
|
|
}
|
|
|
- ),
|
|
|
- span(cls := "ui-icon ui-icon-close",
|
|
|
- onClick --> { (e: Event) =>
|
|
|
- _ingredients.update(_.filterNot(_ == ingredient))
|
|
|
- }
|
|
|
- ),
|
|
|
- span(f"${ingredient.amount}%.02f${ingredient.unit.abr} ${food.name}")
|
|
|
- )
|
|
|
- } withDefault(Nil)
|
|
|
- })
|
|
|
+ }
|
|
|
+ ),
|
|
|
+ span(cls := "ui-icon ui-icon-close",
|
|
|
+ onClick --> { (e: Event) =>
|
|
|
+ _ingredients.update(_.filterNot(_ == ingredient))
|
|
|
+ }
|
|
|
+ ),
|
|
|
+ span(f"${ingredient.amount}%.02f${ingredient.unit.abr} ${food.name}")
|
|
|
+ )
|
|
|
+ }).withDefault(Nil)
|
|
|
+ )
|
|
|
|
|
|
private val _ENTER_KEY_CODE = 13
|
|
|
|
|
|
+ private val _ingredientList = ul(
|
|
|
+ listStyleType := "none",
|
|
|
+ paddingLeft := "0",
|
|
|
+ // Do not use zipWithIndex. It conflicts with the Sortable interface.
|
|
|
+ children <-- ingredients.map(_.zipWithIndex.map((_presentFoodNode _).tupled)),
|
|
|
+ onMountCallback({(ctx) =>
|
|
|
+ Sortable.create(ctx.thisNode.ref, SortableOptions.onUpdate({
|
|
|
+ (event: SortableEvent) =>
|
|
|
+ _ingredients.update({ (ingredients) =>
|
|
|
+ (event.oldIndex.toOption, event.newIndex.toOption) match {
|
|
|
+ case (Some(old), Some(ne)) if (old < ne) =>
|
|
|
+ moveBackwards(ingredients, old, ne)
|
|
|
+ case (Some(old), Some(ne)) =>
|
|
|
+ moveBackwards(
|
|
|
+ ingredients.reverse,
|
|
|
+ ingredients.size - old - 1,
|
|
|
+ ingredients.size - ne - 1
|
|
|
+ ).reverse
|
|
|
+ case (None, Some(ne)) =>
|
|
|
+ val (first, second) = ingredients.splitAt(ne)
|
|
|
+ (first :+ ???) ++ second
|
|
|
+ case (Some(old), None) =>
|
|
|
+ _removeFromList(ingredients, old)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // If the added element is still in the parent, remove it since the
|
|
|
+ // Rx.update will have generated a new one.
|
|
|
+ Option(event.item.parentElement).map(_.removeChild(event.item))
|
|
|
+
|
|
|
+ def moveBackwards(ingredients: Seq[Ingredient], old: Int, ne: Int) =
|
|
|
+ (ingredients.take(old) ++
|
|
|
+ ingredients.take(ne+1).drop(old + 1) :+
|
|
|
+ ingredients(old)) ++
|
|
|
+ ingredients.drop(ne+1)
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ )
|
|
|
+
|
|
|
private val _steps = Var[Seq[String]](_defaultRecipe.steps)
|
|
|
val steps = _steps.signal
|
|
|
private val _stepIn = input(idAttr := "step",
|
|
|
@@ -263,11 +300,12 @@ case class RecipeVar(recipe: Option[RecipeNode])
|
|
|
private val _stepList = ol(
|
|
|
listStyleType := "none",
|
|
|
paddingLeft := "0",
|
|
|
+ // Do not use zipWithIndex. It conflicts with the Sortable interface.
|
|
|
children <-- _steps.signal.map(_.zipWithIndex.map((_presentStep _).tupled)),
|
|
|
onMountCallback({(ctx) =>
|
|
|
Sortable.create(ctx.thisNode.ref, SortableOptions.onUpdate({
|
|
|
(event: SortableEvent) =>
|
|
|
- _steps.update({ steps =>
|
|
|
+ _steps.update({ (steps) =>
|
|
|
(event.oldIndex.toOption, event.newIndex.toOption) match {
|
|
|
case (Some(old), Some(ne)) if (old < ne) =>
|
|
|
moveBackwards(steps, old, ne)
|
|
|
@@ -381,14 +419,7 @@ case class RecipeVar(recipe: Option[RecipeNode])
|
|
|
div(cls := "col-md-6",
|
|
|
h2("Ingredients"),
|
|
|
_ingredientSearch,
|
|
|
- ul(
|
|
|
- listStyleType := "none",
|
|
|
- paddingLeft := "0",
|
|
|
- children <-- ingredients.splitByIndex {
|
|
|
- case (idx, _, ingredientStream) =>
|
|
|
- _presentFoodNode(idx)(ingredientStream)
|
|
|
- }
|
|
|
- )
|
|
|
+ _ingredientList
|
|
|
),
|
|
|
div(cls := "col-md-6",
|
|
|
h2("Steps"),
|