Helper functions for collaborative post editing with Phoenix.Presence.
Provides utilities for tracking editing sessions, determining owner/spectator roles, and syncing state between users.
Summary
Functions
Counts total number of people editing (owner + spectators).
Generates the Presence topic name for a form.
Determines if the current socket is the owner (first in the presence list).
Gets the lock owner's metadata, or nil if no one is editing.
Gets all presences for a form, sorted by join time (FIFO).
Gets all spectators (everyone except the first person).
Subscribes the current process to presence events for a form.
Tracks the current LiveView process in a Presence topic.
Unsubscribes from presence events and editor form events for a form.
Untracks the current LiveView process from a Presence topic.
Functions
Counts total number of people editing (owner + spectators).
Generates the Presence topic name for a form.
Examples
editing_topic("docs:my-post:en")
# => "publishing_edit:docs:my-post:en"
Determines if the current socket is the owner (first in the presence list).
Returns {:owner, presences} if this socket is the owner (or same user in different tab), or
{:spectator, owner_meta, presences} if a different user is the owner.
Examples
case get_editing_role("blog:my-post", socket.id, current_user.uuid) do
{:owner, all_presences} ->
# I can edit!
{:spectator, owner_metadata, all_presences} ->
# I'm read-only, sync with owner's state
end
Gets the lock owner's metadata, or nil if no one is editing.
Gets all presences for a form, sorted by join time (FIFO).
Returns a list of tuples: [{socket_id, metadata}, ...]
Gets all spectators (everyone except the first person).
Returns a list of metadata for spectators only.
Subscribes the current process to presence events for a form.
After subscribing, the process will receive:
%Phoenix.Socket.Broadcast{event: "presence_diff", ...}when users join/leave
Tracks the current LiveView process in a Presence topic.
Parameters
form_key: The unique key for the post being editedsocket: The LiveView socketuser: The current user struct
Examples
track_editing_session("blog:my-post:en", socket, user)
# => {:ok, ref}
Unsubscribes from presence events and editor form events for a form.
Call this when switching languages or versions to clean up subscriptions.
Untracks the current LiveView process from a Presence topic.
Call this when switching languages or versions to release the lock on the previous form before tracking the new one.
Parameters
form_key: The unique key for the post that was being editedsocket: The LiveView socket
Examples
untrack_editing_session("blog:my-post:en", socket)
# => :ok