diff --git a/assets/js/cell/index.js b/assets/js/cell/index.js index 4a0f0f515..a99442d04 100644 --- a/assets/js/cell/index.js +++ b/assets/js/cell/index.js @@ -234,7 +234,10 @@ function handleInsertModeChanged(hook, insertMode) { if (input) { if (hook.state.insertMode) { input.focus(); - input.selectionStart = input.selectionEnd = input.value.length; + // selectionStart is only supported on text based input + if (input.selectionStart !== null) { + input.selectionStart = input.selectionEnd = input.value.length; + } } else { input.blur(); } diff --git a/lib/livebook/notebook/cell/input.ex b/lib/livebook/notebook/cell/input.ex index 2e74017be..447e1ff9a 100644 --- a/lib/livebook/notebook/cell/input.ex +++ b/lib/livebook/notebook/cell/input.ex @@ -21,7 +21,8 @@ defmodule Livebook.Notebook.Cell.Input do props: props() } - @type type :: :text | :url | :number | :password | :textarea | :color | :range | :select + @type type :: + :text | :url | :number | :password | :textarea | :color | :range | :select | :checkbox @typedoc """ Additional properties adjusting the given input type. diff --git a/lib/livebook_web/helpers.ex b/lib/livebook_web/helpers.ex index b1dc85313..29d4dbd61 100644 --- a/lib/livebook_web/helpers.ex +++ b/lib/livebook_web/helpers.ex @@ -151,6 +151,10 @@ defmodule LivebookWeb.Helpers do @doc """ Renders a checkbox input styled as a switch. + Also, a hidden input with the same name is rendered + alongside the checkbox, so the submitted value is + always either `"true"` or `"false"`. + ## Examples <.switch_checkbox @@ -159,13 +163,30 @@ defmodule LivebookWeb.Helpers do checked={@likes_cats} /> """ def switch_checkbox(assigns) do - assigns = assign_new(assigns, :disabled, fn -> false end) + assigns = + assigns + |> assign_new(:label, fn -> nil end) + |> assign_new(:disabled, fn -> false end) + |> assign_new(:class, fn -> "" end) + |> assign( + :attrs, + assigns_to_attributes(assigns, [:label, :name, :checked, :disabled, :class]) + ) ~H"""
- <%= @label %> + <%= if @label do %> + <%= @label %> + <% end %>
diff --git a/lib/livebook_web/live/session_live/cell_component.ex b/lib/livebook_web/live/session_live/cell_component.ex index eeb77d7a1..a78be5701 100644 --- a/lib/livebook_web/live/session_live/cell_component.ex +++ b/lib/livebook_web/live/session_live/cell_component.ex @@ -179,6 +179,17 @@ defmodule LivebookWeb.SessionLive.CellComponent do """ end + defp cell_input(%{cell_view: %{input_type: :checkbox}} = assigns) do + ~H""" +
+ <.switch_checkbox + data-element="input" + name="value" + checked={@cell_view.value == "true"} /> +
+ """ + end + defp cell_input(assigns) do ~H""" delete_cells}, socket) do + delete_cells? = delete_cells == "true" Livebook.Session.delete_section( socket.assigns.session_id, diff --git a/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex b/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex index 8abd0635a..2943e0749 100644 --- a/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex +++ b/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex @@ -50,7 +50,7 @@ defmodule LivebookWeb.SessionLive.ElixirCellSettingsComponent do end defp update_metadata(metadata, form_data) do - if Map.has_key?(form_data, "disable_formatting") do + if form_data["disable_formatting"] == "true" do Map.put(metadata, "disable_formatting", true) else Map.delete(metadata, "disable_formatting") diff --git a/lib/livebook_web/live/session_live/input_cell_settings_component.ex b/lib/livebook_web/live/session_live/input_cell_settings_component.ex index ea0384ede..8082145a2 100644 --- a/lib/livebook_web/live/session_live/input_cell_settings_component.ex +++ b/lib/livebook_web/live/session_live/input_cell_settings_component.ex @@ -161,7 +161,7 @@ defmodule LivebookWeb.SessionLive.InputCellSettingsComponent do defp validate_attrs(data, prev_attrs) do name = data["name"] type = data["type"] |> String.to_existing_atom() - reactive = Map.has_key?(data, "reactive") + reactive = data["reactive"] == "true" {props_valid?, props} = if type == prev_attrs.type do @@ -209,6 +209,7 @@ defmodule LivebookWeb.SessionLive.InputCellSettingsComponent do end end + defp default_value(:checkbox, _props), do: "false" defp default_value(:color, _props), do: "#3E64FF" defp default_value(:range, %{min: min}), do: to_string(min) defp default_value(:select, %{options: [option | _]}), do: option @@ -216,6 +217,7 @@ defmodule LivebookWeb.SessionLive.InputCellSettingsComponent do defp input_types do [ + checkbox: "Checkbox", color: "Color", number: "Number", password: "Password", diff --git a/lib/livebook_web/live/session_live/shortcuts_component.ex b/lib/livebook_web/live/session_live/shortcuts_component.ex index a4045e8ae..deb0ef68e 100644 --- a/lib/livebook_web/live/session_live/shortcuts_component.ex +++ b/lib/livebook_web/live/session_live/shortcuts_component.ex @@ -226,8 +226,8 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do end @impl true - def handle_event("settings", params, socket) do - basic? = Map.has_key?(params, "basic") + def handle_event("settings", %{"basic" => basic}, socket) do + basic? = basic == "true" {:noreply, assign(socket, :basic, basic?)} end end