Skip to content

Commit

Permalink
Merge pull request #494 from eyra/fix-wysiwyg
Browse files Browse the repository at this point in the history
Fixed Wysiwyg switching combined with realtime updates
  • Loading branch information
mellelieuwes authored Dec 3, 2023
2 parents c8ba9e5 + 07a7217 commit 7e53119
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 59 deletions.
71 changes: 67 additions & 4 deletions core/assets/js/wysiwyg.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,72 @@ import Trix from "trix";

export const Wysiwyg = {
mounted() {
const element = document.querySelector("trix-editor");
element.editor.element.addEventListener("trix-change", (e) => {
element.dispatchEvent(new Event("input", {bubbles: true}))
console.log("[Wysiwyg] Mounted");
this.init();
this.insertTextArea(this.html);
this.upsert_editor(this.visible);
},
updated() {
console.log("[Wysiwyg] Updated");
if (!this.el.parentNode.classList.contains("border-primary")) {
console.log("[Wysiwyg] Reset");
this.init();
this.insertTextArea(this.html);
this.upsert_editor(this.visible);
}
},
init() {
this.id = this.el.dataset.id;
this.name = this.el.dataset.name;
this.target = this.el.dataset.target;
this.html = this.el.dataset.html;
this.visible = this.el.dataset.visible != undefined;
this.locked = this.el.dataset.locked != undefined;
},
insertTextArea(html) {
if (this.textarea != undefined) {
this.textarea.remove();
}

this.textarea = document.createElement("textarea");
this.textarea.setAttribute("id", this.id);
this.textarea.setAttribute("name", this.name);
this.textarea.setAttribute("phx-target", this.target);
this.textarea.setAttribute("phx-debounce", "1000");
this.textarea.classList.add("hidden");
this.textarea.value = html;
this.el.appendChild(this.textarea);
},
upsert_editor(visible) {
if (visible) {
this.removeEditor();
this.insertEditor();
} else {
this.removeEditor();
}
},
insertEditor() {
this.editor = document.createElement("trix-editor");
this.editor.setAttribute("input", this.textarea.id);
this.editor.classList.add("min-h-wysiwyg-editor");
this.editor.classList.add("max-h-wysiwyg-editor");
this.editor.classList.add("overflow-y-scroll");
this.editor.setAttribute("phx-debounce", "1000");

this.container = document.createElement("div");
this.container.appendChild(this.editor);
this.el.appendChild(this.container);
this.editor.addEventListener("trix-change", (e) => {
this.editor.dispatchEvent(new Event("input", { bubbles: true }));
});
},
};
removeEditor() {
if (this.container != undefined) {
while (this.container.lastElementChild) {
this.container.removeChild(this.container.lastElementChild);
}
this.container.remove();
this.container = undefined;
}
},
};
30 changes: 13 additions & 17 deletions core/frameworks/pixel/components/form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ defmodule Frameworks.Pixel.Form do
attr(:debounce, :string, default: "1000")
attr(:min_height, :string, default: "min-h-wysiwyg-editor")
attr(:max_height, :string, default: "max-h-wysiwyg-editor")
attr(:visible, :boolean, default: true)

def wysiwyg_area(%{form: form, field: field} = assigns) do
errors = guarded_errors(form, field)
Expand All @@ -415,6 +416,7 @@ defmodule Frameworks.Pixel.Form do
})

~H"""
<div class={if @visible do "visible" else "hidden" end}>
<.field
field={@field_id}
label_text={@label_text}
Expand All @@ -423,34 +425,28 @@ defmodule Frameworks.Pixel.Form do
errors={@errors}
extra_space={false}
>
<textarea
id={"#{@field_id}_input"}
name={"#{@field_name}_input"}
class="hidden"
phx-target={@target}
phx-debounce={@debounce}
>
<%= @field_value %>
</textarea>
<div
phx-hook="Wysiwyg"
id={@field_id}
name={@field_name}
class={[@input_static_class, @input_dynamic_class]}
__eyra_field_id={@field_id}
__eyra_field_has_errors={@has_errors}
__eyra_field_static_class={@input_static_class}
__eyra_field_active_color={@active_color}
phx-update="ignore"
>
<trix-editor
phx-debounce={@debounce}
input={"#{@field_id}_input"}
class={"#{@min_height} #{@max_height} overflow-y-scroll"}>
<%= @field_value %>
</trix-editor>
<div id={:wysiwyg}
phx-update="ignore"
phx-hook="Wysiwyg"
data-id={"#{@field_id}_input"}
data-name={"#{@field_name}_input"}
data-html={@field_value}
data-visible={true}
data-locked={false}
data-target={@target}
/>
</div>
</.field>
</div>
"""
end

Expand Down
47 changes: 47 additions & 0 deletions core/frameworks/pixel/components/radio_group.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
defmodule Frameworks.Pixel.RadioGroup do
use CoreWeb, :live_component_fabric
use Fabric.LiveComponent

@impl true
def update(%{items: items}, socket) do
active_item = items |> Enum.find(& &1.active)
form = to_form(%{"radio-group" => "#{active_item.id}"})

