phoenix_live_view 1.0.9 → 1.0.10
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_patch.js +18 -15
- package/assets/js/phoenix_live_view/view.js +19 -9
- package/package.json +14 -14
- package/priv/static/phoenix_live_view.cjs.js +28 -24
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +28 -24
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +28 -24
- package/priv/static/phoenix_live_view.min.js +5 -5
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
detectInvalidStreamInserts,
|
|
22
22
|
isCid
|
|
23
23
|
} from "./utils"
|
|
24
|
-
|
|
24
|
+
import ElementRef from "./element_ref"
|
|
25
25
|
import DOM from "./dom"
|
|
26
26
|
import DOMPostMorphRestorer from "./dom_post_morph_restorer"
|
|
27
27
|
import morphdom from "morphdom"
|
|
@@ -217,20 +217,23 @@ export default class DOMPatch {
|
|
|
217
217
|
// apply any changes that happened while the element was locked.
|
|
218
218
|
let isFocusedFormEl = focused && fromEl.isSameNode(focused) && DOM.isFormInput(fromEl)
|
|
219
219
|
let focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
DOM.
|
|
232
|
-
if(
|
|
233
|
-
fromEl
|
|
220
|
+
if(fromEl.hasAttribute(PHX_REF_SRC)){
|
|
221
|
+
const ref = new ElementRef(fromEl)
|
|
222
|
+
// only perform the clone step if this is not a patch that unlocks
|
|
223
|
+
if(ref.lockRef && (!this.undoRef || !ref.isLockUndoneBy(this.undoRef))){
|
|
224
|
+
if(DOM.isUploadInput(fromEl)){
|
|
225
|
+
DOM.mergeAttrs(fromEl, toEl, {isIgnored: true})
|
|
226
|
+
this.trackBefore("updated", fromEl, toEl)
|
|
227
|
+
updates.push(fromEl)
|
|
228
|
+
}
|
|
229
|
+
DOM.applyStickyOperations(fromEl)
|
|
230
|
+
let isLocked = fromEl.hasAttribute(PHX_REF_LOCK)
|
|
231
|
+
let clone = isLocked ? DOM.private(fromEl, PHX_REF_LOCK) || fromEl.cloneNode(true) : null
|
|
232
|
+
if(clone){
|
|
233
|
+
DOM.putPrivate(fromEl, PHX_REF_LOCK, clone)
|
|
234
|
+
if(!isFocusedFormEl){
|
|
235
|
+
fromEl = clone
|
|
236
|
+
}
|
|
234
237
|
}
|
|
235
238
|
}
|
|
236
239
|
}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
PHX_ROOT_ID,
|
|
25
25
|
PHX_SESSION,
|
|
26
26
|
PHX_STATIC,
|
|
27
|
+
PHX_STICKY,
|
|
27
28
|
PHX_TRACK_STATIC,
|
|
28
29
|
PHX_TRACK_UPLOADS,
|
|
29
30
|
PHX_UPDATE,
|
|
@@ -181,6 +182,7 @@ export default class View {
|
|
|
181
182
|
session: this.getSession(),
|
|
182
183
|
static: this.getStatic(),
|
|
183
184
|
flash: this.flash,
|
|
185
|
+
sticky: this.el.hasAttribute(PHX_STICKY)
|
|
184
186
|
}
|
|
185
187
|
})
|
|
186
188
|
}
|
|
@@ -850,7 +852,7 @@ export default class View {
|
|
|
850
852
|
return
|
|
851
853
|
} else if(resp.reason === "unauthorized" || resp.reason === "stale"){
|
|
852
854
|
this.log("error", () => ["unauthorized live_redirect. Falling back to page request", resp])
|
|
853
|
-
this.onRedirect({to: this.root.href})
|
|
855
|
+
this.onRedirect({to: this.root.href, flash: this.flash})
|
|
854
856
|
return
|
|
855
857
|
}
|
|
856
858
|
if(resp.redirect || resp.live_redirect){
|
|
@@ -1168,7 +1170,9 @@ export default class View {
|
|
|
1168
1170
|
event: phxEvent,
|
|
1169
1171
|
value: this.extractMeta(el, meta, opts.value),
|
|
1170
1172
|
cid: this.targetComponentID(el, targetCtx, opts)
|
|
1171
|
-
})
|
|
1173
|
+
})
|
|
1174
|
+
.then(({reply}) => onReply && onReply(reply))
|
|
1175
|
+
.catch((error) => logError("Failed to push event", error))
|
|
1172
1176
|
}
|
|
1173
1177
|
|
|
1174
1178
|
pushFileProgress(fileEl, entryRef, progress, onReply = function (){ }){
|
|
@@ -1179,7 +1183,9 @@ export default class View {
|
|
|
1179
1183
|
entry_ref: entryRef,
|
|
1180
1184
|
progress: progress,
|
|
1181
1185
|
cid: view.targetComponentID(fileEl.form, targetCtx)
|
|
1182
|
-
})
|
|
1186
|
+
})
|
|
1187
|
+
.then(({resp}) => onReply(resp))
|
|
1188
|
+
.catch((error) => logError("Failed to push file progress", error))
|
|
1183
1189
|
})
|
|
1184
1190
|
}
|
|
1185
1191
|
|
|
@@ -1244,7 +1250,7 @@ export default class View {
|
|
|
1244
1250
|
} else {
|
|
1245
1251
|
callback && callback(resp)
|
|
1246
1252
|
}
|
|
1247
|
-
})
|
|
1253
|
+
}).catch((error) => logError("Failed to push input event", error))
|
|
1248
1254
|
}
|
|
1249
1255
|
|
|
1250
1256
|
triggerAwaitingSubmit(formEl, phxEvent){
|
|
@@ -1343,7 +1349,9 @@ export default class View {
|
|
|
1343
1349
|
value: formData,
|
|
1344
1350
|
meta: meta,
|
|
1345
1351
|
cid: cid
|
|
1346
|
-
})
|
|
1352
|
+
})
|
|
1353
|
+
.then(({resp}) => onReply(resp))
|
|
1354
|
+
.catch((error) => logError("Failed to push form submit", error))
|
|
1347
1355
|
})
|
|
1348
1356
|
} else if(!(formEl.hasAttribute(PHX_REF_SRC) && formEl.classList.contains("phx-submit-loading"))){
|
|
1349
1357
|
let meta = this.extractMeta(formEl, {}, opts.value)
|
|
@@ -1354,7 +1362,9 @@ export default class View {
|
|
|
1354
1362
|
value: formData,
|
|
1355
1363
|
meta: meta,
|
|
1356
1364
|
cid: cid
|
|
1357
|
-
})
|
|
1365
|
+
})
|
|
1366
|
+
.then(({resp}) => onReply(resp))
|
|
1367
|
+
.catch((error) => logError("Failed to push form submit", error))
|
|
1358
1368
|
}
|
|
1359
1369
|
}
|
|
1360
1370
|
|
|
@@ -1410,7 +1420,7 @@ export default class View {
|
|
|
1410
1420
|
}
|
|
1411
1421
|
uploader.initAdapterUpload(resp, onError, this.liveSocket)
|
|
1412
1422
|
}
|
|
1413
|
-
})
|
|
1423
|
+
}).catch((error) => logError("Failed to push upload", error))
|
|
1414
1424
|
})
|
|
1415
1425
|
}
|
|
1416
1426
|
|
|
@@ -1546,10 +1556,10 @@ export default class View {
|
|
|
1546
1556
|
if(completelyDestroyCIDs.length > 0){
|
|
1547
1557
|
this.pushWithReply(null, "cids_destroyed", {cids: completelyDestroyCIDs}).then(({resp}) => {
|
|
1548
1558
|
this.rendered.pruneCIDs(resp.cids)
|
|
1549
|
-
})
|
|
1559
|
+
}).catch((error) => logError("Failed to push components destroyed", error))
|
|
1550
1560
|
}
|
|
1551
1561
|
})
|
|
1552
|
-
})
|
|
1562
|
+
}).catch((error) => logError("Failed to push components destroyed", error))
|
|
1553
1563
|
}
|
|
1554
1564
|
}
|
|
1555
1565
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phoenix_live_view",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "The Phoenix LiveView JavaScript client.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "./priv/static/phoenix_live_view.esm.js",
|
|
@@ -24,25 +24,25 @@
|
|
|
24
24
|
"assets/js/phoenix_live_view/*"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"morphdom": "2.7.
|
|
27
|
+
"morphdom": "2.7.5"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@babel/cli": "7.
|
|
31
|
-
"@babel/core": "7.26.
|
|
32
|
-
"@babel/preset-env": "7.26.
|
|
33
|
-
"@eslint/js": "^9.
|
|
34
|
-
"@playwright/test": "^1.
|
|
35
|
-
"@stylistic/eslint-plugin-js": "^2.
|
|
30
|
+
"@babel/cli": "7.27.0",
|
|
31
|
+
"@babel/core": "7.26.10",
|
|
32
|
+
"@babel/preset-env": "7.26.9",
|
|
33
|
+
"@eslint/js": "^9.24.0",
|
|
34
|
+
"@playwright/test": "^1.51.1",
|
|
35
|
+
"@stylistic/eslint-plugin-js": "^4.2.0",
|
|
36
36
|
"css.escape": "^1.5.1",
|
|
37
|
-
"eslint": "9.
|
|
38
|
-
"eslint-plugin-jest": "28.
|
|
39
|
-
"eslint-plugin-playwright": "^2.
|
|
40
|
-
"globals": "^
|
|
37
|
+
"eslint": "9.24.0",
|
|
38
|
+
"eslint-plugin-jest": "28.11.0",
|
|
39
|
+
"eslint-plugin-playwright": "^2.2.0",
|
|
40
|
+
"globals": "^16.0.0",
|
|
41
41
|
"jest": "^29.7.0",
|
|
42
42
|
"jest-environment-jsdom": "^29.7.0",
|
|
43
43
|
"jest-monocart-coverage": "^1.1.1",
|
|
44
|
-
"monocart-reporter": "^2.9.
|
|
45
|
-
"phoenix": "1.7.
|
|
44
|
+
"monocart-reporter": "^2.9.17",
|
|
45
|
+
"phoenix": "1.7.21"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"setup": "mix deps.get && npm install",
|
|
@@ -2164,19 +2164,22 @@ var DOMPatch = class {
|
|
|
2164
2164
|
}
|
|
2165
2165
|
let isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl);
|
|
2166
2166
|
let focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl);
|
|
2167
|
-
if (fromEl.hasAttribute(PHX_REF_SRC)
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
dom_default.
|
|
2178
|
-
if (
|
|
2179
|
-
fromEl
|
|
2167
|
+
if (fromEl.hasAttribute(PHX_REF_SRC)) {
|
|
2168
|
+
const ref = new ElementRef(fromEl);
|
|
2169
|
+
if (ref.lockRef && (!this.undoRef || !ref.isLockUndoneBy(this.undoRef))) {
|
|
2170
|
+
if (dom_default.isUploadInput(fromEl)) {
|
|
2171
|
+
dom_default.mergeAttrs(fromEl, toEl, { isIgnored: true });
|
|
2172
|
+
this.trackBefore("updated", fromEl, toEl);
|
|
2173
|
+
updates.push(fromEl);
|
|
2174
|
+
}
|
|
2175
|
+
dom_default.applyStickyOperations(fromEl);
|
|
2176
|
+
let isLocked = fromEl.hasAttribute(PHX_REF_LOCK);
|
|
2177
|
+
let clone2 = isLocked ? dom_default.private(fromEl, PHX_REF_LOCK) || fromEl.cloneNode(true) : null;
|
|
2178
|
+
if (clone2) {
|
|
2179
|
+
dom_default.putPrivate(fromEl, PHX_REF_LOCK, clone2);
|
|
2180
|
+
if (!isFocusedFormEl) {
|
|
2181
|
+
fromEl = clone2;
|
|
2182
|
+
}
|
|
2180
2183
|
}
|
|
2181
2184
|
}
|
|
2182
2185
|
}
|
|
@@ -3463,7 +3466,8 @@ var View = class _View {
|
|
|
3463
3466
|
params: this.connectParams(liveReferer),
|
|
3464
3467
|
session: this.getSession(),
|
|
3465
3468
|
static: this.getStatic(),
|
|
3466
|
-
flash: this.flash
|
|
3469
|
+
flash: this.flash,
|
|
3470
|
+
sticky: this.el.hasAttribute(PHX_STICKY)
|
|
3467
3471
|
};
|
|
3468
3472
|
});
|
|
3469
3473
|
}
|
|
@@ -4052,7 +4056,7 @@ var View = class _View {
|
|
|
4052
4056
|
return;
|
|
4053
4057
|
} else if (resp.reason === "unauthorized" || resp.reason === "stale") {
|
|
4054
4058
|
this.log("error", () => ["unauthorized live_redirect. Falling back to page request", resp]);
|
|
4055
|
-
this.onRedirect({ to: this.root.href });
|
|
4059
|
+
this.onRedirect({ to: this.root.href, flash: this.flash });
|
|
4056
4060
|
return;
|
|
4057
4061
|
}
|
|
4058
4062
|
if (resp.redirect || resp.live_redirect) {
|
|
@@ -4390,7 +4394,7 @@ var View = class _View {
|
|
|
4390
4394
|
event: phxEvent,
|
|
4391
4395
|
value: this.extractMeta(el, meta, opts.value),
|
|
4392
4396
|
cid: this.targetComponentID(el, targetCtx, opts)
|
|
4393
|
-
}).then(({ reply }) => onReply && onReply(reply));
|
|
4397
|
+
}).then(({ reply }) => onReply && onReply(reply)).catch((error) => logError("Failed to push event", error));
|
|
4394
4398
|
}
|
|
4395
4399
|
pushFileProgress(fileEl, entryRef, progress, onReply = function() {
|
|
4396
4400
|
}) {
|
|
@@ -4401,7 +4405,7 @@ var View = class _View {
|
|
|
4401
4405
|
entry_ref: entryRef,
|
|
4402
4406
|
progress,
|
|
4403
4407
|
cid: view.targetComponentID(fileEl.form, targetCtx)
|
|
4404
|
-
}).then(({ resp }) => onReply(resp));
|
|
4408
|
+
}).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push file progress", error));
|
|
4405
4409
|
});
|
|
4406
4410
|
}
|
|
4407
4411
|
pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback) {
|
|
@@ -4462,7 +4466,7 @@ var View = class _View {
|
|
|
4462
4466
|
} else {
|
|
4463
4467
|
callback && callback(resp);
|
|
4464
4468
|
}
|
|
4465
|
-
});
|
|
4469
|
+
}).catch((error) => logError("Failed to push input event", error));
|
|
4466
4470
|
}
|
|
4467
4471
|
triggerAwaitingSubmit(formEl, phxEvent) {
|
|
4468
4472
|
let awaitingSubmit = this.getScheduledSubmit(formEl);
|
|
@@ -4549,7 +4553,7 @@ var View = class _View {
|
|
|
4549
4553
|
value: formData,
|
|
4550
4554
|
meta,
|
|
4551
4555
|
cid
|
|
4552
|
-
}).then(({ resp }) => onReply(resp));
|
|
4556
|
+
}).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push form submit", error));
|
|
4553
4557
|
});
|
|
4554
4558
|
} else if (!(formEl.hasAttribute(PHX_REF_SRC) && formEl.classList.contains("phx-submit-loading"))) {
|
|
4555
4559
|
let meta = this.extractMeta(formEl, {}, opts.value);
|
|
@@ -4560,7 +4564,7 @@ var View = class _View {
|
|
|
4560
4564
|
value: formData,
|
|
4561
4565
|
meta,
|
|
4562
4566
|
cid
|
|
4563
|
-
}).then(({ resp }) => onReply(resp));
|
|
4567
|
+
}).then(({ resp }) => onReply(resp)).catch((error) => logError("Failed to push form submit", error));
|
|
4564
4568
|
}
|
|
4565
4569
|
}
|
|
4566
4570
|
uploadFiles(formEl, phxEvent, targetCtx, ref, cid, onComplete) {
|
|
@@ -4608,7 +4612,7 @@ var View = class _View {
|
|
|
4608
4612
|
};
|
|
4609
4613
|
uploader.initAdapterUpload(resp, onError, this.liveSocket);
|
|
4610
4614
|
}
|
|
4611
|
-
});
|
|
4615
|
+
}).catch((error) => logError("Failed to push upload", error));
|
|
4612
4616
|
});
|
|
4613
4617
|
}
|
|
4614
4618
|
handleFailedEntryPreflight(uploadRef, reason, uploader) {
|
|
@@ -4719,10 +4723,10 @@ var View = class _View {
|
|
|
4719
4723
|
if (completelyDestroyCIDs.length > 0) {
|
|
4720
4724
|
this.pushWithReply(null, "cids_destroyed", { cids: completelyDestroyCIDs }).then(({ resp }) => {
|
|
4721
4725
|
this.rendered.pruneCIDs(resp.cids);
|
|
4722
|
-
});
|
|
4726
|
+
}).catch((error) => logError("Failed to push components destroyed", error));
|
|
4723
4727
|
}
|
|
4724
4728
|
});
|
|
4725
|
-
});
|
|
4729
|
+
}).catch((error) => logError("Failed to push components destroyed", error));
|
|
4726
4730
|
}
|
|
4727
4731
|
}
|
|
4728
4732
|
ownsElement(el) {
|
|
@@ -4812,7 +4816,7 @@ var LiveSocket = class {
|
|
|
4812
4816
|
}
|
|
4813
4817
|
// public
|
|
4814
4818
|
version() {
|
|
4815
|
-
return "1.0.
|
|
4819
|
+
return "1.0.10";
|
|
4816
4820
|
}
|
|
4817
4821
|
isProfileEnabled() {
|
|
4818
4822
|
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
|