phoenix_live_view 1.1.31 → 1.1.32
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/assets/js/phoenix_live_view/dom.js +3 -1
- package/assets/js/phoenix_live_view/dom_patch.js +1 -1
- package/assets/js/phoenix_live_view/live_socket.js +15 -8
- package/assets/js/phoenix_live_view/utils.js +1 -4
- package/assets/js/phoenix_live_view/view.js +4 -0
- package/assets/js/types/live_socket.d.ts +1 -1
- package/package.json +2 -2
- package/priv/static/phoenix_live_view.cjs.js +16 -9
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +16 -9
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +16 -9
- package/priv/static/phoenix_live_view.min.js +5 -5
|
@@ -370,7 +370,9 @@ const DOM = {
|
|
|
370
370
|
// we also clear the throttle timeout to prevent the callback
|
|
371
371
|
// from being called again after the timeout fires
|
|
372
372
|
clearTimeout(this.private(el, THROTTLED));
|
|
373
|
-
|
|
373
|
+
if (asyncFilter()) {
|
|
374
|
+
this.triggerCycle(el, DEBOUNCE_TRIGGER);
|
|
375
|
+
}
|
|
374
376
|
});
|
|
375
377
|
}
|
|
376
378
|
}
|
|
@@ -711,7 +711,7 @@ export default class DOMPatch {
|
|
|
711
711
|
transitionPendingRemoves() {
|
|
712
712
|
const { pendingRemoves, liveSocket } = this;
|
|
713
713
|
if (pendingRemoves.length > 0) {
|
|
714
|
-
liveSocket.transitionRemoves(pendingRemoves, () => {
|
|
714
|
+
liveSocket.transitionRemoves(pendingRemoves, this.view, () => {
|
|
715
715
|
pendingRemoves.forEach((el) => {
|
|
716
716
|
const child = DOM.firstPhxChild(el);
|
|
717
717
|
if (child) {
|
|
@@ -472,12 +472,15 @@ export default class LiveSocket {
|
|
|
472
472
|
).filter((el) => !DOM.isChildOfAny(el, stickies));
|
|
473
473
|
|
|
474
474
|
const newMainEl = DOM.cloneNode(this.outgoingMainEl, "");
|
|
475
|
-
this.main
|
|
476
|
-
this.
|
|
475
|
+
const oldMainView = this.main;
|
|
476
|
+
oldMainView.showLoader(this.loaderTimeout);
|
|
477
|
+
oldMainView.destroy();
|
|
477
478
|
|
|
478
479
|
this.main = this.newRootView(newMainEl, flash, liveReferer);
|
|
479
480
|
this.main.setRedirect(href);
|
|
480
|
-
this
|
|
481
|
+
// the old view is destroyed at this point; pass it explicitly so the
|
|
482
|
+
// phx-remove commands execute in the context of the outgoing view
|
|
483
|
+
this.transitionRemoves(removeEls, oldMainView);
|
|
481
484
|
this.main.join((joinCount, onDone) => {
|
|
482
485
|
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
483
486
|
this.requestDOMUpdate(() => {
|
|
@@ -493,7 +496,7 @@ export default class LiveSocket {
|
|
|
493
496
|
});
|
|
494
497
|
}
|
|
495
498
|
|
|
496
|
-
transitionRemoves(elements, callback) {
|
|
499
|
+
transitionRemoves(elements, view, callback) {
|
|
497
500
|
const removeAttr = this.binding("remove");
|
|
498
501
|
const silenceEvents = (e) => {
|
|
499
502
|
e.preventDefault();
|
|
@@ -505,7 +508,8 @@ export default class LiveSocket {
|
|
|
505
508
|
for (const event of this.boundEventNames) {
|
|
506
509
|
el.addEventListener(event, silenceEvents, true);
|
|
507
510
|
}
|
|
508
|
-
|
|
511
|
+
const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } });
|
|
512
|
+
JS.exec(e, "remove", el.getAttribute(removeAttr), view, el);
|
|
509
513
|
});
|
|
510
514
|
// remove the silenced listeners when transitions are done incase the element is re-used
|
|
511
515
|
// and call caller's callback as soon as we are done with transitions
|
|
@@ -533,9 +537,12 @@ export default class LiveSocket {
|
|
|
533
537
|
let view;
|
|
534
538
|
const viewEl = DOM.closestViewEl(childEl);
|
|
535
539
|
if (viewEl) {
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
|
|
540
|
+
// resolve the view by element identity instead of id; during live
|
|
541
|
+
// navigation the new view is registered under the same id while the
|
|
542
|
+
// old DOM is still attached, and events from the old DOM must not be
|
|
543
|
+
// routed to the new view. A destroyed view removes its element binding,
|
|
544
|
+
// in which case we DO NOT want to fallback to the main element
|
|
545
|
+
view = DOM.private(viewEl, "view");
|
|
539
546
|
} else {
|
|
540
547
|
if (!childEl.isConnected) {
|
|
541
548
|
// if the element is not part of the DOM any more
|
|
@@ -8,10 +8,7 @@ export const logError = (msg, obj) => console.error && console.error(msg, obj);
|
|
|
8
8
|
// target over the existing socket. A full URL to a different origin (or a
|
|
9
9
|
// non-http(s) scheme, which resolves to an opaque "null" origin) is a
|
|
10
10
|
// programming error, so we fail loudly instead of attempting a broken join.
|
|
11
|
-
export const ensureSameOrigin = (
|
|
12
|
-
href,
|
|
13
|
-
kind,
|
|
14
|
-
) => {
|
|
11
|
+
export const ensureSameOrigin = (href, kind) => {
|
|
15
12
|
let url;
|
|
16
13
|
try {
|
|
17
14
|
url = new URL(href, window.location.href);
|
|
@@ -443,6 +443,7 @@ export default class View {
|
|
|
443
443
|
if (container) {
|
|
444
444
|
const [tag, attrs] = container;
|
|
445
445
|
this.el = DOM.replaceRootContainer(this.el, tag, attrs);
|
|
446
|
+
DOM.putPrivate(this.el, "view", this);
|
|
446
447
|
}
|
|
447
448
|
this.childJoins = 0;
|
|
448
449
|
this.joinPending = true;
|
|
@@ -548,6 +549,7 @@ export default class View {
|
|
|
548
549
|
|
|
549
550
|
attachTrueDocEl() {
|
|
550
551
|
this.el = DOM.byId(this.id);
|
|
552
|
+
DOM.putPrivate(this.el, "view", this);
|
|
551
553
|
this.el.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
552
554
|
}
|
|
553
555
|
|
|
@@ -770,6 +772,7 @@ export default class View {
|
|
|
770
772
|
});
|
|
771
773
|
|
|
772
774
|
// because we work with a template element, we must manually copy the attributes
|
|
775
|
+
// and bind the template root to this view,
|
|
773
776
|
// otherwise the owner / target helpers don't work properly
|
|
774
777
|
const rootEl = template.content.firstElementChild;
|
|
775
778
|
rootEl.id = this.id;
|
|
@@ -777,6 +780,7 @@ export default class View {
|
|
|
777
780
|
rootEl.setAttribute(PHX_SESSION, this.getSession());
|
|
778
781
|
rootEl.setAttribute(PHX_STATIC, this.getStatic());
|
|
779
782
|
rootEl.setAttribute(PHX_PARENT_ID, this.parent ? this.parent.id : null);
|
|
783
|
+
DOM.putPrivate(rootEl, "view", this);
|
|
780
784
|
|
|
781
785
|
// we go over all form elements in the new HTML for the LV
|
|
782
786
|
// and look for old forms in the `formsForRecovery` object;
|
|
@@ -89,7 +89,7 @@ export default class LiveSocket {
|
|
|
89
89
|
joinRootViews(): boolean;
|
|
90
90
|
redirect(to: any, flash: any, reloadToken: any): void;
|
|
91
91
|
replaceMain(href: any, flash: any, callback?: any, linkRef?: number): void;
|
|
92
|
-
transitionRemoves(elements: any, callback: any): void;
|
|
92
|
+
transitionRemoves(elements: any, view: any, callback: any): void;
|
|
93
93
|
isPhxView(el: any): boolean;
|
|
94
94
|
newRootView(el: any, flash: any, liveReferer: any): View;
|
|
95
95
|
owner(childEl: any, callback: any): any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phoenix_live_view",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.32",
|
|
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",
|
|
@@ -650,7 +650,9 @@ var DOM = {
|
|
|
650
650
|
if (this.once(el, "bind-debounce")) {
|
|
651
651
|
el.addEventListener("blur", () => {
|
|
652
652
|
clearTimeout(this.private(el, THROTTLED));
|
|
653
|
-
|
|
653
|
+
if (asyncFilter()) {
|
|
654
|
+
this.triggerCycle(el, DEBOUNCE_TRIGGER);
|
|
655
|
+
}
|
|
654
656
|
});
|
|
655
657
|
}
|
|
656
658
|
}
|
|
@@ -2756,7 +2758,7 @@ var DOMPatch = class {
|
|
|
2756
2758
|
transitionPendingRemoves() {
|
|
2757
2759
|
const { pendingRemoves, liveSocket } = this;
|
|
2758
2760
|
if (pendingRemoves.length > 0) {
|
|
2759
|
-
liveSocket.transitionRemoves(pendingRemoves, () => {
|
|
2761
|
+
liveSocket.transitionRemoves(pendingRemoves, this.view, () => {
|
|
2760
2762
|
pendingRemoves.forEach((el) => {
|
|
2761
2763
|
const child = dom_default.firstPhxChild(el);
|
|
2762
2764
|
if (child) {
|
|
@@ -4448,6 +4450,7 @@ var View = class _View {
|
|
|
4448
4450
|
if (container) {
|
|
4449
4451
|
const [tag, attrs] = container;
|
|
4450
4452
|
this.el = dom_default.replaceRootContainer(this.el, tag, attrs);
|
|
4453
|
+
dom_default.putPrivate(this.el, "view", this);
|
|
4451
4454
|
}
|
|
4452
4455
|
this.childJoins = 0;
|
|
4453
4456
|
this.joinPending = true;
|
|
@@ -4530,6 +4533,7 @@ var View = class _View {
|
|
|
4530
4533
|
}
|
|
4531
4534
|
attachTrueDocEl() {
|
|
4532
4535
|
this.el = dom_default.byId(this.id);
|
|
4536
|
+
dom_default.putPrivate(this.el, "view", this);
|
|
4533
4537
|
this.el.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
4534
4538
|
}
|
|
4535
4539
|
// this is invoked for dead and live views, so we must filter by
|
|
@@ -4713,6 +4717,7 @@ var View = class _View {
|
|
|
4713
4717
|
rootEl.setAttribute(PHX_SESSION, this.getSession());
|
|
4714
4718
|
rootEl.setAttribute(PHX_STATIC, this.getStatic());
|
|
4715
4719
|
rootEl.setAttribute(PHX_PARENT_ID, this.parent ? this.parent.id : null);
|
|
4720
|
+
dom_default.putPrivate(rootEl, "view", this);
|
|
4716
4721
|
const formsToRecover = (
|
|
4717
4722
|
// we go over all forms in the new DOM; because this is only the HTML for the current
|
|
4718
4723
|
// view, we can be sure that all forms are owned by this view:
|
|
@@ -5993,7 +5998,7 @@ var LiveSocket = class {
|
|
|
5993
5998
|
}
|
|
5994
5999
|
// public
|
|
5995
6000
|
version() {
|
|
5996
|
-
return "1.1.
|
|
6001
|
+
return "1.1.32";
|
|
5997
6002
|
}
|
|
5998
6003
|
isProfileEnabled() {
|
|
5999
6004
|
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
|
|
@@ -6272,11 +6277,12 @@ var LiveSocket = class {
|
|
|
6272
6277
|
`[${this.binding("remove")}]`
|
|
6273
6278
|
).filter((el) => !dom_default.isChildOfAny(el, stickies));
|
|
6274
6279
|
const newMainEl = dom_default.cloneNode(this.outgoingMainEl, "");
|
|
6275
|
-
this.main
|
|
6276
|
-
this.
|
|
6280
|
+
const oldMainView = this.main;
|
|
6281
|
+
oldMainView.showLoader(this.loaderTimeout);
|
|
6282
|
+
oldMainView.destroy();
|
|
6277
6283
|
this.main = this.newRootView(newMainEl, flash, liveReferer);
|
|
6278
6284
|
this.main.setRedirect(href);
|
|
6279
|
-
this.transitionRemoves(removeEls);
|
|
6285
|
+
this.transitionRemoves(removeEls, oldMainView);
|
|
6280
6286
|
this.main.join((joinCount, onDone) => {
|
|
6281
6287
|
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
6282
6288
|
this.requestDOMUpdate(() => {
|
|
@@ -6290,7 +6296,7 @@ var LiveSocket = class {
|
|
|
6290
6296
|
}
|
|
6291
6297
|
});
|
|
6292
6298
|
}
|
|
6293
|
-
transitionRemoves(elements, callback) {
|
|
6299
|
+
transitionRemoves(elements, view, callback) {
|
|
6294
6300
|
const removeAttr = this.binding("remove");
|
|
6295
6301
|
const silenceEvents = (e) => {
|
|
6296
6302
|
e.preventDefault();
|
|
@@ -6300,7 +6306,8 @@ var LiveSocket = class {
|
|
|
6300
6306
|
for (const event of this.boundEventNames) {
|
|
6301
6307
|
el.addEventListener(event, silenceEvents, true);
|
|
6302
6308
|
}
|
|
6303
|
-
|
|
6309
|
+
const e = new CustomEvent("phx:exec", { detail: { sourceElement: el } });
|
|
6310
|
+
js_default.exec(e, "remove", el.getAttribute(removeAttr), view, el);
|
|
6304
6311
|
});
|
|
6305
6312
|
this.requestDOMUpdate(() => {
|
|
6306
6313
|
elements.forEach((el) => {
|
|
@@ -6323,7 +6330,7 @@ var LiveSocket = class {
|
|
|
6323
6330
|
let view;
|
|
6324
6331
|
const viewEl = dom_default.closestViewEl(childEl);
|
|
6325
6332
|
if (viewEl) {
|
|
6326
|
-
view =
|
|
6333
|
+
view = dom_default.private(viewEl, "view");
|
|
6327
6334
|
} else {
|
|
6328
6335
|
if (!childEl.isConnected) {
|
|
6329
6336
|
return null;
|