Update notebook and section name from the UI

This commit is contained in:
Jonatan Kłosko 2021-01-16 19:49:19 +01:00
parent 565b87cfb6
commit 341d0a7ce6
4 changed files with 81 additions and 2 deletions

View file

@ -4,6 +4,11 @@ import "phoenix_html";
import { Socket } from "phoenix";
import NProgress from "nprogress";
import { LiveSocket } from "phoenix_live_view";
import ContentEditable from "./content_editable";
const Hooks = {
ContentEditable,
};
const csrfToken = document
.querySelector("meta[name='csrf-token']")
@ -11,6 +16,7 @@ const csrfToken = document
const liveSocket = new LiveSocket("/live", Socket, {
params: { _csrf_token: csrfToken },
hooks: Hooks,
});
// Show progress bar on live navigation and form submits

View file

@ -0,0 +1,39 @@
/**
* A hook used on [contenteditable] elements to update the specified
* attribute with the element text.
*
* Configuration:
*
* * `data-update-attribute` - the name of the attribute to update when content changes
*/
const ContentEditable = {
mounted() {
this.attribute = this.el.dataset.updateAttribute;
this.__updateAttribute();
// Set the specified attribute on every content change
this.el.addEventListener("input", (event) => {
this.__updateAttribute();
});
// Make sure only plain text is pasted
this.el.addEventListener("paste", (event) => {
event.preventDefault();
const text = event.clipboardData.getData("text/plain");
document.execCommand("insertText", false, text);
});
},
updated() {
// The element has been re-rendered so we have to add the attribute back
this.__updateAttribute();
},
__updateAttribute() {
const value = this.el.innerText.trim();
this.el.setAttribute(this.attribute, value);
},
};
export default ContentEditable;

View file

@ -7,7 +7,14 @@ defmodule LiveBookWeb.Section do
<div class="flex justify-between items-center">
<div class="flex space-x-2 items-center text-gray-600">
<%= Icons.svg(:chevron_right, class: "h-8") %>
<h2 class="text-3xl" contenteditable spellcheck="false"><%= @section.name %></h2>
<h2 id="section-<%= @section.id %>-name"
contenteditable
spellcheck="false"
phx-blur="set_section_name"
phx-value-section_id="<%= @section.id %>"
phx-hook="ContentEditable"
data-update-attribute="phx-value-name"
class="text-3xl"><%= @section.name %></h2>
</div>
<div class="flex space-x-2 items-center">
<button phx-click="delete_section" phx-value-section_id="<%= @section.id %>" class="text-gray-600 hover:text-current">

View file

@ -30,7 +30,13 @@ defmodule LiveBookWeb.SessionLive do
~L"""
<div class="flex flex-grow max-h-full">
<div class="w-1/5 bg-gray-100 border-r-2 border-gray-200">
<h1 class="p-8 text-2xl" contenteditable spellcheck="false"><%= @data.notebook.name %></h1>
<h1 id="notebook-name"
contenteditable
spellcheck="false"
phx-blur="set_notebook_name"
phx-hook="ContentEditable"
data-update-attribute="phx-value-name"
class="p-8 text-2xl"><%= @data.notebook.name %></h1>
<div class="flex flex-col space-y-2 pl-4">
<%= for section <- @data.notebook.sections do %>
<div phx-click="select_section" phx-value-section_id="<%= section.id %>" class="py-2 px-4 rounded-l-md cursor-pointer text-gray-500 hover:text-current">
@ -102,6 +108,27 @@ defmodule LiveBookWeb.SessionLive do
{:noreply, assign(socket, focused_cell_id: cell_id)}
end
def handle_event("set_notebook_name", %{"name" => name}, socket) do
name = normalize_name(name)
Session.set_notebook_name(socket.assigns.session_id, name)
{:noreply, socket}
end
def handle_event("set_section_name", %{"section_id" => section_id, "name" => name}, socket) do
name = normalize_name(name)
Session.set_section_name(socket.assigns.session_id, section_id, name)
{:noreply, socket}
end
defp normalize_name(name) do
case String.trim(name) do
"" -> "Untitled"
name -> name
end
end
@impl true
def handle_info({:operation, operation}, socket) do
case Session.Data.apply_operation(socket.assigns.data, operation) do