changed CHANGELOG.md
 
@@ -22,7 22,7 @@ let liveSocket = new LiveSocket("/live", Socket, {
22
22
})
23
23
```
24
24
25
- Additionally, the `phx-page-loading` attrbute has been removed in favor of using the `page_loading: true`
25
Additionally, the `phx-page-loading` attribute has been removed in favor of using the `page_loading: true`
26
26
option to `Phoenix.LiveView.JS.push/2` as needed.
27
27
28
28
### Migrating from phx-feedback-for
 
@@ -112,17 112,22 @@ generated user module:
112
112
if valid_password?(changeset.data, password) do
113
113
```
114
114
115
## 1.0.1 (2024-12-13)
116
117
### Bug fixes
118
* Fix live session verification causing logged errors, push_patch failures, and failed mounts when a cold deploy occurs
119
115
120
## 1.0.0 (2024-12-03) 🚀
116
121
117
122
## 1.0.0-rc.9 (2024-12-03)
118
123
119
124
### Enhancements
120
- * Support `phx-no-curly-interpolation` to disable HEEx curly interpolation in a specific tag body
125
* Support `phx-no-curly-interpolation` to disable HEEx curly interpolation in a specific tag body
121
126
122
127
## 1.0.0-rc.8 (2024-12-02)
123
128
124
129
### Backwards incompatible changes
125
- * Require Elixir v1.14
130
* Require Elixir v1.14.1
126
131
127
132
### Bug fixes
128
133
* Fix live navigation issue where LiveView would attempt a patch on back navigation instead of navigate under certain routing conditions
changed README.md
 
