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
|
> `{` 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);})();
|