phoenix_live_view 0.18.15 → 0.18.17
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 +3 -0
- package/assets/js/phoenix_live_view/dom_patch.js +6 -6
- package/assets/js/phoenix_live_view/js.js +2 -1
- package/assets/js/phoenix_live_view/live_socket.js +1 -1
- package/assets/js/phoenix_live_view/view.js +21 -8
- package/assets/package.json +1 -1
- package/package.json +1 -1
- package/priv/static/phoenix_live_view.cjs.js +19 -16
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +19 -16
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +31 -16
- package/priv/static/phoenix_live_view.min.js +6 -6
- package/priv/static/phoenix_live_view.js.map +0 -7
package/README.md
CHANGED
|
@@ -134,6 +134,8 @@ $ npm install --save --prefix assets mdn-polyfills url-search-params-polyfill fo
|
|
|
134
134
|
|
|
135
135
|
Note: The `shim-keyboard-event-key` polyfill is also required for [MS Edge 12-18](https://caniuse.com/#feat=keyboardevent-key).
|
|
136
136
|
|
|
137
|
+
Note: The `event-submitter-polyfill` package is also required for [MS Edge 12-80 & Safari < 15.4](https://caniuse.com/mdn-api_submitevent_submitter).
|
|
138
|
+
|
|
137
139
|
```
|
|
138
140
|
// assets/js/app.js
|
|
139
141
|
import "mdn-polyfills/Object.assign"
|
|
@@ -153,6 +155,7 @@ import "classlist-polyfill"
|
|
|
153
155
|
import "new-event-polyfill"
|
|
154
156
|
import "@webcomponents/template"
|
|
155
157
|
import "shim-keyboard-event-key"
|
|
158
|
+
import "event-submitter-polyfill"
|
|
156
159
|
import "core-js/features/set"
|
|
157
160
|
import "core-js/features/url"
|
|
158
161
|
|
|
@@ -98,7 +98,6 @@ export default class DOMPatch {
|
|
|
98
98
|
this.trackBefore("updated", container, container)
|
|
99
99
|
|
|
100
100
|
liveSocket.time("morphdom", () => {
|
|
101
|
-
|
|
102
101
|
this.streams.forEach(([inserts, deleteIds]) => {
|
|
103
102
|
this.streamInserts = Object.assign(this.streamInserts, inserts)
|
|
104
103
|
deleteIds.forEach(id => {
|
|
@@ -124,8 +123,7 @@ export default class DOMPatch {
|
|
|
124
123
|
let streamAt = child.id ? this.streamInserts[child.id] : undefined
|
|
125
124
|
if(streamAt === undefined) { return parent.appendChild(child) }
|
|
126
125
|
|
|
127
|
-
//streaming
|
|
128
|
-
DOM.putPrivate(child, PHX_STREAM, true)
|
|
126
|
+
// streaming
|
|
129
127
|
if(streamAt === 0){
|
|
130
128
|
parent.insertAdjacentElement("afterbegin", child)
|
|
131
129
|
} else if(streamAt === -1){
|
|
@@ -160,10 +158,13 @@ export default class DOMPatch {
|
|
|
160
158
|
onNodeDiscarded: (el) => this.onNodeDiscarded(el),
|
|
161
159
|
onBeforeNodeDiscarded: (el) => {
|
|
162
160
|
if(el.getAttribute && el.getAttribute(PHX_PRUNE) !== null){ return true }
|
|
163
|
-
if(
|
|
164
|
-
|
|
161
|
+
if(el.parentElement !== null && el.id &&
|
|
162
|
+
DOM.isPhxUpdate(el.parentElement, phxUpdate, [PHX_STREAM, "append", "prepend"])){
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
165
|
if(this.maybePendingRemove(el)){ return false }
|
|
166
166
|
if(this.skipCIDSibling(el)){ return false }
|
|
167
|
+
|
|
167
168
|
return true
|
|
168
169
|
},
|
|
169
170
|
onElUpdated: (el) => {
|
|
@@ -270,7 +271,6 @@ export default class DOMPatch {
|
|
|
270
271
|
let streamAt = el.id ? this.streamInserts[el.id] : undefined
|
|
271
272
|
if(streamAt === undefined){ return }
|
|
272
273
|
|
|
273
|
-
DOM.putPrivate(el, PHX_STREAM, true)
|
|
274
274
|
if(streamAt === 0){
|
|
275
275
|
el.parentElement.insertBefore(el, el.parentElement.firstElementChild)
|
|
276
276
|
} else if(streamAt > 0){
|
|
@@ -47,7 +47,8 @@ let JS = {
|
|
|
47
47
|
if(_target){ pushOpts._target = _target }
|
|
48
48
|
targetView.pushInput(sourceEl, targetCtx, newCid, event || phxEvent, pushOpts, callback)
|
|
49
49
|
} else if(eventType === "submit"){
|
|
50
|
-
|
|
50
|
+
let {submitter} = args
|
|
51
|
+
targetView.submitForm(sourceEl, targetCtx, event || phxEvent, submitter, pushOpts)
|
|
51
52
|
} else {
|
|
52
53
|
targetView.pushEvent(eventType, sourceEl, targetCtx, event || phxEvent, data, pushOpts)
|
|
53
54
|
}
|
|
@@ -822,7 +822,7 @@ export default class LiveSocket {
|
|
|
822
822
|
e.preventDefault()
|
|
823
823
|
e.target.disabled = true
|
|
824
824
|
this.withinOwners(e.target, view => {
|
|
825
|
-
JS.exec("submit", phxEvent, view, e.target, ["push", {}])
|
|
825
|
+
JS.exec("submit", phxEvent, view, e.target, ["push", {submitter: e.submitter}])
|
|
826
826
|
})
|
|
827
827
|
}, false)
|
|
828
828
|
|
|
@@ -51,8 +51,18 @@ import Rendered from "./rendered"
|
|
|
51
51
|
import ViewHook from "./view_hook"
|
|
52
52
|
import JS from "./js"
|
|
53
53
|
|
|
54
|
-
let serializeForm = (form,
|
|
54
|
+
let serializeForm = (form, metadata, onlyNames = []) => {
|
|
55
|
+
let {submitter, ...meta} = metadata
|
|
56
|
+
|
|
57
|
+
// TODO: Replace with `new FormData(form, submitter)` when supported by latest browsers,
|
|
58
|
+
// and mention `formdata-submitter-polyfill` in the docs.
|
|
55
59
|
let formData = new FormData(form)
|
|
60
|
+
|
|
61
|
+
// TODO: Remove when FormData constructor supports the submitter argument.
|
|
62
|
+
if (submitter && submitter.form && submitter.form === form){
|
|
63
|
+
formData.append(submitter.name, submitter.value)
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
let toRemove = []
|
|
57
67
|
|
|
58
68
|
formData.forEach((val, key, _index) => {
|
|
@@ -632,7 +642,10 @@ export default class View {
|
|
|
632
642
|
}
|
|
633
643
|
|
|
634
644
|
onJoinError(resp){
|
|
635
|
-
if(resp.reason === "
|
|
645
|
+
if(resp.reason === "reload"){
|
|
646
|
+
this.log("error", () => [`failed mount with ${resp.status}. Falling back to page request`, resp])
|
|
647
|
+
return this.onRedirect({to: this.href})
|
|
648
|
+
} else if(resp.reason === "unauthorized" || resp.reason === "stale"){
|
|
636
649
|
this.log("error", () => ["unauthorized live_redirect. Falling back to page request", resp])
|
|
637
650
|
return this.onRedirect({to: this.href})
|
|
638
651
|
}
|
|
@@ -951,18 +964,18 @@ export default class View {
|
|
|
951
964
|
return this.putRef([formEl].concat(disables).concat(buttons).concat(inputs), "submit", opts)
|
|
952
965
|
}
|
|
953
966
|
|
|
954
|
-
pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply){
|
|
967
|
+
pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply){
|
|
955
968
|
let refGenerator = () => this.disableForm(formEl, opts)
|
|
956
969
|
let cid = this.targetComponentID(formEl, targetCtx)
|
|
957
970
|
if(LiveUploader.hasUploadsInProgress(formEl)){
|
|
958
971
|
let [ref, _els] = refGenerator()
|
|
959
|
-
let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply)
|
|
972
|
+
let push = () => this.pushFormSubmit(formEl, submitter, targetCtx, phxEvent, opts, onReply)
|
|
960
973
|
return this.scheduleSubmit(formEl, ref, opts, push)
|
|
961
974
|
} else if(LiveUploader.inputsAwaitingPreflight(formEl).length > 0){
|
|
962
975
|
let [ref, els] = refGenerator()
|
|
963
976
|
let proxyRefGen = () => [ref, els, opts]
|
|
964
977
|
this.uploadFiles(formEl, targetCtx, ref, cid, (_uploads) => {
|
|
965
|
-
let formData = serializeForm(formEl, {})
|
|
978
|
+
let formData = serializeForm(formEl, {submitter})
|
|
966
979
|
this.pushWithReply(proxyRefGen, "event", {
|
|
967
980
|
type: "form",
|
|
968
981
|
event: phxEvent,
|
|
@@ -971,7 +984,7 @@ export default class View {
|
|
|
971
984
|
}, onReply)
|
|
972
985
|
})
|
|
973
986
|
} else {
|
|
974
|
-
let formData = serializeForm(formEl, {})
|
|
987
|
+
let formData = serializeForm(formEl, {submitter})
|
|
975
988
|
this.pushWithReply(refGenerator, "event", {
|
|
976
989
|
type: "form",
|
|
977
990
|
event: phxEvent,
|
|
@@ -1124,13 +1137,13 @@ export default class View {
|
|
|
1124
1137
|
(!parentViewEl && this.isDead)
|
|
1125
1138
|
}
|
|
1126
1139
|
|
|
1127
|
-
submitForm(form, targetCtx, phxEvent, opts = {}){
|
|
1140
|
+
submitForm(form, targetCtx, phxEvent, submitter, opts = {}){
|
|
1128
1141
|
DOM.putPrivate(form, PHX_HAS_SUBMITTED, true)
|
|
1129
1142
|
let phxFeedback = this.liveSocket.binding(PHX_FEEDBACK_FOR)
|
|
1130
1143
|
let inputs = Array.from(form.elements)
|
|
1131
1144
|
inputs.forEach(input => DOM.putPrivate(input, PHX_HAS_SUBMITTED, true))
|
|
1132
1145
|
this.liveSocket.blurActiveElement(this)
|
|
1133
|
-
this.pushFormSubmit(form, targetCtx, phxEvent, opts, () => {
|
|
1146
|
+
this.pushFormSubmit(form, targetCtx, phxEvent, submitter, opts, () => {
|
|
1134
1147
|
inputs.forEach(input => DOM.showError(input, phxFeedback))
|
|
1135
1148
|
this.liveSocket.restorePreviouslyActiveFocus()
|
|
1136
1149
|
})
|
package/assets/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1662,7 +1662,6 @@ var DOMPatch = class {
|
|
|
1662
1662
|
if (streamAt === void 0) {
|
|
1663
1663
|
return parent.appendChild(child);
|
|
1664
1664
|
}
|
|
1665
|
-
dom_default.putPrivate(child, PHX_STREAM, true);
|
|
1666
1665
|
if (streamAt === 0) {
|
|
1667
1666
|
parent.insertAdjacentElement("afterbegin", child);
|
|
1668
1667
|
} else if (streamAt === -1) {
|
|
@@ -1696,10 +1695,7 @@ var DOMPatch = class {
|
|
|
1696
1695
|
if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) {
|
|
1697
1696
|
return true;
|
|
1698
1697
|
}
|
|
1699
|
-
if (dom_default.
|
|
1700
|
-
return false;
|
|
1701
|
-
}
|
|
1702
|
-
if (el.parentElement !== null && dom_default.isPhxUpdate(el.parentElement, phxUpdate, ["append", "prepend"]) && el.id) {
|
|
1698
|
+
if (el.parentElement !== null && el.id && dom_default.isPhxUpdate(el.parentElement, phxUpdate, [PHX_STREAM, "append", "prepend"])) {
|
|
1703
1699
|
return false;
|
|
1704
1700
|
}
|
|
1705
1701
|
if (this.maybePendingRemove(el)) {
|
|
@@ -1813,7 +1809,6 @@ var DOMPatch = class {
|
|
|
1813
1809
|
if (streamAt === void 0) {
|
|
1814
1810
|
return;
|
|
1815
1811
|
}
|
|
1816
|
-
dom_default.putPrivate(el, PHX_STREAM, true);
|
|
1817
1812
|
if (streamAt === 0) {
|
|
1818
1813
|
el.parentElement.insertBefore(el, el.parentElement.firstElementChild);
|
|
1819
1814
|
} else if (streamAt > 0) {
|
|
@@ -2232,7 +2227,8 @@ var JS = {
|
|
|
2232
2227
|
}
|
|
2233
2228
|
targetView.pushInput(sourceEl, targetCtx, newCid, event || phxEvent, pushOpts, callback);
|
|
2234
2229
|
} else if (eventType === "submit") {
|
|
2235
|
-
|
|
2230
|
+
let { submitter } = args;
|
|
2231
|
+
targetView.submitForm(sourceEl, targetCtx, event || phxEvent, submitter, pushOpts);
|
|
2236
2232
|
} else {
|
|
2237
2233
|
targetView.pushEvent(eventType, sourceEl, targetCtx, event || phxEvent, data, pushOpts);
|
|
2238
2234
|
}
|
|
@@ -2396,8 +2392,12 @@ var JS = {
|
|
|
2396
2392
|
var js_default = JS;
|
|
2397
2393
|
|
|
2398
2394
|
// js/phoenix_live_view/view.js
|
|
2399
|
-
var serializeForm = (form,
|
|
2395
|
+
var serializeForm = (form, metadata, onlyNames = []) => {
|
|
2396
|
+
let { submitter, ...meta } = metadata;
|
|
2400
2397
|
let formData = new FormData(form);
|
|
2398
|
+
if (submitter && submitter.form && submitter.form === form) {
|
|
2399
|
+
formData.append(submitter.name, submitter.value);
|
|
2400
|
+
}
|
|
2401
2401
|
let toRemove = [];
|
|
2402
2402
|
formData.forEach((val, key, _index) => {
|
|
2403
2403
|
if (val instanceof File) {
|
|
@@ -2942,7 +2942,10 @@ var View = class {
|
|
|
2942
2942
|
});
|
|
2943
2943
|
}
|
|
2944
2944
|
onJoinError(resp) {
|
|
2945
|
-
if (resp.reason === "
|
|
2945
|
+
if (resp.reason === "reload") {
|
|
2946
|
+
this.log("error", () => [`failed mount with ${resp.status}. Falling back to page request`, resp]);
|
|
2947
|
+
return this.onRedirect({ to: this.href });
|
|
2948
|
+
} else if (resp.reason === "unauthorized" || resp.reason === "stale") {
|
|
2946
2949
|
this.log("error", () => ["unauthorized live_redirect. Falling back to page request", resp]);
|
|
2947
2950
|
return this.onRedirect({ to: this.href });
|
|
2948
2951
|
}
|
|
@@ -3277,18 +3280,18 @@ var View = class {
|
|
|
3277
3280
|
formEl.setAttribute(this.binding(PHX_PAGE_LOADING), "");
|
|
3278
3281
|
return this.putRef([formEl].concat(disables).concat(buttons).concat(inputs), "submit", opts);
|
|
3279
3282
|
}
|
|
3280
|
-
pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply) {
|
|
3283
|
+
pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply) {
|
|
3281
3284
|
let refGenerator = () => this.disableForm(formEl, opts);
|
|
3282
3285
|
let cid = this.targetComponentID(formEl, targetCtx);
|
|
3283
3286
|
if (LiveUploader.hasUploadsInProgress(formEl)) {
|
|
3284
3287
|
let [ref, _els] = refGenerator();
|
|
3285
|
-
let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply);
|
|
3288
|
+
let push = () => this.pushFormSubmit(formEl, submitter, targetCtx, phxEvent, opts, onReply);
|
|
3286
3289
|
return this.scheduleSubmit(formEl, ref, opts, push);
|
|
3287
3290
|
} else if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) {
|
|
3288
3291
|
let [ref, els] = refGenerator();
|
|
3289
3292
|
let proxyRefGen = () => [ref, els, opts];
|
|
3290
3293
|
this.uploadFiles(formEl, targetCtx, ref, cid, (_uploads) => {
|
|
3291
|
-
let formData = serializeForm(formEl, {});
|
|
3294
|
+
let formData = serializeForm(formEl, { submitter });
|
|
3292
3295
|
this.pushWithReply(proxyRefGen, "event", {
|
|
3293
3296
|
type: "form",
|
|
3294
3297
|
event: phxEvent,
|
|
@@ -3297,7 +3300,7 @@ var View = class {
|
|
|
3297
3300
|
}, onReply);
|
|
3298
3301
|
});
|
|
3299
3302
|
} else {
|
|
3300
|
-
let formData = serializeForm(formEl, {});
|
|
3303
|
+
let formData = serializeForm(formEl, { submitter });
|
|
3301
3304
|
this.pushWithReply(refGenerator, "event", {
|
|
3302
3305
|
type: "form",
|
|
3303
3306
|
event: phxEvent,
|
|
@@ -3425,13 +3428,13 @@ var View = class {
|
|
|
3425
3428
|
let parentViewEl = el.closest(PHX_VIEW_SELECTOR);
|
|
3426
3429
|
return el.getAttribute(PHX_PARENT_ID) === this.id || parentViewEl && parentViewEl.id === this.id || !parentViewEl && this.isDead;
|
|
3427
3430
|
}
|
|
3428
|
-
submitForm(form, targetCtx, phxEvent, opts = {}) {
|
|
3431
|
+
submitForm(form, targetCtx, phxEvent, submitter, opts = {}) {
|
|
3429
3432
|
dom_default.putPrivate(form, PHX_HAS_SUBMITTED, true);
|
|
3430
3433
|
let phxFeedback = this.liveSocket.binding(PHX_FEEDBACK_FOR);
|
|
3431
3434
|
let inputs = Array.from(form.elements);
|
|
3432
3435
|
inputs.forEach((input) => dom_default.putPrivate(input, PHX_HAS_SUBMITTED, true));
|
|
3433
3436
|
this.liveSocket.blurActiveElement(this);
|
|
3434
|
-
this.pushFormSubmit(form, targetCtx, phxEvent, opts, () => {
|
|
3437
|
+
this.pushFormSubmit(form, targetCtx, phxEvent, submitter, opts, () => {
|
|
3435
3438
|
inputs.forEach((input) => dom_default.showError(input, phxFeedback));
|
|
3436
3439
|
this.liveSocket.restorePreviouslyActiveFocus();
|
|
3437
3440
|
});
|
|
@@ -4156,7 +4159,7 @@ var LiveSocket = class {
|
|
|
4156
4159
|
e.preventDefault();
|
|
4157
4160
|
e.target.disabled = true;
|
|
4158
4161
|
this.withinOwners(e.target, (view) => {
|
|
4159
|
-
js_default.exec("submit", phxEvent, view, e.target, ["push", {}]);
|
|
4162
|
+
js_default.exec("submit", phxEvent, view, e.target, ["push", { submitter: e.submitter }]);
|
|
4160
4163
|
});
|
|
4161
4164
|
}, false);
|
|
4162
4165
|
for (let type of ["change", "input"]) {
|