Don't render cell initial data and make a request instead

This commit is contained in:
Jonatan Kłosko 2021-01-29 21:36:12 +01:00
parent e0d2adfa64
commit cc752542de
3 changed files with 61 additions and 45 deletions

View file

@ -18,17 +18,14 @@ import Markdown from "./markdown";
* * `data-type` - editor type (i.e. language), either "markdown" or "elixir" is expected * * `data-type` - editor type (i.e. language), either "markdown" or "elixir" is expected
* * `data-focused` - whether the cell is currently focused * * `data-focused` - whether the cell is currently focused
* * `data-expanded` - whether the cell is currently expanded (relevant for markdown cells) * * `data-expanded` - whether the cell is currently expanded (relevant for markdown cells)
*
* Additionally the root element should have a `div[data-init]` child (rendered once)
* holding the initial data rendered only once:
*
* * `data-source` - the initial cell source
* * `data-revision` - the initial cell revision corresponding to the source
*/ */
const Cell = { const Cell = {
mounted() { mounted() {
this.props = getProps(this); this.props = getProps(this);
this.pushEvent("cell_init", { cell_id: this.props.cellId }, (payload) => {
const { source, revision } = payload;
const editorContainer = this.el.querySelector("[data-editor-container]"); const editorContainer = this.el.querySelector("[data-editor-container]");
// Remove the content placeholder. // Remove the content placeholder.
editorContainer.firstElementChild.remove(); editorContainer.firstElementChild.remove();
@ -41,8 +38,8 @@ const Cell = {
editorElement, editorElement,
this.props.cellId, this.props.cellId,
this.props.type, this.props.type,
this.props.init.source, source,
this.props.init.revision revision
); );
// Setup markdown rendering. // Setup markdown rendering.
@ -50,12 +47,13 @@ const Cell = {
const markdownContainer = this.el.querySelector( const markdownContainer = this.el.querySelector(
"[data-markdown-container]" "[data-markdown-container]"
); );
const markdown = new Markdown(markdownContainer, this.props.init.source); const markdown = new Markdown(markdownContainer, source);
this.liveEditor.onChange((newSource) => { this.liveEditor.onChange((newSource) => {
markdown.setContent(newSource); markdown.setContent(newSource);
}); });
} }
});
}, },
updated() { updated() {
@ -73,17 +71,11 @@ const Cell = {
}; };
function getProps(hook) { function getProps(hook) {
const initElement = hook.el.querySelector("[data-init]");
return { return {
cellId: getAttributeOrThrow(hook.el, "data-cell-id"), cellId: getAttributeOrThrow(hook.el, "data-cell-id"),
type: getAttributeOrThrow(hook.el, "data-type"), type: getAttributeOrThrow(hook.el, "data-type"),
isFocused: getAttributeOrThrow(hook.el, "data-focused", parseBoolean), isFocused: getAttributeOrThrow(hook.el, "data-focused", parseBoolean),
isExpanded: getAttributeOrThrow(hook.el, "data-expanded", parseBoolean), isExpanded: getAttributeOrThrow(hook.el, "data-expanded", parseBoolean),
init: {
source: getAttributeOrThrow(initElement, "data-source"),
revision: getAttributeOrThrow(initElement, "data-revision", parseInteger),
},
}; };
} }

View file

@ -10,11 +10,6 @@ defmodule LiveBookWeb.Cell do
data-focused="<%= @focused %>" data-focused="<%= @focused %>"
data-expanded="<%= @expanded %>" data-expanded="<%= @expanded %>"
class="flex flex-col relative mr-10 border-l-4 pl-4 -ml-4 border-blue-100 border-opacity-0 hover:border-opacity-100 <%= if @focused, do: "border-blue-300 border-opacity-100"%>"> class="flex flex-col relative mr-10 border-l-4 pl-4 -ml-4 border-blue-100 border-opacity-0 hover:border-opacity-100 <%= if @focused, do: "border-blue-300 border-opacity-100"%>">
<div id="init-container-<%= @cell.id %>" phx-update="ignore">
<div data-init data-source="<%= @cell.source %>" data-revision="<%= @cell_info.revision %>">
</div>
</div>
<%= render_cell_content(assigns) %> <%= render_cell_content(assigns) %>
</div> </div>
""" """
@ -33,7 +28,7 @@ defmodule LiveBookWeb.Cell do
</div> </div>
<div class="markdown" data-markdown-container id="markdown-container-<%= @cell.id %>" phx-update="ignore"> <div class="markdown" data-markdown-container id="markdown-container-<%= @cell.id %>" phx-update="ignore">
<%= render_markdown_content_placeholder() %> <%= render_markdown_content_placeholder(@cell.source) %>
</div> </div>
""" """
end end
@ -59,7 +54,7 @@ defmodule LiveBookWeb.Cell do
data-editor-container data-editor-container
id="editor-container-<%= cell.id %>" id="editor-container-<%= cell.id %>"
phx-update="ignore"> phx-update="ignore">
<%= render_editor_content_placeholder() %> <%= render_editor_content_placeholder(cell.source) %>
</div> </div>
""" """
end end
@ -68,7 +63,13 @@ defmodule LiveBookWeb.Cell do
# There may be a tiny delay before the markdown is rendered # There may be a tiny delay before the markdown is rendered
# or and editors are mounted, so show neat placeholders immediately. # or and editors are mounted, so show neat placeholders immediately.
defp render_markdown_content_placeholder() do defp render_markdown_content_placeholder("" = _content) do
~E"""
<div class="h-4"></div>
"""
end
defp render_markdown_content_placeholder(_content) do
~E""" ~E"""
<div class="max-w-2xl w-full animate-pulse"> <div class="max-w-2xl w-full animate-pulse">
<div class="flex-1 space-y-4"> <div class="flex-1 space-y-4">
@ -80,7 +81,13 @@ defmodule LiveBookWeb.Cell do
""" """
end end
defp render_editor_content_placeholder() do defp render_editor_content_placeholder("" = _content) do
~E"""
<div class="h-4"></div>
"""
end
defp render_editor_content_placeholder(_content) do
~E""" ~E"""
<div class="px-8 max-w-2xl w-full animate-pulse"> <div class="px-8 max-w-2xl w-full animate-pulse">
<div class="flex-1 space-y-4 py-1"> <div class="flex-1 space-y-4 py-1">

View file

@ -88,6 +88,23 @@ defmodule LiveBookWeb.SessionLive do
end end
@impl true @impl true
def handle_event("cell_init", %{"cell_id" => cell_id}, socket) do
data = socket.assigns.data
case Notebook.fetch_cell_and_section(data.notebook, cell_id) do
{:ok, cell, _section} ->
payload = %{
source: cell.source,
revision: data.cell_infos[cell.id].revision
}
{:reply, payload, socket}
:error ->
{:noreply, socket}
end
end
def handle_event("add_section", _params, socket) do def handle_event("add_section", _params, socket) do
end_index = length(socket.assigns.data.notebook.sections) end_index = length(socket.assigns.data.notebook.sections)
Session.insert_section(socket.assigns.session_id, end_index) Session.insert_section(socket.assigns.session_id, end_index)