From e37a4fcf7135c6e04073206b72cde8de0bc149f6 Mon Sep 17 00:00:00 2001 From: GRBurst Date: Sat, 19 Oct 2019 18:33:02 +0200 Subject: [PATCH] allow all content nodes to be referenced --- webApp/src/main/scala/wust/webApp/Main.scala | 10 +++- .../scala/wust/webApp/views/Components.scala | 54 ++++++++++++++----- .../wust/facades/fomanticui/FomanticUI.scala | 3 ++ 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/webApp/src/main/scala/wust/webApp/Main.scala b/webApp/src/main/scala/wust/webApp/Main.scala index 54322337b..fd04736cd 100644 --- a/webApp/src/main/scala/wust/webApp/Main.scala +++ b/webApp/src/main/scala/wust/webApp/Main.scala @@ -17,6 +17,7 @@ import wust.facades.jquery.JQuery import wust.facades.marked.{Marked, MarkedOptions, Renderer} import wust.facades.wdtEmojiBundle._ import wust.graph.Node +import wust.ids.NodeData import wust.webApp.dragdrop.SortableEvents import wust.webApp.state.{GlobalState, GlobalStateFactory} import wust.webApp.views.{GenericSidebar, MainView, Modal} @@ -66,7 +67,14 @@ object Main { cls := "result", //we need this class for semantic ui to work, div(cls := "title", display.none, result.title), // needed for semantic ui to map the html element back to the SearchSourceEntry padding := "4px", - views.Components.nodeCardAsOneLineText( node, projectWithIcon = true)(Ctx.Owner.Unsafe).prepend( + if(result.placeholder.getOrElse(false)) { + views.Components.renderNodeCard(node, + contentInject = node => + views.Components.displayPlaceholder(node.data.asInstanceOf[NodeData.Placeholder]) + .apply(s" of ${result.text}", cls := "oneline") + )(Ctx.Owner.Unsafe) + } + else views.Components.nodeCardAsOneLineText( node, projectWithIcon = true)(Ctx.Owner.Unsafe).prepend( cursor.pointer, Styles.flex, alignItems.center diff --git a/webApp/src/main/scala/wust/webApp/views/Components.scala b/webApp/src/main/scala/wust/webApp/views/Components.scala index a9fc9e9bd..e31e232d6 100644 --- a/webApp/src/main/scala/wust/webApp/views/Components.scala +++ b/webApp/src/main/scala/wust/webApp/views/Components.scala @@ -108,6 +108,7 @@ object Components { // 4. crop via overflow ellipsis cls := "oneline" ) + } def nodeCardAsOneLineText(node: Node, projectWithIcon: Boolean = true)(implicit ctx: Ctx.Owner): VNode = { @@ -652,7 +653,7 @@ object Components { def searchAndSelectNodeApplied[F[_] : Sink : Source](current: F[Option[NodeId]], filter: Node => Boolean)(implicit ctx: Ctx.Owner): VNode = searchAndSelectNode(current, filter) --> current def searchAndSelectNode[F[_] : Source](observable: F[Option[NodeId]], filter: Node => Boolean)(implicit ctx: Ctx.Owner): EmitterBuilder[Option[NodeId], VNode] = Components.searchInGraph(GlobalState.rawGraph, "Search", filter = { - case n: Node.Content => InlineList.contains[NodeRole](NodeRole.Message, NodeRole.Task, NodeRole.Project)(n.role) && filter(n) + case n: Node.Content => filter(n) case _ => false }, innerElementModifier = width := "100%", inputModifiers = width := "100%").mapResult[VNode] { search => div( @@ -689,18 +690,47 @@ object Components { minCharacters = 0 showNoResults = showNotFound - source = graph.now.nodes.collect { case node: Node if filter(node) => - val str = node match { - case user: Node.User => Components.displayUserName(user.data) - case _ => node.str - } + source = { + val g: Graph = graph.now + val res1 = (g.nodes.collect { case node: Node if filter(node) && node.role == NodeRole.Neutral => - new SearchSourceEntry { - title = node.id.toCuidString - description = trimToMaxLength(str, 36) - data = node.asInstanceOf[js.Any] - } - }(breakOut): js.Array[SearchSourceEntry] + val probEdgesRev = g.propertiesEdgeReverseIdx(g.idToIdxOrThrow(node.id)) + + val probData = probEdgesRev.map{ idx => + val keyString = g.edges(idx).as[Edge.LabeledProperty].data.key + val propertyValue = g.nodes(g.edgesIdx.b(idx)) + val propertySource = g.nodes(g.edgesIdx.a(idx)) + (keyString, propertyValue, propertySource) + } + + probData.collect { + case p: (String, Node, Node) if p._2.data.isInstanceOf[NodeData.Placeholder] => + new SearchSourceEntry { + title = p._2.id.toCuidString + placeholder = true + text = s"${p._1} of ${p._3.str}" + description = trimToMaxLength(s"missing ${p._1} of ${p._3.str}", 36) + data = node.asInstanceOf[js.Any] + } + }(breakOut): js.Array[SearchSourceEntry] + }(breakOut): js.Array[js.Array[SearchSourceEntry]]).flatten + + val res2 = g.nodes.collect { case node: Node if filter(node) && node.role != NodeRole.Neutral => + val str = node match { + case user: Node.User => Components.displayUserName(user.data) + case n: Node.Content => node.str + } + + new SearchSourceEntry { + title = node.id.toCuidString + placeholder = false + description = trimToMaxLength(str, 36) + data = node.asInstanceOf[js.Any] + } + }(breakOut): js.Array[SearchSourceEntry] + + res2 ++ res1 + } searchFields = js.Array("description") diff --git a/webUtil/src/main/scala/wust/facades/fomanticui/FomanticUI.scala b/webUtil/src/main/scala/wust/facades/fomanticui/FomanticUI.scala index 47b7a93a4..80a64d5b0 100644 --- a/webUtil/src/main/scala/wust/facades/fomanticui/FomanticUI.scala +++ b/webUtil/src/main/scala/wust/facades/fomanticui/FomanticUI.scala @@ -169,6 +169,9 @@ trait SearchSourceEntry extends js.Object { var description: js.UndefOr[String] = js.undefined var category: js.UndefOr[String] = js.undefined + var placeholder: js.UndefOr[Boolean] = js.undefined + var text: js.UndefOr[String] = js.undefined + var data: js.UndefOr[js.Any] = js.undefined }