phoenix_live_view 1.2.0-rc.3 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/assets/js/phoenix_live_view/README.md +1 -1
- package/assets/js/phoenix_live_view/dom.ts +3 -1
- package/assets/js/phoenix_live_view/dom_patch.ts +1 -1
- package/assets/js/phoenix_live_view/index.ts +2 -2
- package/assets/js/phoenix_live_view/live_socket.ts +21 -14
- package/assets/js/phoenix_live_view/view.ts +10 -0
- package/assets/js/phoenix_live_view/view_hook.ts +22 -14
- package/package.json +2 -2
- package/priv/static/phoenix_live_view.cjs.js +23 -13
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +23 -13
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +23 -13
- package/priv/static/phoenix_live_view.min.js +6 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Phoenix LiveView
|
|
2
2
|
|
|
3
|
-
[](https://github.com/phoenixframework/phoenix_live_view/actions?query=workflow%3ACI) [](https://hex.pm/packages/phoenix_live_view) [](https://hexdocs.pm
|
|
3
|
+
[](https://github.com/phoenixframework/phoenix_live_view/actions?query=workflow%3ACI) [](https://hex.pm/packages/phoenix_live_view) [](https://phoenix-live-view.hexdocs.pm)
|
|
4
4
|
|
|
5
5
|
Phoenix LiveView enables rich, real-time user experiences with server-rendered HTML.
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@ model while keeping your code closer to your data (and ultimately your source of
|
|
|
34
34
|
|
|
35
35
|
* **Diffs over the wire:** Instead of sending "HTML over the wire", LiveView knows exactly which parts of your templates change, sending minimal diffs over the wire after the initial render, reducing latency and bandwidth usage. The client leverages this information and optimizes the browser with 5-10x faster updates, compared to solutions that replace whole HTML fragments.
|
|
36
36
|
|
|
37
|
-
* **Live form validation:** LiveView supports real-time form validation out of the box. Create rich user interfaces with features like uploads, nested inputs, and [specialized recovery](https://hexdocs.pm/
|
|
37
|
+
* **Live form validation:** LiveView supports real-time form validation out of the box. Create rich user interfaces with features like uploads, nested inputs, and [specialized recovery](https://phoenix-live-view.hexdocs.pm/form-bindings.html#recovery-following-crashes-or-disconnects).
|
|
38
38
|
|
|
39
39
|
* **File uploads:** Real-time file uploads with progress indicators and image previews. Process your uploads on the fly or submit them to your desired cloud service.
|
|
40
40
|
|
|
@@ -52,9 +52,9 @@ model while keeping your code closer to your data (and ultimately your source of
|
|
|
52
52
|
|
|
53
53
|
## Learning
|
|
54
54
|
|
|
55
|
-
Check our [comprehensive docs](https://hexdocs.pm
|
|
55
|
+
Check our [comprehensive docs](https://phoenix-live-view.hexdocs.pm) to get started.
|
|
56
56
|
|
|
57
|
-
The Phoenix framework documentation also keeps a list of [community resources](https://hexdocs.pm/
|
|
57
|
+
The Phoenix framework documentation also keeps a list of [community resources](https://phoenix.hexdocs.pm/community.html), including books, videos, and other materials, and some include LiveView too.
|
|
58
58
|
|
|
59
59
|
Also follow these announcements from the Phoenix team on LiveView for more examples and rationale:
|
|
60
60
|
|
|
@@ -103,7 +103,7 @@ which provides quick times for "First Meaningful Paint", in addition to
|
|
|
103
103
|
helping search and indexing engines.
|
|
104
104
|
|
|
105
105
|
Then LiveView uses a persistent connection between client and server.
|
|
106
|
-
This allows LiveView applications to react faster to user events as
|
|
106
|
+
This allows LiveView applications to react faster to user events, as
|
|
107
107
|
there is less work to be done and less data to be sent compared to
|
|
108
108
|
stateless requests that have to authenticate, decode, load, and encode
|
|
109
109
|
data on every request.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
## LiveView JavaScript Client
|
|
2
2
|
|
|
3
|
-
This is the documentation for the LiveView JavaScript client. It is a more low-level API documentation for advanced users. For a higher-level overview, [see the page on JavaScript interoperability](https://hexdocs.pm/
|
|
3
|
+
This is the documentation for the LiveView JavaScript client. It is a more low-level API documentation for advanced users. For a higher-level overview, [see the page on JavaScript interoperability](https://phoenix-live-view.hexdocs.pm/js-interop.html) instead.
|
|
@@ -411,7 +411,9 @@ const DOM = {
|
|
|
411
411
|
// we also clear the throttle timeout to prevent the callback
|
|
412
412
|
// from being called again after the timeout fires
|
|
413
413
|
clearTimeout(this.private(el, THROTTLED));
|
|
414
|
-
|
|
414
|
+
if (asyncFilter()) {
|
|
415
|
+
this.triggerCycle(el, DEBOUNCE_TRIGGER);
|
|
416
|
+
}
|
|
415
417
|
});
|
|
416
418
|
}
|
|
417
419
|
}
|
|
@@ -792,7 +792,7 @@ export default class DOMPatch {
|
|
|
792
792
|
private transitionPendingRemoves() {
|
|
793
793
|
const { pendingRemoves, liveSocket } = this;
|
|
794
794
|
if (pendingRemoves.length > 0) {
|
|
795
|
-
liveSocket.transitionRemoves(pendingRemoves, () => {
|
|
795
|
+
liveSocket.transitionRemoves(pendingRemoves, this.view, () => {
|
|
796
796
|
pendingRemoves.forEach((el) => {
|
|
797
797
|
const child = DOM.firstPhxChild(el);
|
|
798
798
|
if (child) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* This is the documentation for the LiveView JavaScript client.
|
|
3
3
|
* It is a more low-level API documentation for advanced users.
|
|
4
|
-
* For a higher-level overview, [see the page on JavaScript interoperability](https://hexdocs.pm/
|
|
4
|
+
* For a higher-level overview, [see the page on JavaScript interoperability](https://phoenix-live-view.hexdocs.pm/js-interop.html) instead.
|
|
5
5
|
*
|
|
6
|
-
* The main documentation can be found at `https://hexdocs.pm
|
|
6
|
+
* The main documentation can be found at `https://phoenix-live-view.hexdocs.pm`.
|
|
7
7
|
*
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
@@ -92,7 +92,7 @@ export interface LiveSocketOptions {
|
|
|
92
92
|
/**
|
|
93
93
|
* Callbacks for LiveView hooks.
|
|
94
94
|
*
|
|
95
|
-
* See [Client hooks via `phx-hook`](https://hexdocs.pm/
|
|
95
|
+
* See [Client hooks via `phx-hook`](https://phoenix-live-view.hexdocs.pm/js-interop.html#client-hooks-via-phx-hook) for more information.
|
|
96
96
|
*/
|
|
97
97
|
hooks?: HooksOptions;
|
|
98
98
|
/** Callbacks for LiveView uploaders. */
|
|
@@ -425,7 +425,7 @@ export default class LiveSocket {
|
|
|
425
425
|
* Enables debugging.
|
|
426
426
|
*
|
|
427
427
|
* When debugging is enabled, the LiveView client will log debug information to the console.
|
|
428
|
-
* See [Debugging client events](https://hexdocs.pm/
|
|
428
|
+
* See [Debugging client events](https://phoenix-live-view.hexdocs.pm/js-interop.html#debugging-client-events) for more information.
|
|
429
429
|
*/
|
|
430
430
|
enableDebug(): void {
|
|
431
431
|
this.sessionStorage.setItem(PHX_LV_DEBUG, "true");
|
|
@@ -458,7 +458,7 @@ export default class LiveSocket {
|
|
|
458
458
|
* Enables latency simulation.
|
|
459
459
|
*
|
|
460
460
|
* When latency simulation is enabled, the LiveView client will add a delay to requests and responses from the server.
|
|
461
|
-
* See [Simulating Latency](https://hexdocs.pm/
|
|
461
|
+
* See [Simulating Latency](https://phoenix-live-view.hexdocs.pm/js-interop.html#simulating-latency) for more information.
|
|
462
462
|
*/
|
|
463
463
|
enableLatencySim(upperBoundMs: number): void {
|
|
464
464
|
this.enableDebug();
|
|
@@ -547,7 +547,7 @@ export default class LiveSocket {
|
|
|
547
547
|
/**
|
|
548
548
|
* Executes an encoded JS command, targeting the given element.
|
|
549
549
|
*
|
|
550
|
-
* See [`Phoenix.LiveView.JS`](https://hexdocs.pm/
|
|
550
|
+
* See [`Phoenix.LiveView.JS`](https://phoenix-live-view.hexdocs.pm/Phoenix.LiveView.JS.html) for more information.
|
|
551
551
|
*/
|
|
552
552
|
execJS(
|
|
553
553
|
el: Element,
|
|
@@ -562,7 +562,7 @@ export default class LiveSocket {
|
|
|
562
562
|
* Returns an object with methods to manipulate the DOM and execute JavaScript.
|
|
563
563
|
* The applied changes integrate with server DOM patching.
|
|
564
564
|
*
|
|
565
|
-
* See [JavaScript interoperability](https://hexdocs.pm/
|
|
565
|
+
* See [JavaScript interoperability](https://phoenix-live-view.hexdocs.pm/js-interop.html) for more information.
|
|
566
566
|
*/
|
|
567
567
|
js(): LiveSocketJSCommands {
|
|
568
568
|
return jsCommands(this, "js");
|
|
@@ -823,12 +823,15 @@ export default class LiveSocket {
|
|
|
823
823
|
).filter((el) => !DOM.isChildOfAny(el, stickies));
|
|
824
824
|
|
|
825
825
|
const newMainEl = DOM.cloneNode(this.outgoingMainEl, "");
|
|
826
|
-
this.main
|
|
827
|
-
this.
|
|
826
|
+
const oldMainView = this.main;
|
|
827
|
+
oldMainView.showLoader(this.loaderTimeout);
|
|
828
|
+
oldMainView.destroy();
|
|
828
829
|
|
|
829
830
|
this.main = this.newRootView(newMainEl, flash, liveReferer);
|
|
830
831
|
this.main.setRedirect(href);
|
|
831
|
-
this
|
|
832
|
+
// the old view is destroyed at this point; pass it explicitly so the
|
|
833
|
+
// phx-remove commands execute in the context of the outgoing view
|
|
834
|
+
this.transitionRemoves(removeEls, oldMainView);
|
|
832
835
|
this.main.join((joinCount, onDone) => {
|
|
833
836
|
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
834
837
|
this.requestDOMUpdate(() => {
|
|
@@ -845,7 +848,7 @@ export default class LiveSocket {
|
|
|
845
848
|
}
|
|
846
849
|
|
|
847
850
|
/** @internal */
|
|
848
|
-
transitionRemoves(elements, callback?) {
|
|
851
|
+
transitionRemoves(elements, view: View, callback?) {
|
|
849
852
|
const removeAttr = this.binding("remove");
|
|
850
853
|
const silenceEvents = (e) => {
|
|
851
854
|
e.preventDefault();
|
|
@@ -857,7 +860,8 @@ export default class LiveSocket {
|
|
|
857
860
|
for (const event of this.boundEventNames) {
|
|
858
861
|
el.addEventListener(event, silenceEvents, true);
|
|
859
862
|
}
|
|
860
|
-
|
|
863
|
+
const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } });
|
|
864
|
+
JS.exec(e, "remove", el.getAttribute(removeAttr), view, el);
|
|
861
865
|
});
|
|
862
866
|
// remove the silenced listeners when transitions are done in case the element is re-used
|
|
863
867
|
// and call caller's callback as soon as we are done with transitions
|
|
@@ -885,12 +889,15 @@ export default class LiveSocket {
|
|
|
885
889
|
|
|
886
890
|
/** @internal */
|
|
887
891
|
owner(childEl: Element, callback?: (view: View) => any) {
|
|
888
|
-
let view: View;
|
|
892
|
+
let view: View | undefined;
|
|
889
893
|
const viewEl = DOM.closestViewEl(childEl);
|
|
890
894
|
if (viewEl) {
|
|
891
|
-
//
|
|
892
|
-
//
|
|
893
|
-
|
|
895
|
+
// resolve the view by element identity instead of id; during live
|
|
896
|
+
// navigation the new view is registered under the same id while the
|
|
897
|
+
// old DOM is still attached, and events from the old DOM must not be
|
|
898
|
+
// routed to the new view. A destroyed view removes its element binding,
|
|
899
|
+
// in which case we DO NOT want to fallback to the main element
|
|
900
|
+
view = DOM.private(viewEl, "view");
|
|
894
901
|
} else {
|
|
895
902
|
if (!childEl.isConnected) {
|
|
896
903
|
// if the element is not part of the DOM any more
|
|
@@ -408,6 +408,7 @@ export default class View {
|
|
|
408
408
|
if (container) {
|
|
409
409
|
const [tag, attrs] = container;
|
|
410
410
|
this.el = DOM.replaceRootContainer(this.el, tag, attrs);
|
|
411
|
+
DOM.putPrivate(this.el, "view", this);
|
|
411
412
|
}
|
|
412
413
|
this.childJoins = 0;
|
|
413
414
|
this.joinPending = true;
|
|
@@ -516,7 +517,10 @@ export default class View {
|
|
|
516
517
|
if (!el) {
|
|
517
518
|
throw new Error("unable to find root element for view");
|
|
518
519
|
}
|
|
520
|
+
// child views are initially bound to an element inside the join HTML
|
|
521
|
+
// fragment (see onJoinComplete), so the binding must move to the real el
|
|
519
522
|
this.el = el;
|
|
523
|
+
DOM.putPrivate(this.el, "view", this);
|
|
520
524
|
this.el.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
521
525
|
}
|
|
522
526
|
|
|
@@ -746,6 +750,7 @@ export default class View {
|
|
|
746
750
|
});
|
|
747
751
|
|
|
748
752
|
// because we work with a template element, we must manually copy the attributes
|
|
753
|
+
// and bind the template root to this view,
|
|
749
754
|
// otherwise the owner / target helpers don't work properly
|
|
750
755
|
const rootEl = template.content.firstElementChild!;
|
|
751
756
|
rootEl.id = this.id;
|
|
@@ -753,6 +758,7 @@ export default class View {
|
|
|
753
758
|
rootEl.setAttribute(PHX_SESSION, this.getSession());
|
|
754
759
|
rootEl.setAttribute(PHX_STATIC, this.getStatic() ?? "");
|
|
755
760
|
this.parent && rootEl.setAttribute(PHX_PARENT_ID, this.parent.id);
|
|
761
|
+
DOM.putPrivate(rootEl, "view", this);
|
|
756
762
|
|
|
757
763
|
// we go over all form elements in the new HTML for the LV
|
|
758
764
|
// and look for old forms in the `formsForRecovery` object;
|
|
@@ -1152,6 +1158,10 @@ export default class View {
|
|
|
1152
1158
|
}
|
|
1153
1159
|
|
|
1154
1160
|
onJoinError(resp) {
|
|
1161
|
+
if (resp.events) {
|
|
1162
|
+
this.liveSocket.dispatchEvents(resp.events);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1155
1165
|
if (resp.reason === "reload") {
|
|
1156
1166
|
this.log("error", () => [
|
|
1157
1167
|
`failed mount with ${resp.status}. Falling back to page reload`,
|
|
@@ -84,10 +84,12 @@ export interface HookInterface<E extends HTMLElement = HTMLElement> {
|
|
|
84
84
|
* Use the {@link pushEvent | promise-returning version} to handle errors.
|
|
85
85
|
*
|
|
86
86
|
* @param event - The event name.
|
|
87
|
-
* @param payload - The payload to send to the server.
|
|
87
|
+
* @param payload - The payload to send to the server. Must be a serializable
|
|
88
|
+
* value (typically JSON-serializable, depends on the Socket configuration).
|
|
89
|
+
* Defaults to an empty object.
|
|
88
90
|
* @param onReply - A callback to handle the server's reply.
|
|
89
91
|
*/
|
|
90
|
-
pushEvent(event: string, payload:
|
|
92
|
+
pushEvent(event: string, payload: unknown, onReply: OnReply): void;
|
|
91
93
|
/**
|
|
92
94
|
* Pushes an event to the server and returns a Promise that resolves with the server's reply.
|
|
93
95
|
*
|
|
@@ -95,10 +97,12 @@ export interface HookInterface<E extends HTMLElement = HTMLElement> {
|
|
|
95
97
|
* such as a disconnected state, timeout, or the server rejecting the event.
|
|
96
98
|
*
|
|
97
99
|
* @param event - The event name.
|
|
98
|
-
* @param [payload] - The payload to send to the server.
|
|
100
|
+
* @param [payload] - The payload to send to the server. Must be a serializable
|
|
101
|
+
* value (typically JSON-serializable, depends on the Socket configuration).
|
|
102
|
+
* Defaults to an empty object.
|
|
99
103
|
* @returns A promise that fulfills or rejects with the server's reply.
|
|
100
104
|
*/
|
|
101
|
-
pushEvent(event: string, payload?:
|
|
105
|
+
pushEvent(event: string, payload?: unknown): Promise<any>;
|
|
102
106
|
|
|
103
107
|
/**
|
|
104
108
|
* Pushes a targeted event to the server and invokes a callback with the server's reply.
|
|
@@ -115,13 +119,15 @@ export interface HookInterface<E extends HTMLElement = HTMLElement> {
|
|
|
115
119
|
*
|
|
116
120
|
* @param selectorOrTarget - The selector, element, or CID to target.
|
|
117
121
|
* @param event - The event name.
|
|
118
|
-
* @param payload - The payload to send to the server.
|
|
122
|
+
* @param payload - The payload to send to the server. Must be a serializable
|
|
123
|
+
* value (typically JSON-serializable, depends on the Socket configuration).
|
|
124
|
+
* Defaults to an empty object.
|
|
119
125
|
* @param onReply - A callback to handle the server's reply.
|
|
120
126
|
*/
|
|
121
127
|
pushEventTo(
|
|
122
128
|
selectorOrTarget: PhxTarget,
|
|
123
129
|
event: string,
|
|
124
|
-
payload:
|
|
130
|
+
payload: unknown,
|
|
125
131
|
onReply: OnReply,
|
|
126
132
|
): void;
|
|
127
133
|
/**
|
|
@@ -142,13 +148,15 @@ export interface HookInterface<E extends HTMLElement = HTMLElement> {
|
|
|
142
148
|
*
|
|
143
149
|
* @param selectorOrTarget - The selector, element, or CID to target.
|
|
144
150
|
* @param event - The event name.
|
|
145
|
-
* @param [payload] - The payload to send to the server.
|
|
151
|
+
* @param [payload] - The payload to send to the server. Must be a serializable
|
|
152
|
+
* value (typically JSON-serializable, depends on the Socket configuration).
|
|
153
|
+
* Defaults to an empty object.
|
|
146
154
|
* @returns A promise that resolves when the event has been handled by all targets.
|
|
147
155
|
*/
|
|
148
156
|
pushEventTo(
|
|
149
157
|
selectorOrTarget: PhxTarget,
|
|
150
158
|
event: string,
|
|
151
|
-
payload?:
|
|
159
|
+
payload?: unknown,
|
|
152
160
|
): Promise<PromiseSettledResult<{ reply: any; ref: number }>[]>;
|
|
153
161
|
|
|
154
162
|
/**
|
|
@@ -445,11 +453,11 @@ export class ViewHook<E extends HTMLElement = HTMLElement>
|
|
|
445
453
|
};
|
|
446
454
|
}
|
|
447
455
|
|
|
448
|
-
pushEvent(event: string, payload:
|
|
449
|
-
pushEvent(event: string, payload?:
|
|
456
|
+
pushEvent(event: string, payload: unknown, onReply: OnReply): void;
|
|
457
|
+
pushEvent(event: string, payload?: unknown): Promise<any>;
|
|
450
458
|
pushEvent(
|
|
451
459
|
event: string,
|
|
452
|
-
payload?:
|
|
460
|
+
payload?: unknown,
|
|
453
461
|
onReply?: OnReply,
|
|
454
462
|
): Promise<any> | void {
|
|
455
463
|
const promise = this.__view().pushHookEvent(
|
|
@@ -471,18 +479,18 @@ export class ViewHook<E extends HTMLElement = HTMLElement>
|
|
|
471
479
|
pushEventTo(
|
|
472
480
|
selectorOrTarget: PhxTarget,
|
|
473
481
|
event: string,
|
|
474
|
-
payload:
|
|
482
|
+
payload: unknown,
|
|
475
483
|
onReply: OnReply,
|
|
476
484
|
): void;
|
|
477
485
|
pushEventTo(
|
|
478
486
|
selectorOrTarget: PhxTarget,
|
|
479
487
|
event: string,
|
|
480
|
-
payload?:
|
|
488
|
+
payload?: unknown,
|
|
481
489
|
): Promise<PromiseSettledResult<{ reply: any; ref: number }>[]>;
|
|
482
490
|
pushEventTo(
|
|
483
491
|
selectorOrTarget: PhxTarget,
|
|
484
492
|
event: string,
|
|
485
|
-
payload?:
|
|
493
|
+
payload?: unknown,
|
|
486
494
|
onReply?: OnReply,
|
|
487
495
|
): Promise<PromiseSettledResult<{ reply: any; ref: number }>[]> | void {
|
|
488
496
|
if (onReply === undefined) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phoenix_live_view",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "The Phoenix LiveView JavaScript client.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@babel/preset-env": "7.27.2",
|
|
38
38
|
"@babel/preset-typescript": "^7.27.1",
|
|
39
39
|
"@eslint/js": "^9.29.0",
|
|
40
|
-
"@playwright/test": "^1.
|
|
40
|
+
"@playwright/test": "^1.60.0",
|
|
41
41
|
"@types/jest": "^30.0.0",
|
|
42
42
|
"@types/phoenix": "^1.6.6",
|
|
43
43
|
"css.escape": "^1.5.1",
|
|
@@ -671,7 +671,9 @@ var DOM = {
|
|
|
671
671
|
if (this.once(el, "bind-debounce")) {
|
|
672
672
|
el.addEventListener("blur", () => {
|
|
673
673
|
clearTimeout(this.private(el, THROTTLED));
|
|
674
|
-
|
|
674
|
+
if (asyncFilter()) {
|
|
675
|
+
this.triggerCycle(el, DEBOUNCE_TRIGGER);
|
|
676
|
+
}
|
|
675
677
|
});
|
|
676
678
|
}
|
|
677
679
|
}
|
|
@@ -2825,7 +2827,7 @@ var DOMPatch = class {
|
|
|
2825
2827
|
transitionPendingRemoves() {
|
|
2826
2828
|
const { pendingRemoves, liveSocket } = this;
|
|
2827
2829
|
if (pendingRemoves.length > 0) {
|
|
2828
|
-
liveSocket.transitionRemoves(pendingRemoves, () => {
|
|
2830
|
+
liveSocket.transitionRemoves(pendingRemoves, this.view, () => {
|
|
2829
2831
|
pendingRemoves.forEach((el) => {
|
|
2830
2832
|
const child = dom_default.firstPhxChild(el);
|
|
2831
2833
|
if (child) {
|
|
@@ -4453,6 +4455,7 @@ var View = class _View {
|
|
|
4453
4455
|
if (container) {
|
|
4454
4456
|
const [tag, attrs] = container;
|
|
4455
4457
|
this.el = dom_default.replaceRootContainer(this.el, tag, attrs);
|
|
4458
|
+
dom_default.putPrivate(this.el, "view", this);
|
|
4456
4459
|
}
|
|
4457
4460
|
this.childJoins = 0;
|
|
4458
4461
|
this.joinPending = true;
|
|
@@ -4539,6 +4542,7 @@ var View = class _View {
|
|
|
4539
4542
|
throw new Error("unable to find root element for view");
|
|
4540
4543
|
}
|
|
4541
4544
|
this.el = el;
|
|
4545
|
+
dom_default.putPrivate(this.el, "view", this);
|
|
4542
4546
|
this.el.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
4543
4547
|
}
|
|
4544
4548
|
// this is invoked for dead and live views, so we must filter by
|
|
@@ -4727,6 +4731,7 @@ var View = class _View {
|
|
|
4727
4731
|
rootEl.setAttribute(PHX_SESSION, this.getSession());
|
|
4728
4732
|
rootEl.setAttribute(PHX_STATIC, this.getStatic() ?? "");
|
|
4729
4733
|
this.parent && rootEl.setAttribute(PHX_PARENT_ID, this.parent.id);
|
|
4734
|
+
dom_default.putPrivate(rootEl, "view", this);
|
|
4730
4735
|
const formsToRecover = (
|
|
4731
4736
|
// we go over all forms in the new DOM; because this is only the HTML for the current
|
|
4732
4737
|
// view, we can be sure that all forms are owned by this view:
|
|
@@ -5021,6 +5026,9 @@ var View = class _View {
|
|
|
5021
5026
|
});
|
|
5022
5027
|
}
|
|
5023
5028
|
onJoinError(resp) {
|
|
5029
|
+
if (resp.events) {
|
|
5030
|
+
this.liveSocket.dispatchEvents(resp.events);
|
|
5031
|
+
}
|
|
5024
5032
|
if (resp.reason === "reload") {
|
|
5025
5033
|
this.log("error", () => [
|
|
5026
5034
|
`failed mount with ${resp.status}. Falling back to page reload`,
|
|
@@ -6086,7 +6094,7 @@ var LiveSocket = class {
|
|
|
6086
6094
|
* Returns the version of the LiveView client.
|
|
6087
6095
|
*/
|
|
6088
6096
|
version() {
|
|
6089
|
-
return "1.2.
|
|
6097
|
+
return "1.2.1";
|
|
6090
6098
|
}
|
|
6091
6099
|
/**
|
|
6092
6100
|
* Returns true if profiling is enabled. See {@link enableProfiling} and {@link disableProfiling}.
|
|
@@ -6110,7 +6118,7 @@ var LiveSocket = class {
|
|
|
6110
6118
|
* Enables debugging.
|
|
6111
6119
|
*
|
|
6112
6120
|
* When debugging is enabled, the LiveView client will log debug information to the console.
|
|
6113
|
-
* See [Debugging client events](https://hexdocs.pm/
|
|
6121
|
+
* See [Debugging client events](https://phoenix-live-view.hexdocs.pm/js-interop.html#debugging-client-events) for more information.
|
|
6114
6122
|
*/
|
|
6115
6123
|
enableDebug() {
|
|
6116
6124
|
this.sessionStorage.setItem(PHX_LV_DEBUG, "true");
|
|
@@ -6139,7 +6147,7 @@ var LiveSocket = class {
|
|
|
6139
6147
|
* Enables latency simulation.
|
|
6140
6148
|
*
|
|
6141
6149
|
* When latency simulation is enabled, the LiveView client will add a delay to requests and responses from the server.
|
|
6142
|
-
* See [Simulating Latency](https://hexdocs.pm/
|
|
6150
|
+
* See [Simulating Latency](https://phoenix-live-view.hexdocs.pm/js-interop.html#simulating-latency) for more information.
|
|
6143
6151
|
*/
|
|
6144
6152
|
enableLatencySim(upperBoundMs) {
|
|
6145
6153
|
this.enableDebug();
|
|
@@ -6214,7 +6222,7 @@ var LiveSocket = class {
|
|
|
6214
6222
|
/**
|
|
6215
6223
|
* Executes an encoded JS command, targeting the given element.
|
|
6216
6224
|
*
|
|
6217
|
-
* See [`Phoenix.LiveView.JS`](https://hexdocs.pm/
|
|
6225
|
+
* See [`Phoenix.LiveView.JS`](https://phoenix-live-view.hexdocs.pm/Phoenix.LiveView.JS.html) for more information.
|
|
6218
6226
|
*/
|
|
6219
6227
|
execJS(el, encodedJS, eventType = null) {
|
|
6220
6228
|
const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } });
|
|
@@ -6224,7 +6232,7 @@ var LiveSocket = class {
|
|
|
6224
6232
|
* Returns an object with methods to manipulate the DOM and execute JavaScript.
|
|
6225
6233
|
* The applied changes integrate with server DOM patching.
|
|
6226
6234
|
*
|
|
6227
|
-
* See [JavaScript interoperability](https://hexdocs.pm/
|
|
6235
|
+
* See [JavaScript interoperability](https://phoenix-live-view.hexdocs.pm/js-interop.html) for more information.
|
|
6228
6236
|
*/
|
|
6229
6237
|
js() {
|
|
6230
6238
|
return js_commands_default(this, "js");
|
|
@@ -6439,11 +6447,12 @@ var LiveSocket = class {
|
|
|
6439
6447
|
`[${this.binding("remove")}]`
|
|
6440
6448
|
).filter((el) => !dom_default.isChildOfAny(el, stickies));
|
|
6441
6449
|
const newMainEl = dom_default.cloneNode(this.outgoingMainEl, "");
|
|
6442
|
-
this.main
|
|
6443
|
-
this.
|
|
6450
|
+
const oldMainView = this.main;
|
|
6451
|
+
oldMainView.showLoader(this.loaderTimeout);
|
|
6452
|
+
oldMainView.destroy();
|
|
6444
6453
|
this.main = this.newRootView(newMainEl, flash, liveReferer);
|
|
6445
6454
|
this.main.setRedirect(href);
|
|
6446
|
-
this.transitionRemoves(removeEls);
|
|
6455
|
+
this.transitionRemoves(removeEls, oldMainView);
|
|
6447
6456
|
this.main.join((joinCount, onDone) => {
|
|
6448
6457
|
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
6449
6458
|
this.requestDOMUpdate(() => {
|
|
@@ -6458,7 +6467,7 @@ var LiveSocket = class {
|
|
|
6458
6467
|
});
|
|
6459
6468
|
}
|
|
6460
6469
|
/** @internal */
|
|
6461
|
-
transitionRemoves(elements, callback) {
|
|
6470
|
+
transitionRemoves(elements, view, callback) {
|
|
6462
6471
|
const removeAttr = this.binding("remove");
|
|
6463
6472
|
const silenceEvents = (e) => {
|
|
6464
6473
|
e.preventDefault();
|
|
@@ -6468,7 +6477,8 @@ var LiveSocket = class {
|
|
|
6468
6477
|
for (const event of this.boundEventNames) {
|
|
6469
6478
|
el.addEventListener(event, silenceEvents, true);
|
|
6470
6479
|
}
|
|
6471
|
-
|
|
6480
|
+
const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } });
|
|
6481
|
+
js_default.exec(e, "remove", el.getAttribute(removeAttr), view, el);
|
|
6472
6482
|
});
|
|
6473
6483
|
this.requestDOMUpdate(() => {
|
|
6474
6484
|
elements.forEach((el) => {
|
|
@@ -6494,7 +6504,7 @@ var LiveSocket = class {
|
|
|
6494
6504
|
let view;
|
|
6495
6505
|
const viewEl = dom_default.closestViewEl(childEl);
|
|
6496
6506
|
if (viewEl) {
|
|
6497
|
-
view =
|
|
6507
|
+
view = dom_default.private(viewEl, "view");
|
|
6498
6508
|
} else {
|
|
6499
6509
|
if (!childEl.isConnected) {
|
|
6500
6510
|
return null;
|