{
:ok,
socket
|> assign(items: items, form: form)
}
end

@impl true
def handle_event("change", %{"radio-group" => status}, socket) do
{:noreply,
socket |> send_event(:parent, "update", %{status: String.to_existing_atom(status)})}
end

@impl true
def render(assigns) do
~H"""
<div>
<.form id={"#{@id}_form"} for={@form} phx-change="change" phx-target={@myself}>
<div class="flex flex-row gap-8">
<%= for item <- @items do %>
<label class="cursor-pointer flex flex-row gap-[18px] items-center">
<input
id={item.id}
value={item.id}
type="radio"
name="radio-group"
checked={item.active}
class="cursor-pointer appearance-none w-3 h-3 rounded-full ring-2 ring-offset-4 ring-grey3 checked:bg-primary checked:ring-primary"
/>
<div class="text-label font-label text-grey1 select-none mt-1"><%= item.value %></div>
</label>
<% end %>
</div>
</.form>
</div>
"""
end
end
13 changes: 11 additions & 2 deletions core/frameworks/pixel/components/selector.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ defmodule Frameworks.Pixel.Selector do
}
end

@impl true
def update(%{items: new_items}, %{assigns: %{items: _items}} = socket) do
{
:ok,
socket
|> assign(current_items: new_items)
}
end

@impl true
def update(
%{
Expand Down Expand Up @@ -213,7 +222,7 @@ defmodule Frameworks.Pixel.Selector.Item do
})

~H"""
<div class="flex flex-row gap-3 items-center">
<button class="flex flex-row gap-3 items-center">
<div>
<img
x-show="active"
Expand All @@ -229,7 +238,7 @@ defmodule Frameworks.Pixel.Selector.Item do
<div class={"#{@label_color} text-label font-label select-none mt-1"}>
<%= @value %>
</div>
</div>
</button>
"""
end

Expand Down
39 changes: 13 additions & 26 deletions core/frameworks/pixel/components/switch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ defmodule Frameworks.Pixel.Switch do

alias Frameworks.Pixel

# Handle Selector Update
@impl true
def update(%{active_item_id: status, selector_id: :selector}, socket) do
{:ok, socket |> update_status(status)}
end

@impl true
def update(
%{id: id, on_text: on_text, off_text: off_text, opt_in?: opt_in?, status: status},
Expand All @@ -25,24 +19,12 @@ defmodule Frameworks.Pixel.Switch do
opt_in?: opt_in?,
status: status
)
|> compose_child(:selector)
|> compose_child(:radio_group)
}
end

defp update_status(%{assigns: %{status: status}} = socket, new_status)
when status != new_status do
socket
|> assign(status: new_status)
|> send_event(:parent, "switch", %{status: new_status})
end

defp update_status(socket, _status) do
socket
end

@impl true
def compose(:selector, %{
id: id,
def compose(:radio_group, %{
on_text: on_text,
off_text: off_text,
opt_in?: opt_in?,
Expand All @@ -59,17 +41,22 @@ defmodule Frameworks.Pixel.Switch do
end

%{
module: Pixel.Selector,
module: Pixel.RadioGroup,
params: %{
grid_options: "flex flex-row gap-8",
items: items,
type: :radio,
optional?: false,
parent: %{id: id, type: __MODULE__}
items: items
}
}
end

@impl true
def handle_event("update", %{status: status}, socket) do
{
:noreply,
socket
|> send_event(:parent, "update", %{status: status})
}
end

@impl true
def render(assigns) do
~H"""
Expand Down
17 changes: 9 additions & 8 deletions core/systems/assignment/gdpr_form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ defmodule Systems.Assignment.GdprForm do

@impl true
def compose(:consent_revision_form, %{entity: %{consent_agreement: nil}}) do
nil
%{
module: Consent.RevisionForm,
params: %{entity: nil}
}
end

@impl true
Expand All @@ -55,28 +58,26 @@ defmodule Systems.Assignment.GdprForm do

@impl true
def handle_event(
"switch",
"update",
%{status: :on},
%{assigns: %{entity: %{auth_node: auth_node} = assignment}} = socket
) do
consent_agreement = Consent.Public.prepare_agreement(auth_node: auth_node)
Assignment.Public.update_consent_agreement(assignment, consent_agreement)
consent_agreement = Consent.Public.prepare_agreement(auth_node)
{:ok, _} = Assignment.Public.update_consent_agreement(assignment, consent_agreement)

{
:noreply,
socket
|> compose_child(:consent_revision_form)
}
end

@impl true
def handle_event("switch", %{status: :off}, %{assigns: %{entity: assignment}} = socket) do
Assignment.Public.update_consent_agreement(assignment, nil)
def handle_event("update", %{status: :off}, %{assigns: %{entity: assignment}} = socket) do
{:ok, _} = Assignment.Public.update_consent_agreement(assignment, nil)

{
:noreply,
socket
|> hide_child(:consent_revision_form)
}
end

Expand Down
Loading

0 comments on commit 7e53119

Please sign in to comment.