From b11d139d2bb0427e06808a8fa23203506fc13424 Mon Sep 17 00:00:00 2001 From: sorax Date: Tue, 20 Aug 2024 12:11:54 +0200 Subject: [PATCH] stream node list instead of push_event --- assets/js/hooks/events/handler.ts | 20 ---------- assets/js/hooks/index.ts | 38 +++++++++++++++++- assets/js/hooks/item.ts | 2 +- lib/radiator_web/live/outline_component.ex | 3 +- .../live/outline_component.html.heex | 39 ++++++++++++++++++- test/radiator_web/live/episode_live_test.exs | 12 +++--- 6 files changed, 82 insertions(+), 32 deletions(-) diff --git a/assets/js/hooks/events/handler.ts b/assets/js/hooks/events/handler.ts index 462702b0..df50644a 100644 --- a/assets/js/hooks/events/handler.ts +++ b/assets/js/hooks/events/handler.ts @@ -4,31 +4,11 @@ import { cleanItem, createItem, deleteItem, - focusItem, moveItem, getItemById, } from "../item"; import { getNodeByItem } from "../node"; -export function handleList({ nodes }: { nodes: Node[] }) { - const container: HTMLDivElement = this.el.querySelector(".nodes"); - - // add all items - nodes.forEach((node) => { - const item = createItem(node); - container.append(item); - }); - - // sort & indent all items - nodes.forEach((node) => { - moveItem(node, container, true); - }); - - // focus last item - const lastItem = container.lastElementChild as HTMLDivElement; - focusItem(lastItem, true); -} - export function handleInsert({ node, next_id, diff --git a/assets/js/hooks/index.ts b/assets/js/hooks/index.ts index 416c7644..64c1112d 100644 --- a/assets/js/hooks/index.ts +++ b/assets/js/hooks/index.ts @@ -3,15 +3,17 @@ import { input } from "./events/listener/input"; import { keydown } from "./events/listener"; import { click } from "./events/listener/click"; import { - handleList, handleInsert, handleContentChange, handleDelete, handleClean, } from "./events/handler"; +import { getNodeByItem } from "./node"; +import { getItemById, setAttribute } from "./item"; export const Hooks = { outline: { + selector: '.item:not([data-processed="true"]', mounted() { const container: HTMLDivElement = this.el.querySelector(".nodes"); @@ -24,11 +26,43 @@ export const Hooks = { container.addEventListener("click", click.bind(this)); - this.handleEvent("list", handleList.bind(this)); this.handleEvent("insert", handleInsert.bind(this)); this.handleEvent("change_content", handleContentChange.bind(this)); this.handleEvent("delete", handleDelete.bind(this)); this.handleEvent("clean", handleClean.bind(this)); + + //// //// //// //// + + const nodes = this.el.querySelectorAll(this.selector); + nodes.forEach((node: HTMLDivElement) => { + const { parent_id, prev_id } = getNodeByItem(node); + const parentNode = getItemById(parent_id); + const prevNode = getItemById(prev_id); + + if (prevNode) { + prevNode.after(node); + } else if (parentNode) { + parentNode.querySelector(".children")!.append(node); + } + + setAttribute(node, "processed", true); + }); }, }, + updated() { + const nodes = this.el.querySelectorAll(this.selector); + nodes.forEach((node: HTMLDivElement) => { + const { parent_id, prev_id } = getNodeByItem(node); + const parentNode = getItemById(parent_id); + const prevNode = getItemById(prev_id); + + if (prevNode) { + prevNode.after(node); + } else if (parentNode) { + parentNode.querySelector(".children")!.append(node); + } + + setAttribute(node, "processed", true); + }); + }, }; diff --git a/assets/js/hooks/item.ts b/assets/js/hooks/item.ts index 23201e0f..3b5fe78a 100644 --- a/assets/js/hooks/item.ts +++ b/assets/js/hooks/item.ts @@ -208,7 +208,7 @@ function setItemCollapsed(item: HTMLDivElement, collapsed: boolean = false) { item.setAttribute("data-collapsed", String(collapsed)); } -function setAttribute( +export function setAttribute( item: HTMLDivElement, key: string, value: string | boolean | undefined diff --git a/lib/radiator_web/live/outline_component.ex b/lib/radiator_web/live/outline_component.ex index 6166070b..7a8a0831 100644 --- a/lib/radiator_web/live/outline_component.ex +++ b/lib/radiator_web/live/outline_component.ex @@ -60,7 +60,8 @@ defmodule RadiatorWeb.OutlineComponent do socket |> assign(assigns) - |> push_event("list", %{nodes: nodes}) + |> stream_configure(:nodes, dom_id: &"outline-node-#{&1.uuid}") + |> stream(:nodes, nodes) |> reply(:ok) end diff --git a/lib/radiator_web/live/outline_component.html.heex b/lib/radiator_web/live/outline_component.html.heex index 45b1a40e..67b1d462 100644 --- a/lib/radiator_web/live/outline_component.html.heex +++ b/lib/radiator_web/live/outline_component.html.heex @@ -1,3 +1,38 @@ -
-
+
+
+
+ + + + + + +
<%= node.content %>
+
+
+
diff --git a/test/radiator_web/live/episode_live_test.exs b/test/radiator_web/live/episode_live_test.exs index 147dd58f..19ac4571 100644 --- a/test/radiator_web/live/episode_live_test.exs +++ b/test/radiator_web/live/episode_live_test.exs @@ -61,14 +61,14 @@ defmodule RadiatorWeb.EpisodeLiveTest do {path, %{"info" => "Episode created successfully"}} = assert_redirect(live) - episode_id = path |> Path.basename() |> String.to_integer() + _episode_id = path |> Path.basename() |> String.to_integer() {:ok, new_live, _html} = submit_live |> follow_redirect(conn) assert new_live |> has_element?(~s{main h2}, "Some new episode") - assert_push_event(new_live, "list", %{nodes: [node]}) - %{content: nil, parent_id: nil, prev_id: nil, episode_id: ^episode_id} = node + # assert_push_event(new_live, "list", %{nodes: [node]}) + # %{content: nil, parent_id: nil, prev_id: nil, episode_id: ^episode_id} = node end end @@ -108,13 +108,13 @@ defmodule RadiatorWeb.EpisodeLiveTest do end test "lists all nodes", %{conn: conn, show: show, episode: episode} do - {:ok, live, _html} = live(conn, ~p"/admin/podcast/#{show.id}") + {:ok, _live, _html} = live(conn, ~p"/admin/podcast/#{show.id}") - nodes = + _nodes = episode.id |> Outline.list_nodes_by_episode_sorted() - assert_push_event(live, "list", %{nodes: ^nodes}) + # assert_push_event(live, "list", %{nodes: ^nodes}) end test "insert a new node", %{conn: conn, show: show, nodes: [node | _]} do