@@ -62,6 62,8 @@ Also follow these announcements from the Phoenix team on LiveView for more examp
62
62
63
63
* [Build a real-time Twitter clone with LiveView](https://www.phoenixframework.org/blog/build-a-real-time-twitter-clone-in-15-minutes-with-live-view-and-phoenix-1-5)
64
64
65
* [Build a real-time Twitch clone with LiveView and Elixir WebRTC](https://www.youtube.com/watch?v=jziOb2Edfzk)
66
65
67
* [Initial announcement](https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript)
66
68
67
69
## Component systems
 
@@ -74,7 76,7 @@ community at different stages of development:
74
76
75
77
* [Doggo](https://github.com/woylie/doggo): Headless UI components for Phoenix
76
78
77
- * [Petal Components](https://github.com/petalframework/petal_components): Phoenix Live View HEEX Components
79
* [Petal Components](https://github.com/petalframework/petal_components): Phoenix Live View HEEX Components
78
80
79
81
* [PrimerLive](https://github.com/ArthurClemens/primer_live): An implementation of GitHub's Primer Design System using Phoenix LiveView
changed hex_metadata.config
 
@@ -2,7 2,7 @@
2
2
[{<<"Changelog">>,<<"https://hexdocs.pm/phoenix_live_view/changelog.html">>},
3
3
{<<"GitHub">>,<<"https://github.com/phoenixframework/phoenix_live_view">>}]}.
4
4
{<<"name">>,<<"phoenix_live_view">>}.
5
- {<<"version">>,<<"1.0.0">>}.
5
{<<"version">>,<<"1.0.1">>}.
6
6
{<<"description">>,
7
7
<<"Rich, real-time user experiences with server-rendered HTML">>}.
8
8
{<<"elixir">>,<<"~> 1.14.1 or ~> 1.15">>}.
changed lib/phoenix_component.ex
 
@@ -666,6 666,12 @@ defmodule Phoenix.Component do
666
666
However, for conditionals and for-comprehensions, there are built-in constructs
667
667
in HEEx too, which we will explore next.
668
668
669
> #### Curly braces in text within tag bodies {: .tip}
670
>
671
> If you have text in your tag bodies, which includes curly braces you can use
672
> `&lbrace;` or `<%= "{" %>` to prevent them from being considered the start of
673
> interpolation.
674
669
675
### Special attributes
670
676
671
677
Apart from normal HTML attributes, HEEx also supports some special attributes
 
@@ -898,7 904,7 @@ defmodule Phoenix.Component do
898
904
Or:
899
905
900
906
```heex
901
- {live_render(@conn, MyApp.ThermostatLive, session:}"home_id" => @home.id}) %>
907
{live_render(@conn, MyApp.ThermostatLive, session: %{"home_id" => @home.id})}
902
908
```
903
909
904
910
Within another LiveView, you must pass the `:id` option:
changed lib/phoenix_live_view/channel.ex
 
@@ -1554,8 1554,27 @@ defmodule Phoenix.LiveView.Channel do
1554
1554
end
1555
1555
1556
1556
defp authorize_session(%Session{} = session, endpoint, %{"url" => url}) do
1557
%Session{view: view, live_session_name: session_name} = session
1558
1557
1559
if Session.main?(session) do
1558
- {:ok, session, session_route(session, endpoint, url), url}
1560
# Ensure the session's LV module and live session name still match on connect.
1561
# If the route has changed the LV module or has moved live sessions, the client
1562
# will fallback to full page redirect to the current URL.
1563
case session_route(session, endpoint, url) do
1564
%Route{view: ^view, live_session: %{name: ^session_name}} = route ->
1565
{:ok, session, route, url}
1566
1567
# if we have a sticky LV, it will be considered a main with no live session
1568
%Route{} when is_nil(session_name) ->
1569
{:ok, session, nil, url}
1570
1571
# if we have a session, then it no longer matches and is unauthorized
1572
%Route{} ->
1573
{:error, :unauthorized}
1574
1575
nil ->
1576
{:error, :unauthorized}
1577
end
1559
1578
else
1560
1579
{:ok, session, _route = nil, _url = nil}
1561
1580
end
 
@@ -1566,7 1585,7 @@ defmodule Phoenix.LiveView.Channel do
1566
1585
end
1567
1586
1568
1587
defp session_route(%Session{} = session, endpoint, url) do
1569
- case Route.live_link_info(endpoint, session.router, url) do
1588
case Route.live_link_info_without_checks(endpoint, session.router, url) do
1570
1589
{:internal, %Route{} = route} -> route
1571
1590
_ -> nil
1572
1591
end
changed lib/phoenix_live_view/html_formatter.ex
 
@@ -569,6 569,7 @@ defmodule Phoenix.LiveView.HTMLFormatter do
569
569
defp head_may_not_have_whitespace?([{:text, text, _meta} | _]),
570
570
do: String.trim_leading(text) != "" and :binary.last(text) not in ~c"\s\t"
571
571
572
defp head_may_not_have_whitespace?([{:body_expr, _, _} | _]), do: true
572
573
defp head_may_not_have_whitespace?([{:eex, _, _} | _]), do: true
573
574
defp head_may_not_have_whitespace?(_), do: false
changed lib/phoenix_live_view/route.ex
 
@@ -29,14 29,13 @@ defmodule Phoenix.LiveView.Route do
29
29
end
30
30
31
31
def live_link_info!(%Socket{} = socket, view, uri) do
32
- %{private: %{live_session_name: session_name, live_session_vsn: session_version}} = socket
32
%{private: %{live_session_name: session_name}} = socket
33
33
34
- case live_link_info(socket.endpoint, socket.router, uri) do
35
- {:internal,
36
- %Route{view: ^view, live_session: %{name: ^session_name, vsn: ^session_version}} = route} ->
34
case live_link_info_without_checks(socket.endpoint, socket.router, uri) do
35
{:internal, %Route{view: ^view, live_session: %{name: ^session_name}} = route} ->
37
36
{:internal, route}
38
37
39
- {:internal, %Route{view: _view} = route} ->
38
{:internal, %Route{} = route} ->
40
39
{:external, route.uri}
41
40
42
41
{:external, _parsed_uri} = external ->
 
@@ -52,11 51,11 @@ defmodule Phoenix.LiveView.Route do
52
51
@doc """
53
52
Returns the internal or external matched LiveView route info for the given uri.
54
53
"""
55
- def live_link_info(endpoint, router, uri) when is_binary(uri) do
56
- live_link_info(endpoint, router, URI.parse(uri))
54
def live_link_info_without_checks(endpoint, router, uri) when is_binary(uri) do
55
live_link_info_without_checks(endpoint, router, URI.parse(uri))
57
56
end
58
57
59
- def live_link_info(endpoint, router, %URI{} = parsed_uri)
58
def live_link_info_without_checks(endpoint, router, %URI{} = parsed_uri)
60
59
when is_atom(endpoint) and is_atom(router) do
61
60
%URI{host: host, path: path, query: query} = parsed_uri
62
61
query_params = if query, do: Plug.Conn.Query.decode(query), else: %{}
changed lib/phoenix_live_view/session.ex
 
@@ -20,11 20,13 @@ defmodule Phoenix.LiveView.Session do
20
20
def authorize_root_redirect(%Session{} = session, %Route{} = route) do
21
21
%Session{live_session_name: session_name, live_session_vsn: session_vsn} = session
22
22
23
- cond do
24
- route.live_session.name == session_name and route.live_session.vsn == session_vsn ->
23
case route.live_session do
24
# We check the version because if there was a new deploy,
25
# we can use this opportunity to reload the whole thing.
26
%{name: ^session_name, vsn: ^session_vsn} ->
25
27
{:ok, replace_root(session, route.view, self())}
26
28
27
- true ->
29
%{} ->
28
30
:error
29
31
end
30
32
end
changed lib/phoenix_live_view/test/dom.ex
 
@@ -25,9 25,40 @@ defmodule Phoenix.LiveViewTest.DOM do
25
25
]
26
26
def parse(html) do
27
27
{:ok, parsed} = Floki.parse_document(html)
28
detect_duplicate_ids(parsed)
29
28
30
parsed
29
31
end
30
32
33
defp detect_duplicate_ids(tree), do: detect_duplicate_ids(tree, MapSet.new())
34
35
defp detect_duplicate_ids([node | rest], ids) do
36
ids = detect_duplicate_ids(node, ids)
37
detect_duplicate_ids(rest, ids)
38
end
39
40
defp detect_duplicate_ids({_tag_name, _attrs, children} = node, ids) do
41
case Floki.attribute(node, "id") do
42
[id] ->
43
if MapSet.member?(ids, id) do
44
raise """
45
Duplicate id found: #{id}
46
47
LiveView requires that all elements have unique ids, duplicate IDs will cause
48
undefined behavior at runtime, as DOM patching will not be able to target the correct
49
elements.
50
"""
51
else
52
detect_duplicate_ids(children, MapSet.put(ids, id))
53
end
54
55
_ ->
56
detect_duplicate_ids(children, ids)
57
end
58
end
59
60
defp detect_duplicate_ids(_non_tag, seen_ids), do: seen_ids
61
31
62
def all(html_tree, selector), do: Floki.find(html_tree, selector)
32
63
33
64
def maybe_one(html_tree, selector, type \\ :selector) do
changed lib/phoenix_live_view/test/live_view_test.ex
 
@@ -1778,7 1778,7 @@ defmodule Phoenix.LiveViewTest do
1778
1778
end
1779
1779
1780
1780
live_module =
1781
- case Phoenix.LiveView.Route.live_link_info(root.endpoint, root.router, url) do
1781
case Phoenix.LiveView.Route.live_link_info_without_checks(root.endpoint, root.router, url) do
1782
1782
{:internal, route} ->
1783
1783
route.view
changed mix.exs
 
@@ -1,7 1,7 @@
1
1
defmodule Phoenix.LiveView.MixProject do
2
2
use Mix.Project
3
3
4
- @version "1.0.0"
4
@version "1.0.1"
5
5
6
6
def project do
7
7
[
 
@@ -21,13 21,14 @@ defmodule Phoenix.LiveView.MixProject do
21
21
homepage_url: "http://www.phoenixframework.org",
22
22
description: """
23
23
Rich, real-time user experiences with server-rendered HTML
24
- """,
25
- preferred_cli_env: [
26
- docs: :docs
27
- ]
24
"""
28
25
]
29
26
end
30
27
28
def cli do
29
[preferred_envs: [docs: :docs]]
30
end
31
31
32
defp elixirc_paths(:e2e), do: ["lib", "test/support", "test/e2e/support"]
32
33
defp elixirc_paths(:test), do: ["lib", "test/support"]
33
34
defp elixirc_paths(_), do: ["lib"]
 
@@ -51,13 52,7 @@ defmodule Phoenix.LiveView.MixProject do
51
52
{:jason, "~> 1.0", optional: true},
52
53
{:floki, "~> 0.36", optional: true},
53
54
{:ex_doc, "~> 0.29", only: :docs},
54
- # TODO: change me when new makeup_elixir is released
55
- # {:makeup_elixir, "~> 1.0", only: :docs},
56
- {:makeup_elixir,
57
- github: "elixir-makeup/makeup_elixir",
58
- ref: "532ebf9e10989a4a54fff47cb51d36a621928b99",
59
- only: :docs,
60
- override: true},
55
{:makeup_elixir, "~> 1.0.1 or ~> 1.1", only: :docs},
61
56
{:makeup_diff, "~> 0.1.1", only: :docs},
62
57
# TODO: change me when makeup_lexers is not needed any more
63
58
# {:makeup_eex, "~> 1.0", only: :docs},
changed package.json
 
@@ -1,6 1,6 @@
1
1
{
2
2
"name": "phoenix_live_view",
3
- "version": "1.0.0",
3
"version": "1.0.1",
4
4
"description": "The Phoenix LiveView JavaScript client.",
5
5
"license": "MIT",
6
6
"module": "./priv/static/phoenix_live_view.esm.js",
changed priv/static/phoenix_live_view.cjs.js
 
@@ -4731,7 4731,7 @@ var LiveSocket = class {
4731
4731
}
4732
4732
// public
4733
4733
version() {
4734
- return "1.0.0";
4734
return "1.0.1";
4735
4735
}
4736
4736
isProfileEnabled() {
4737
4737
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
changed priv/static/phoenix_live_view.esm.js
 
@@ -4704,7 4704,7 @@ var LiveSocket = class {
4704
4704
}
4705
4705
// public
4706
4706
version() {
4707
- return "1.0.0";
4707
return "1.0.1";
4708
4708
}
4709
4709
isProfileEnabled() {
4710
4710
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
changed priv/static/phoenix_live_view.js
 
@@ -4760,7 4760,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
4760
4760
}
4761
4761
// public
4762
4762
version() {
4763
- return "1.0.0";
4763
return "1.0.1";
4764
4764
}
4765
4765
isProfileEnabled() {
4766
4766
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
changed priv/static/phoenix_live_view.min.js
 
@@ -12,4 12,4 @@ removing illegal node: "${(i.outerHTML||i.nodeValue).trim()}"
12
12
import {Socket} from "phoenix"
13
13
import {LiveSocket} from "phoenix_live_view"
14
14
let liveSocket = new LiveSocket("/live", Socket, {...})
15
- `);this.socket=new t(e,i),this.bindingPrefix=i.bindingPrefix||ei,this.opts=i,this.params=Oe(i.params||{}),this.viewLogger=i.viewLogger,this.metadataCallbacks=i.metadata||{},this.defaults=Object.assign(Le(ii),i.defaults||{}),this.activeElement=null,this.prevActive=null,this.silenced=!1,this.main=null,this.outgoingMainEl=null,this.clickStartedAtTarget=null,this.linkRef=1,this.roots={},this.href=window.location.href,this.pendingLink=null,this.currentLocation=Le(window.location),this.hooks=i.hooks||{},this.uploaders=i.uploaders||{},this.loaderTimeout=i.loaderTimeout||Qt,this.reloadWithJitterTimer=null,this.maxReloads=i.maxReloads||10,this.reloadJitterMin=i.reloadJitterMin||5e3,this.reloadJitterMax=i.reloadJitterMax||1e4,this.failsafeJitter=i.failsafeJitter||3e4,this.localStorage=i.localStorage||window.localStorage,this.sessionStorage=i.sessionStorage||window.sessionStorage,this.boundTopLevelEvents=!1,this.boundEventNames=new Set,this.serverCloseRef=null,this.domCallbacks=Object.assign({jsQuerySelectorAll:null,onPatchStart:Oe(),onPatchEnd:Oe(),onNodeAdded:Oe(),onBeforeElUpdated:Oe()},i.dom||{}),this.transitions=new Mt,this.currentHistoryPosition=parseInt(this.sessionStorage.getItem($e))||0,window.addEventListener("pagehide",s=>{this.unloaded=!0}),this.socket.onOpen(()=>{this.isUnloaded()&&window.location.reload()})}version(){return"1.0.0"}isProfileEnabled(){return this.sessionStorage.getItem(ot)==="true"}isDebugEnabled(){return this.sessionStorage.getItem(Xe)==="true"}isDebugDisabled(){return this.sessionStorage.getItem(Xe)==="false"}enableDebug(){this.sessionStorage.setItem(Xe,"true")}enableProfiling(){this.sessionStorage.setItem(ot,"true")}disableDebug(){this.sessionStorage.setItem(Xe,"false")}disableProfiling(){this.sessionStorage.removeItem(ot)}enableLatencySim(e){this.enableDebug(),console.log("latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable"),this.sessionStorage.setItem(lt,e)}disableLatencySim(){this.sessionStorage.removeItem(lt)}getLatencySim(){let e=this.sessionStorage.getItem(lt);return e?parseInt(e):null}getSocket(){return this.socket}connect(){window.location.hostname==="localhost"&&!this.isDebugDisabled()&&this.enableDebug();let e=()=>{this.resetReloadStatus(),this.joinRootViews()?(this.bindTopLevelEvents(),this.socket.connect()):this.main?this.socket.connect():this.bindTopLevelEvents({dead:!0}),this.joinDeadView()};["complete","loaded","interactive"].indexOf(document.readyState)>=0?e():document.addEventListener("DOMContentLoaded",()=>e())}disconnect(e){clearTimeout(this.reloadWithJitterTimer),this.serverCloseRef&&(this.socket.off(this.serverCloseRef),this.serverCloseRef=null),this.socket.disconnect(e)}replaceTransport(e){clearTimeout(this.reloadWithJitterTimer),this.socket.replaceTransport(e),this.connect()}execJS(e,t,i=null){let s=new CustomEvent("phx:exec",{detail:{sourceElement:e}});this.owner(e,n=>P.exec(s,i,t,n,e))}execJSHookPush(e,t,i,s){this.withinOwners(e,n=>{let o=new CustomEvent("phx:exec",{detail:{sourceElement:e}});P.exec(o,"hook",t,n,e,["push",{data:i,callback:s}])})}unload(){this.unloaded||(this.main&&this.isConnected()&&this.log(this.main,"socket",()=>["disconnect for page nav"]),this.unloaded=!0,this.destroyAllViews(),this.disconnect())}triggerDOM(e,t){this.domCallbacks[e](...t)}time(e,t){if(!this.isProfileEnabled()||!console.time)return t();console.time(e);let i=t();return console.timeEnd(e),i}log(e,t,i){if(this.viewLogger){let[s,n]=i();this.viewLogger(e,t,s,n)}else if(this.isDebugEnabled()){let[s,n]=i();ni(e,t,s,n)}}requestDOMUpdate(e){this.transitions.after(e)}transition(e,t,i=function(){}){this.transitions.addTransition(e,t,i)}onChannel(e,t,i){e.on(t,s=>{let n=this.getLatencySim();n?setTimeout(()=>i(s),n):i(s)})}reloadWithJitter(e,t){clearTimeout(this.reloadWithJitterTimer),this.disconnect();let i=this.reloadJitterMin,s=this.reloadJitterMax,n=Math.floor(Math.random()*(s-i 1)) i,o=D.updateLocal(this.localStorage,window.location.pathname,Qe,0,l=>l 1);o>=this.maxReloads&&(n=this.failsafeJitter),this.reloadWithJitterTimer=setTimeout(()=>{e.isDestroyed()||e.isConnected()||(e.destroy(),t?t():this.log(e,"join",()=>[`encountered ${o} consecutive reloads`]),o>=this.maxReloads&&this.log(e,"join",()=>[`exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode`]),this.hasPendingLink()?window.location=this.pendingLink:window.location.reload())},n)}getHookCallbacks(e){return e&&e.startsWith("Phoenix.")?ci[e.split(".")[1]]:this.hooks[e]}isUnloaded(){return this.unloaded}isConnected(){return this.socket.isConnected()}getBindingPrefix(){return this.bindingPrefix}binding(e){return`${this.getBindingPrefix()}${e}`}channel(e,t){return this.socket.channel(e,t)}joinDeadView(){let e=document.body;if(e&&!this.isPhxView(e)&&!this.isPhxView(document.firstElementChild)){let t=this.newRootView(e);t.setHref(this.getHref()),t.joinDead(),this.main||(this.main=t),window.requestAnimationFrame(()=>t.execNewMounted())}}joinRootViews(){let e=!1;return h.all(document,`${q}:not([${Z}])`,t=>{if(!this.getRootById(t.id)){let i=this.newRootView(t);i.setHref(this.getHref()),i.join(),t.hasAttribute(ke)&&(this.main=i)}e=!0}),e}redirect(e,t,i){i&&D.setCookie(yt,i,60),this.unload(),D.redirect(e,t)}replaceMain(e,t,i=null,s=this.setPendingLink(e)){let n=this.currentLocation.href;this.outgoingMainEl=this.outgoingMainEl||this.main.el;let o=h.all(this.outgoingMainEl,`[${this.binding("remove")}]`),l=h.cloneNode(this.outgoingMainEl,"");this.main.showLoader(this.loaderTimeout),this.main.destroy(),this.main=this.newRootView(l,t,n),this.main.setRedirect(e),this.transitionRemoves(o,!0),this.main.join((a,d)=>{a===1&&this.commitPendingLink(s)&&this.requestDOMUpdate(()=>{o.forEach(f=>f.remove()),h.findPhxSticky(document).forEach(f=>l.appendChild(f)),this.outgoingMainEl.replaceWith(l),this.outgoingMainEl=null,i&&i(s),d()})})}transitionRemoves(e,t,i){let s=this.binding("remove");if(t){let o=h.findPhxSticky(document)||[];e=e.filter(l=>!h.isChildOfAny(l,o))}let n=o=>{o.preventDefault(),o.stopImmediatePropagation()};e.forEach(o=>{for(let l of this.boundEventNames)o.addEventListener(l,n,!0);this.execJS(o,o.getAttribute(s),"remove")}),this.requestDOMUpdate(()=>{e.forEach(o=>{for(let l of this.boundEventNames)o.removeEventListener(l,n,!0)}),i&&i()})}isPhxView(e){return e.getAttribute&&e.getAttribute(F)!==null}newRootView(e,t,i){let s=new _e(e,this,null,t,i);return this.roots[s.id]=s,s}owner(e,t){let i=z(e.closest(q),s=>this.getViewByEl(s))||this.main;return i&&t?t(i):i}withinOwners(e,t){this.owner(e,i=>t(i,e))}getViewByEl(e){let t=e.getAttribute(J);return z(this.getRootById(t),i=>i.getDescendentByEl(e))}getRootById(e){return this.roots[e]}destroyAllViews(){for(let e in this.roots)this.roots[e].destroy(),delete this.roots[e];this.main=null}destroyViewByEl(e){let t=this.getRootById(e.getAttribute(J));t&&t.id===e.id?(t.destroy(),delete this.roots[t.id]):t&&t.destroyDescendent(e.id)}getActiveElement(){return document.activeElement}dropActiveElement(e){this.prevActive&&e.ownsElement(this.prevActive)&&(this.prevActive=null)}restorePreviouslyActiveFocus(){this.prevActive&&this.prevActive!==document.body&&this.prevActive.focus()}blurActiveElement(){this.prevActive=this.getActiveElement(),this.prevActive!==document.body&&this.prevActive.blur()}bindTopLevelEvents({dead:e}={}){this.boundTopLevelEvents||(this.boundTopLevelEvents=!0,this.serverCloseRef=this.socket.onClose(t=>{if(t&&t.code===1e3&&this.main)return this.reloadWithJitter(this.main)}),document.body.addEventListener("click",function(){}),window.addEventListener("pageshow",t=>{t.persisted&&(this.getSocket().disconnect(),this.withPageLoading({to:window.location.href,kind:"redirect"}),window.location.reload())},!0),e||this.bindNav(),this.bindClicks(),e||this.bindForms(),this.bind({keyup:"keyup",keydown:"keydown"},(t,i,s,n,o,l)=>{let a=n.getAttribute(this.binding(zt)),d=t.key&&t.key.toLowerCase();if(a&&a.toLowerCase()!==d)return;let f=I({key:t.key},this.eventMeta(i,t,n));P.exec(t,i,o,s,n,["push",{data:f}])}),this.bind({blur:"focusout",focus:"focusin"},(t,i,s,n,o,l)=>{if(!l){let a=I({key:t.key},this.eventMeta(i,t,n));P.exec(t,i,o,s,n,["push",{data:a}])}}),this.bind({blur:"blur",focus:"focus"},(t,i,s,n,o,l)=>{if(l==="window"){let a=this.eventMeta(i,t,n);P.exec(t,i,o,s,n,["push",{data:a}])}}),this.on("dragover",t=>t.preventDefault()),this.on("drop",t=>{t.preventDefault();let i=z(ve(t.target,this.binding(gt)),o=>o.getAttribute(this.binding(gt))),s=i&&document.getElementById(i),n=Array.from(t.dataTransfer.files||[]);!s||s.disabled||n.length===0||!(s.files instanceof FileList)||(C.trackFiles(s,n,t.dataTransfer),s.dispatchEvent(new Event("input",{bubbles:!0})))}),this.on(tt,t=>{let i=t.target;if(!h.isUploadInput(i))return;let s=Array.from(t.detail.files||[]).filter(n=>n instanceof File||n instanceof Blob);C.trackFiles(i,s),i.dispatchEvent(new Event("input",{bubbles:!0}))}))}eventMeta(e,t,i){let s=this.metadataCallbacks[e];return s?s(t,i):{}}setPendingLink(e){return this.linkRef ,this.pendingLink=e,this.resetReloadStatus(),this.linkRef}resetReloadStatus(){D.deleteCookie(yt)}commitPendingLink(e){return this.linkRef!==e?!1:(this.href=this.pendingLink,this.pendingLink=null,!0)}getHref(){return this.href}hasPendingLink(){return!!this.pendingLink}bind(e,t){for(let i in e){let s=e[i];this.on(s,n=>{let o=this.binding(i),l=this.binding(`window-${i}`),a=n.target.getAttribute&&n.target.getAttribute(o);a?this.debounce(n.target,n,s,()=>{this.withinOwners(n.target,d=>{t(n,i,d,n.target,a,null)})}):h.all(document,`[${l}]`,d=>{let f=d.getAttribute(l);this.debounce(d,n,s,()=>{this.withinOwners(d,p=>{t(n,i,p,d,f,"window")})})})})}}bindClicks(){this.on("mousedown",e=>this.clickStartedAtTarget=e.target),this.bindClick("click","click")}bindClick(e,t){let i=this.binding(t);window.addEventListener(e,s=>{let n=null;s.detail===0&&(this.clickStartedAtTarget=s.target);let o=this.clickStartedAtTarget||s.target;n=ve(s.target,i),this.dispatchClickAway(s,o),this.clickStartedAtTarget=null;let l=n&&n.getAttribute(i);if(!l){h.isNewPageClick(s,window.location)&&this.unload();return}n.getAttribute("href")==="#"&&s.preventDefault(),!n.hasAttribute(O)&&this.debounce(n,s,"click",()=>{this.withinOwners(n,a=>{P.exec(s,"click",l,a,n,["push",{data:this.eventMeta("click",s,n)}])})})},!1)}dispatchClickAway(e,t){let i=this.binding("click-away");h.all(document,`[${i}]`,s=>{s.isSameNode(t)||s.contains(t)||this.withinOwners(s,n=>{let o=s.getAttribute(i);P.isVisible(s)&&P.isInViewport(s)&&P.exec(e,"click",o,n,s,["push",{data:this.eventMeta("click",e,e.target)}])})})}bindNav(){if(!D.canPushState())return;history.scrollRestoration&&(history.scrollRestoration="manual");let e=null;window.addEventListener("scroll",t=>{clearTimeout(e),e=setTimeout(()=>{D.updateCurrentState(i=>Object.assign(i,{scroll:window.scrollY}))},100)}),window.addEventListener("popstate",t=>{if(!this.registerNewLocation(window.location))return;let{type:i,backType:s,id:n,root:o,scroll:l,position:a}=t.state||{},d=window.location.href,f=a>this.currentHistoryPosition;i=f?i:s||i,this.currentHistoryPosition=a||0,this.sessionStorage.setItem($e,this.currentHistoryPosition.toString()),h.dispatchEvent(window,"phx:navigate",{detail:{href:d,patch:i==="patch",pop:!0,direction:f?"forward":"backward"}}),this.requestDOMUpdate(()=>{this.main.isConnected()&&i==="patch"&&n===this.main.id?this.main.pushLinkPatch(t,d,null,()=>{this.maybeScroll(l)}):this.replaceMain(d,null,()=>{o&&this.replaceRootHistory(),this.maybeScroll(l)})})},!1),window.addEventListener("click",t=>{let i=ve(t.target,et),s=i&&i.getAttribute(et);if(!s||!this.isConnected()||!this.main||h.wantsNewTab(t))return;let n=i.href instanceof SVGAnimatedString?i.href.baseVal:i.href,o=i.getAttribute(jt);t.preventDefault(),t.stopImmediatePropagation(),this.pendingLink!==n&&this.requestDOMUpdate(()=>{if(s==="patch")this.pushHistoryPatch(t,n,o,i);else if(s==="redirect")this.historyRedirect(t,n,o,null,i);else throw new Error(`expected ${et} to be "patch" or "redirect", got: ${s}`);let l=i.getAttribute(this.binding("click"));l&&this.requestDOMUpdate(()=>this.execJS(i,l,"click"))})},!1)}maybeScroll(e){typeof e=="number"&&requestAnimationFrame(()=>{window.scrollTo(0,e)})}dispatchEvent(e,t={}){h.dispatchEvent(window,`phx:${e}`,{detail:t})}dispatchEvents(e){e.forEach(([t,i])=>this.dispatchEvent(t,i))}withPageLoading(e,t){h.dispatchEvent(window,"phx:page-loading-start",{detail:e});let i=()=>h.dispatchEvent(window,"phx:page-loading-stop",{detail:e});return t?t(i):i}pushHistoryPatch(e,t,i,s){if(!this.isConnected()||!this.main.isMain())return D.redirect(t);this.withPageLoading({to:t,kind:"patch"},n=>{this.main.pushLinkPatch(e,t,s,o=>{this.historyPatch(t,i,o),n()})})}historyPatch(e,t,i=this.setPendingLink(e)){this.commitPendingLink(i)&&(this.currentHistoryPosition ,this.sessionStorage.setItem($e,this.currentHistoryPosition.toString()),D.updateCurrentState(s=>De(I({},s),{backType:"patch"})),D.pushState(t,{type:"patch",id:this.main.id,position:this.currentHistoryPosition},e),h.dispatchEvent(window,"phx:navigate",{detail:{patch:!0,href:e,pop:!1,direction:"forward"}}),this.registerNewLocation(window.location))}historyRedirect(e,t,i,s,n){if(n&&e.isTrusted&&e.type!=="popstate"&&n.classList.add("phx-click-loading"),!this.isConnected()||!this.main.isMain())return D.redirect(t,s);if(/^\/$|^\/[^\/] .*$/.test(t)){let{protocol:l,host:a}=window.location;t=`${l}//${a}${t}`}let o=window.scrollY;this.withPageLoading({to:t,kind:"redirect"},l=>{this.replaceMain(t,s,a=>{a===this.linkRef&&(this.currentHistoryPosition ,this.sessionStorage.setItem($e,this.currentHistoryPosition.toString()),D.updateCurrentState(d=>De(I({},d),{backType:"redirect"})),D.pushState(i,{type:"redirect",id:this.main.id,scroll:o,position:this.currentHistoryPosition},t),h.dispatchEvent(window,"phx:navigate",{detail:{href:t,patch:!1,pop:!1,direction:"forward"}}),this.registerNewLocation(window.location)),l()})})}replaceRootHistory(){D.pushState("replace",{root:!0,type:"patch",id:this.main.id,position:this.currentHistoryPosition})}registerNewLocation(e){let{pathname:t,search:i}=this.currentLocation;return t i===e.pathname e.search?!1:(this.currentLocation=Le(e),!0)}bindForms(){let e=0,t=!1;this.on("submit",i=>{let s=i.target.getAttribute(this.binding("submit")),n=i.target.getAttribute(this.binding("change"));!t&&n&&!s&&(t=!0,i.preventDefault(),this.withinOwners(i.target,o=>{o.disableForm(i.target),window.requestAnimationFrame(()=>{h.isUnloadableFormSubmit(i)&&this.unload(),i.target.submit()})}))}),this.on("submit",i=>{let s=i.target.getAttribute(this.binding("submit"));if(!s){h.isUnloadableFormSubmit(i)&&this.unload();return}i.preventDefault(),i.target.disabled=!0,this.withinOwners(i.target,n=>{P.exec(i,"submit",s,n,i.target,["push",{submitter:i.submitter}])})});for(let i of["change","input"])this.on(i,s=>{if(s instanceof CustomEvent&&s.target.form===void 0){if(s.detail&&s.detail.dispatcher)throw new Error(`dispatching a custom ${i} event is only supported on input elements inside a form`);return}let n=this.binding("change"),o=s.target;if(s.isComposing){let u=`composition-listener-${i}`;h.private(o,u)||(h.putPrivate(o,u,!0),o.addEventListener("compositionend",()=>{o.dispatchEvent(new Event(i,{bubbles:!0})),h.deletePrivate(o,u)},{once:!0}));return}let l=o.getAttribute(n),a=o.form&&o.form.getAttribute(n),d=l||a;if(!d||o.type==="number"&&o.validity&&o.validity.badInput)return;let f=l?o:o.form,p=e;e ;let{at:m,type:g}=h.private(o,"prev-iteration")||{};m===p-1&&i==="change"&&g==="input"||(h.putPrivate(o,"prev-iteration",{at:p,type:i}),this.debounce(o,s,i,()=>{this.withinOwners(f,u=>{h.putPrivate(o,pe,!0),P.exec(s,"change",d,u,o,["push",{_target:s.target.name,dispatcher:f}])})}))});this.on("reset",i=>{let s=i.target;h.resetForm(s);let n=Array.from(s.elements).find(o=>o.type==="reset");n&&window.requestAnimationFrame(()=>{n.dispatchEvent(new Event("input",{bubbles:!0,cancelable:!1}))})})}debounce(e,t,i,s){if(i==="blur"||i==="focusout")return s();let n=this.binding(Kt),o=this.binding(Gt),l=this.defaults.debounce.toString(),a=this.defaults.throttle.toString();this.withinOwners(e,d=>{let f=()=>!d.isDestroyed()&&document.body.contains(e);h.debounce(e,t,n,l,o,a,f,()=>{s()})})}silenceEvents(e){this.silenced=!0,e(),this.silenced=!1}on(e,t){this.boundEventNames.add(e),window.addEventListener(e,i=>{this.silenced||t(i)})}jsQuerySelectorAll(e,t,i){let s=this.domCallbacks.jsQuerySelectorAll;return s?s(e,t,i):i()}},Mt=class{constructor(){this.transitions=new Set,this.pendingOps=[]}reset(){this.transitions.forEach(e=>{clearTimeout(e),this.transitions.delete(e)}),this.flushPendingOps()}after(e){this.size()===0?e():this.pushPendingOp(e)}addTransition(e,t,i){t();let s=setTimeout(()=>{this.transitions.delete(s),i(),this.flushPendingOps()},e);this.transitions.add(s)}pushPendingOp(e){this.pendingOps.push(e)}size(){return this.transitions.size}flushPendingOps(){if(this.size()>0)return;let e=this.pendingOps.shift();e&&(e(),this.flushPendingOps())}};var ss=(r,e={})=>{let t=h.getCustomElHook(r);if(t)return t;let i=new Y(_e.closestView(r),r,e);return h.putCustomElHook(r,i),i};return Ti(rs);})();
15
`);this.socket=new t(e,i),this.bindingPrefix=i.bindingPrefix||ei,this.opts=i,this.params=Oe(i.params||{}),this.viewLogger=i.viewLogger,this.metadataCallbacks=i.metadata||{},this.defaults=Object.assign(Le(ii),i.defaults||{}),this.activeElement=null,this.prevActive=null,this.silenced=!1,this.main=null,this.outgoingMainEl=null,this.clickStartedAtTarget=null,this.linkRef=1,this.roots={},this.href=window.location.href,this.pendingLink=null,this.currentLocation=Le(window.location),this.hooks=i.hooks||{},this.uploaders=i.uploaders||{},this.loaderTimeout=i.loaderTimeout||Qt,this.reloadWithJitterTimer=null,this.maxReloads=i.maxReloads||10,this.reloadJitterMin=i.reloadJitterMin||5e3,this.reloadJitterMax=i.reloadJitterMax||1e4,this.failsafeJitter=i.failsafeJitter||3e4,this.localStorage=i.localStorage||window.localStorage,this.sessionStorage=i.sessionStorage||window.sessionStorage,this.boundTopLevelEvents=!1,this.boundEventNames=new Set,this.serverCloseRef=null,this.domCallbacks=Object.assign({jsQuerySelectorAll:null,onPatchStart:Oe(),onPatchEnd:Oe(),onNodeAdded:Oe(),onBeforeElUpdated:Oe()},i.dom||{}),this.transitions=new Mt,this.currentHistoryPosition=parseInt(this.sessionStorage.getItem($e))||0,window.addEventListener("pagehide",s=>{this.unloaded=!0}),this.socket.onOpen(()=>{this.isUnloaded()&&window.location.reload()})}version(){return"1.0.1"}isProfileEnabled(){return this.sessionStorage.getItem(ot)==="true"}isDebugEnabled(){return this.sessionStorage.getItem(Xe)==="true"}isDebugDisabled(){return this.sessionStorage.getItem(Xe)==="false"}enableDebug(){this.sessionStorage.setItem(Xe,"true")}enableProfiling(){this.sessionStorage.setItem(ot,"true")}disableDebug(){this.sessionStorage.setItem(Xe,"false")}disableProfiling(){this.sessionStorage.removeItem(ot)}enableLatencySim(e){this.enableDebug(),console.log("latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable"),this.sessionStorage.setItem(lt,e)}disableLatencySim(){this.sessionStorage.removeItem(lt)}getLatencySim(){let e=this.sessionStorage.getItem(lt);return e?parseInt(e):null}getSocket(){return this.socket}connect(){window.location.hostname==="localhost"&&!this.isDebugDisabled()&&this.enableDebug();let e=()=>{this.resetReloadStatus(),this.joinRootViews()?(this.bindTopLevelEvents(),this.socket.connect()):this.main?this.socket.connect():this.bindTopLevelEvents({dead:!0}),this.joinDeadView()};["complete","loaded","interactive"].indexOf(document.readyState)>=0?e():document.addEventListener("DOMContentLoaded",()=>e())}disconnect(e){clearTimeout(this.reloadWithJitterTimer),this.serverCloseRef&&(this.socket.off(this.serverCloseRef),this.serverCloseRef=null),this.socket.disconnect(e)}replaceTransport(e){clearTimeout(this.reloadWithJitterTimer),this.socket.replaceTransport(e),this.connect()}execJS(e,t,i=null){let s=new CustomEvent("phx:exec",{detail:{sourceElement:e}});this.owner(e,n=>P.exec(s,i,t,n,e))}execJSHookPush(e,t,i,s){this.withinOwners(e,n=>{let o=new CustomEvent("phx:exec",{detail:{sourceElement:e}});P.exec(o,"hook",t,n,e,["push",{data:i,callback:s}])})}unload(){this.unloaded||(this.main&&this.isConnected()&&this.log(this.main,"socket",()=>["disconnect for page nav"]),this.unloaded=!0,this.destroyAllViews(),this.disconnect())}triggerDOM(e,t){this.domCallbacks[e](...t)}time(e,t){if(!this.isProfileEnabled()||!console.time)return t();console.time(e);let i=t();return console.timeEnd(e),i}log(e,t,i){if(this.viewLogger){let[s,n]=i();this.viewLogger(e,t,s,n)}else if(this.isDebugEnabled()){let[s,n]=i();ni(e,t,s,n)}}requestDOMUpdate(e){this.transitions.after(e)}transition(e,t,i=function(){}){this.transitions.addTransition(e,t,i)}onChannel(e,t,i){e.on(t,s=>{let n=this.getLatencySim();n?setTimeout(()=>i(s),n):i(s)})}reloadWithJitter(e,t){clearTimeout(this.reloadWithJitterTimer),this.disconnect();let i=this.reloadJitterMin,s=this.reloadJitterMax,n=Math.floor(Math.random()*(s-i 1)) i,o=D.updateLocal(this.localStorage,window.location.pathname,Qe,0,l=>l 1);o>=this.maxReloads&&(n=this.failsafeJitter),this.reloadWithJitterTimer=setTimeout(()=>{e.isDestroyed()||e.isConnected()||(e.destroy(),t?t():this.log(e,"join",()=>[`encountered ${o} consecutive reloads`]),o>=this.maxReloads&&this.log(e,"join",()=>[`exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode`]),this.hasPendingLink()?window.location=this.pendingLink:window.location.reload())},n)}getHookCallbacks(e){return e&&e.startsWith("Phoenix.")?ci[e.split(".")[1]]:this.hooks[e]}isUnloaded(){return this.unloaded}isConnected(){return this.socket.isConnected()}getBindingPrefix(){return this.bindingPrefix}binding(e){return`${this.getBindingPrefix()}${e}`}channel(e,t){return this.socket.channel(e,t)}joinDeadView(){let e=document.body;if(e&&!this.isPhxView(e)&&!this.isPhxView(document.firstElementChild)){let t=this.newRootView(e);t.setHref(this.getHref()),t.joinDead(),this.main||(this.main=t),window.requestAnimationFrame(()=>t.execNewMounted())}}joinRootViews(){let e=!1;return h.all(document,`${q}:not([${Z}])`,t=>{if(!this.getRootById(t.id)){let i=this.newRootView(t);i.setHref(this.getHref()),i.join(),t.hasAttribute(ke)&&(this.main=i)}e=!0}),e}redirect(e,t,i){i&&D.setCookie(yt,i,60),this.unload(),D.redirect(e,t)}replaceMain(e,t,i=null,s=this.setPendingLink(e)){let n=this.currentLocation.href;this.outgoingMainEl=this.outgoingMainEl||this.main.el;let o=h.all(this.outgoingMainEl,`[${this.binding("remove")}]`),l=h.cloneNode(this.outgoingMainEl,"");this.main.showLoader(this.loaderTimeout),this.main.destroy(),this.main=this.newRootView(l,t,n),this.main.setRedirect(e),this.transitionRemoves(o,!0),this.main.join((a,d)=>{a===1&&this.commitPendingLink(s)&&this.requestDOMUpdate(()=>{o.forEach(f=>f.remove()),h.findPhxSticky(document).forEach(f=>l.appendChild(f)),this.outgoingMainEl.replaceWith(l),this.outgoingMainEl=null,i&&i(s),d()})})}transitionRemoves(e,t,i){let s=this.binding("remove");if(t){let o=h.findPhxSticky(document)||[];e=e.filter(l=>!h.isChildOfAny(l,o))}let n=o=>{o.preventDefault(),o.stopImmediatePropagation()};e.forEach(o=>{for(let l of this.boundEventNames)o.addEventListener(l,n,!0);this.execJS(o,o.getAttribute(s),"remove")}),this.requestDOMUpdate(()=>{e.forEach(o=>{for(let l of this.boundEventNames)o.removeEventListener(l,n,!0)}),i&&i()})}isPhxView(e){return e.getAttribute&&e.getAttribute(F)!==null}newRootView(e,t,i){let s=new _e(e,this,null,t,i);return this.roots[s.id]=s,s}owner(e,t){let i=z(e.closest(q),s=>this.getViewByEl(s))||this.main;return i&&t?t(i):i}withinOwners(e,t){this.owner(e,i=>t(i,e))}getViewByEl(e){let t=e.getAttribute(J);return z(this.getRootById(t),i=>i.getDescendentByEl(e))}getRootById(e){return this.roots[e]}destroyAllViews(){for(let e in this.roots)this.roots[e].destroy(),delete this.roots[e];this.main=null}destroyViewByEl(e){let t=this.getRootById(e.getAttribute(J));t&&t.id===e.id?(t.destroy(),delete this.roots[t.id]):t&&t.destroyDescendent(e.id)}getActiveElement(){return document.activeElement}dropActiveElement(e){this.prevActive&&e.ownsElement(this.prevActive)&&(this.prevActive=null)}restorePreviouslyActiveFocus(){this.prevActive&&this.prevActive!==document.body&&this.prevActive.focus()}blurActiveElement(){this.prevActive=this.getActiveElement(),this.prevActive!==document.body&&this.prevActive.blur()}bindTopLevelEvents({dead:e}={}){this.boundTopLevelEvents||(this.boundTopLevelEvents=!0,this.serverCloseRef=this.socket.onClose(t=>{if(t&&t.code===1e3&&this.main)return this.reloadWithJitter(this.main)}),document.body.addEventListener("click",function(){}),window.addEventListener("pageshow",t=>{t.persisted&&(this.getSocket().disconnect(),this.withPageLoading({to:window.location.href,kind:"redirect"}),window.location.reload())},!0),e||this.bindNav(),this.bindClicks(),e||this.bindForms(),this.bind({keyup:"keyup",keydown:"keydown"},(t,i,s,n,o,l)=>{let a=n.getAttribute(this.binding(zt)),d=t.key&&t.key.toLowerCase();if(a&&a.toLowerCase()!==d)return;let f=I({key:t.key},this.eventMeta(i,t,n));P.exec(t,i,o,s,n,["push",{data:f}])}),this.bind({blur:"focusout",focus:"focusin"},(t,i,s,n,o,l)=>{if(!l){let a=I({key:t.key},this.eventMeta(i,t,n));P.exec(t,i,o,s,n,["push",{data:a}])}}),this.bind({blur:"blur",focus:"focus"},(t,i,s,n,o,l)=>{if(l==="window"){let a=this.eventMeta(i,t,n);P.exec(t,i,o,s,n,["push",{data:a}])}}),this.on("dragover",t=>t.preventDefault()),this.on("drop",t=>{t.preventDefault();let i=z(ve(t.target,this.binding(gt)),o=>o.getAttribute(this.binding(gt))),s=i&&document.getElementById(i),n=Array.from(t.dataTransfer.files||[]);!s||s.disabled||n.length===0||!(s.files instanceof FileList)||(C.trackFiles(s,n,t.dataTransfer),s.dispatchEvent(new Event("input",{bubbles:!0})))}),this.on(tt,t=>{let i=t.target;if(!h.isUploadInput(i))return;let s=Array.from(t.detail.files||[]).filter(n=>n instanceof File||n instanceof Blob);C.trackFiles(i,s),i.dispatchEvent(new Event("input",{bubbles:!0}))}))}eventMeta(e,t,i){let s=this.metadataCallbacks[e];return s?s(t,i):{}}setPendingLink(e){return this.linkRef ,this.pendingLink=e,this.resetReloadStatus(),this.linkRef}resetReloadStatus(){D.deleteCookie(yt)}commitPendingLink(e){return this.linkRef!==e?!1:(this.href=this.pendingLink,this.pendingLink=null,!0)}getHref(){return this.href}hasPendingLink(){return!!this.pendingLink}bind(e,t){for(let i in e){let s=e[i];this.on(s,n=>{let o=this.binding(i),l=this.binding(`window-${i}`),a=n.target.getAttribute&&n.target.getAttribute(o);a?this.debounce(n.target,n,s,()=>{this.withinOwners(n.target,d=>{t(n,i,d,n.target,a,null)})}):h.all(document,`[${l}]`,d=>{let f=d.getAttribute(l);this.debounce(d,n,s,()=>{this.withinOwners(d,p=>{t(n,i,p,d,f,"window")})})})})}}bindClicks(){this.on("mousedown",e=>this.clickStartedAtTarget=e.target),this.bindClick("click","click")}bindClick(e,t){let i=this.binding(t);window.addEventListener(e,s=>{let n=null;s.detail===0&&(this.clickStartedAtTarget=s.target);let o=this.clickStartedAtTarget||s.target;n=ve(s.target,i),this.dispatchClickAway(s,o),this.clickStartedAtTarget=null;let l=n&&n.getAttribute(i);if(!l){h.isNewPageClick(s,window.location)&&this.unload();return}n.getAttribute("href")==="#"&&s.preventDefault(),!n.hasAttribute(O)&&this.debounce(n,s,"click",()=>{this.withinOwners(n,a=>{P.exec(s,"click",l,a,n,["push",{data:this.eventMeta("click",s,n)}])})})},!1)}dispatchClickAway(e,t){let i=this.binding("click-away");h.all(document,`[${i}]`,s=>{s.isSameNode(t)||s.contains(t)||this.withinOwners(s,n=>{let o=s.getAttribute(i);P.isVisible(s)&&P.isInViewport(s)&&P.exec(e,"click",o,n,s,["push",{data:this.eventMeta("click",e,e.target)}])})})}bindNav(){if(!D.canPushState())return;history.scrollRestoration&&(history.scrollRestoration="manual");let e=null;window.addEventListener("scroll",t=>{clearTimeout(e),e=setTimeout(()=>{D.updateCurrentState(i=>Object.assign(i,{scroll:window.scrollY}))},100)}),window.addEventListener("popstate",t=>{if(!this.registerNewLocation(window.location))return;let{type:i,backType:s,id:n,root:o,scroll:l,position:a}=t.state||{},d=window.location.href,f=a>this.currentHistoryPosition;i=f?i:s||i,this.currentHistoryPosition=a||0,this.sessionStorage.setItem($e,this.currentHistoryPosition.toString()),h.dispatchEvent(window,"phx:navigate",{detail:{href:d,patch:i==="patch",pop:!0,direction:f?"forward":"backward"}}),this.requestDOMUpdate(()=>{this.main.isConnected()&&i==="patch"&&n===this.main.id?this.main.pushLinkPatch(t,d,null,()=>{this.maybeScroll(l)}):this.replaceMain(d,null,()=>{o&&this.replaceRootHistory(),this.maybeScroll(l)})})},!1),window.addEventListener("click",t=>{let i=ve(t.target,et),s=i&&i.getAttribute(et);if(!s||!this.isConnected()||!this.main||h.wantsNewTab(t))return;let n=i.href instanceof SVGAnimatedString?i.href.baseVal:i.href,o=i.getAttribute(jt);t.preventDefault(),t.stopImmediatePropagation(),this.pendingLink!==n&&this.requestDOMUpdate(()=>{if(s==="patch")this.pushHistoryPatch(t,n,o,i);else if(s==="redirect")this.historyRedirect(t,n,o,null,i);else throw new Error(`expected ${et} to be "patch" or "redirect", got: ${s}`);let l=i.getAttribute(this.binding("click"));l&&this.requestDOMUpdate(()=>this.execJS(i,l,"click"))})},!1)}maybeScroll(e){typeof e=="number"&&requestAnimationFrame(()=>{window.scrollTo(0,e)})}dispatchEvent(e,t={}){h.dispatchEvent(window,`phx:${e}`,{detail:t})}dispatchEvents(e){e.forEach(([t,i])=>this.dispatchEvent(t,i))}withPageLoading(e,t){h.dispatchEvent(window,"phx:page-loading-start",{detail:e});let i=()=>h.dispatchEvent(window,"phx:page-loading-stop",{detail:e});return t?t(i):i}pushHistoryPatch(e,t,i,s){if(!this.isConnected()||!this.main.isMain())return D.redirect(t);this.withPageLoading({to:t,kind:"patch"},n=>{this.main.pushLinkPatch(e,t,s,o=>{this.historyPatch(t,i,o),n()})})}historyPatch(e,t,i=this.setPendingLink(e)){this.commitPendingLink(i)&&(this.currentHistoryPosition ,this.sessionStorage.setItem($e,this.currentHistoryPosition.toString()),D.updateCurrentState(s=>De(I({},s),{backType:"patch"})),D.pushState(t,{type:"patch",id:this.main.id,position:this.currentHistoryPosition},e),h.dispatchEvent(window,"phx:navigate",{detail:{patch:!0,href:e,pop:!1,direction:"forward"}}),this.registerNewLocation(window.location))}historyRedirect(e,t,i,s,n){if(n&&e.isTrusted&&e.type!=="popstate"&&n.classList.add("phx-click-loading"),!this.isConnected()||!this.main.isMain())return D.redirect(t,s);if(/^\/$|^\/[^\/] .*$/.test(t)){let{protocol:l,host:a}=window.location;t=`${l}//${a}${t}`}let o=window.scrollY;this.withPageLoading({to:t,kind:"redirect"},l=>{this.replaceMain(t,s,a=>{a===this.linkRef&&(this.currentHistoryPosition ,this.sessionStorage.setItem($e,this.currentHistoryPosition.toString()),D.updateCurrentState(d=>De(I({},d),{backType:"redirect"})),D.pushState(i,{type:"redirect",id:this.main.id,scroll:o,position:this.currentHistoryPosition},t),h.dispatchEvent(window,"phx:navigate",{detail:{href:t,patch:!1,pop:!1,direction:"forward"}}),this.registerNewLocation(window.location)),l()})})}replaceRootHistory(){D.pushState("replace",{root:!0,type:"patch",id:this.main.id,position:this.currentHistoryPosition})}registerNewLocation(e){let{pathname:t,search:i}=this.currentLocation;return t i===e.pathname e.search?!1:(this.currentLocation=Le(e),!0)}bindForms(){let e=0,t=!1;this.on("submit",i=>{let s=i.target.getAttribute(this.binding("submit")),n=i.target.getAttribute(this.binding("change"));!t&&n&&!s&&(t=!0,i.preventDefault(),this.withinOwners(i.target,o=>{o.disableForm(i.target),window.requestAnimationFrame(()=>{h.isUnloadableFormSubmit(i)&&this.unload(),i.target.submit()})}))}),this.on("submit",i=>{let s=i.target.getAttribute(this.binding("submit"));if(!s){h.isUnloadableFormSubmit(i)&&this.unload();return}i.preventDefault(),i.target.disabled=!0,this.withinOwners(i.target,n=>{P.exec(i,"submit",s,n,i.target,["push",{submitter:i.submitter}])})});for(let i of["change","input"])this.on(i,s=>{if(s instanceof CustomEvent&&s.target.form===void 0){if(s.detail&&s.detail.dispatcher)throw new Error(`dispatching a custom ${i} event is only supported on input elements inside a form`);return}let n=this.binding("change"),o=s.target;if(s.isComposing){let u=`composition-listener-${i}`;h.private(o,u)||(h.putPrivate(o,u,!0),o.addEventListener("compositionend",()=>{o.dispatchEvent(new Event(i,{bubbles:!0})),h.deletePrivate(o,u)},{once:!0}));return}let l=o.getAttribute(n),a=o.form&&o.form.getAttribute(n),d=l||a;if(!d||o.type==="number"&&o.validity&&o.validity.badInput)return;let f=l?o:o.form,p=e;e ;let{at:m,type:g}=h.private(o,"prev-iteration")||{};m===p-1&&i==="change"&&g==="input"||(h.putPrivate(o,"prev-iteration",{at:p,type:i}),this.debounce(o,s,i,()=>{this.withinOwners(f,u=>{h.putPrivate(o,pe,!0),P.exec(s,"change",d,u,o,["push",{_target:s.target.name,dispatcher:f}])})}))});this.on("reset",i=>{let s=i.target;h.resetForm(s);let n=Array.from(s.elements).find(o=>o.type==="reset");n&&window.requestAnimationFrame(()=>{n.dispatchEvent(new Event("input",{bubbles:!0,cancelable:!1}))})})}debounce(e,t,i,s){if(i==="blur"||i==="focusout")return s();let n=this.binding(Kt),o=this.binding(Gt),l=this.defaults.debounce.toString(),a=this.defaults.throttle.toString();this.withinOwners(e,d=>{let f=()=>!d.isDestroyed()&&document.body.contains(e);h.debounce(e,t,n,l,o,a,f,()=>{s()})})}silenceEvents(e){this.silenced=!0,e(),this.silenced=!1}on(e,t){this.boundEventNames.add(e),window.addEventListener(e,i=>{this.silenced||t(i)})}jsQuerySelectorAll(e,t,i){let s=this.domCallbacks.jsQuerySelectorAll;return s?s(e,t,i):i()}},Mt=class{constructor(){this.transitions=new Set,this.pendingOps=[]}reset(){this.transitions.forEach(e=>{clearTimeout(e),this.transitions.delete(e)}),this.flushPendingOps()}after(e){this.size()===0?e():this.pushPendingOp(e)}addTransition(e,t,i){t();let s=setTimeout(()=>{this.transitions.delete(s),i(),this.flushPendingOps()},e);this.transitions.add(s)}pushPendingOp(e){this.pendingOps.push(e)}size(){return this.transitions.size}flushPendingOps(){if(this.size()>0)return;let e=this.pendingOps.shift();e&&(e(),this.flushPendingOps())}};var ss=(r,e={})=>{let t=h.getCustomElHook(r);if(t)return t;let i=new Y(_e.closestView(r),r,e);return h.putCustomElHook(r,i),i};return Ti(rs);})();