phoenix_live_view 0.20.10 → 0.20.12
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/live_uploader.js +12 -4
- package/assets/js/phoenix_live_view/upload_entry.js +8 -4
- package/assets/js/phoenix_live_view/view.js +30 -9
- package/assets/package.json +1 -1
- package/package.json +1 -1
- package/priv/static/phoenix_live_view.cjs.js +48 -15
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +48 -15
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +48 -15
- package/priv/static/phoenix_live_view.min.js +4 -4
|
@@ -102,11 +102,12 @@ export default class LiveUploader {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
constructor(inputEl, view, onComplete){
|
|
105
|
+
this.autoUpload = DOM.isAutoUpload(inputEl)
|
|
105
106
|
this.view = view
|
|
106
107
|
this.onComplete = onComplete
|
|
107
108
|
this._entries =
|
|
108
109
|
Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || [])
|
|
109
|
-
.map(file => new UploadEntry(inputEl, file, view))
|
|
110
|
+
.map(file => new UploadEntry(inputEl, file, view, this.autoUpload))
|
|
110
111
|
|
|
111
112
|
// prevent sending duplicate preflight requests
|
|
112
113
|
LiveUploader.markPreflightInProgress(this._entries)
|
|
@@ -114,16 +115,23 @@ export default class LiveUploader {
|
|
|
114
115
|
this.numEntriesInProgress = this._entries.length
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
isAutoUpload(){ return this.autoUpload }
|
|
119
|
+
|
|
117
120
|
entries(){ return this._entries }
|
|
118
121
|
|
|
119
122
|
initAdapterUpload(resp, onError, liveSocket){
|
|
120
123
|
this._entries =
|
|
121
124
|
this._entries.map(entry => {
|
|
122
|
-
entry.
|
|
123
|
-
entry.onDone(() => {
|
|
125
|
+
if(entry.isCancelled()){
|
|
124
126
|
this.numEntriesInProgress--
|
|
125
127
|
if(this.numEntriesInProgress === 0){ this.onComplete() }
|
|
126
|
-
}
|
|
128
|
+
} else {
|
|
129
|
+
entry.zipPostFlight(resp)
|
|
130
|
+
entry.onDone(() => {
|
|
131
|
+
this.numEntriesInProgress--
|
|
132
|
+
if(this.numEntriesInProgress === 0){ this.onComplete() }
|
|
133
|
+
})
|
|
134
|
+
}
|
|
127
135
|
return entry
|
|
128
136
|
})
|
|
129
137
|
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
} from "./utils"
|
|
11
11
|
|
|
12
12
|
import LiveUploader from "./live_uploader"
|
|
13
|
-
import DOM from "./dom"
|
|
14
13
|
|
|
15
14
|
export default class UploadEntry {
|
|
16
15
|
static isActive(fileEl, file){
|
|
@@ -34,7 +33,7 @@ export default class UploadEntry {
|
|
|
34
33
|
file._preflightInProgress = true
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
constructor(fileEl, file, view){
|
|
36
|
+
constructor(fileEl, file, view, autoUpload){
|
|
38
37
|
this.ref = LiveUploader.genFileRef(file)
|
|
39
38
|
this.fileEl = fileEl
|
|
40
39
|
this.file = file
|
|
@@ -44,9 +43,10 @@ export default class UploadEntry {
|
|
|
44
43
|
this._isDone = false
|
|
45
44
|
this._progress = 0
|
|
46
45
|
this._lastProgressSent = -1
|
|
47
|
-
this._onDone = function
|
|
46
|
+
this._onDone = function(){ }
|
|
48
47
|
this._onElUpdated = this.onElUpdated.bind(this)
|
|
49
48
|
this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated)
|
|
49
|
+
this.autoUpload = autoUpload
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
metadata(){ return this.meta }
|
|
@@ -69,6 +69,8 @@ export default class UploadEntry {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
isCancelled(){ return this._isCancelled }
|
|
73
|
+
|
|
72
74
|
cancel(){
|
|
73
75
|
this.file._preflightInProgress = false
|
|
74
76
|
this._isCancelled = true
|
|
@@ -81,9 +83,11 @@ export default class UploadEntry {
|
|
|
81
83
|
error(reason = "failed"){
|
|
82
84
|
this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated)
|
|
83
85
|
this.view.pushFileProgress(this.fileEl, this.ref, {error: reason})
|
|
84
|
-
if(!
|
|
86
|
+
if(!this.isAutoUpload()){ LiveUploader.clearFiles(this.fileEl) }
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
isAutoUpload(){ return this.autoUpload }
|
|
90
|
+
|
|
87
91
|
//private
|
|
88
92
|
|
|
89
93
|
onDone(callback){
|
|
@@ -1037,7 +1037,12 @@ export default class View {
|
|
|
1037
1037
|
} else if(LiveUploader.inputsAwaitingPreflight(formEl).length > 0){
|
|
1038
1038
|
let [ref, els] = refGenerator()
|
|
1039
1039
|
let proxyRefGen = () => [ref, els, opts]
|
|
1040
|
-
this.uploadFiles(formEl, targetCtx, ref, cid, (
|
|
1040
|
+
this.uploadFiles(formEl, targetCtx, ref, cid, (uploads) => {
|
|
1041
|
+
// if we still having pending preflights it means we have invalid entries
|
|
1042
|
+
// and the phx-submit cannot be completed
|
|
1043
|
+
if(LiveUploader.inputsAwaitingPreflight(formEl).length > 0){
|
|
1044
|
+
return this.undoRefs(ref)
|
|
1045
|
+
}
|
|
1041
1046
|
let meta = this.extractMeta(formEl)
|
|
1042
1047
|
let formData = serializeForm(formEl, {submitter, ...meta})
|
|
1043
1048
|
this.pushWithReply(proxyRefGen, "event", {
|
|
@@ -1088,15 +1093,20 @@ export default class View {
|
|
|
1088
1093
|
|
|
1089
1094
|
this.pushWithReply(null, "allow_upload", payload, resp => {
|
|
1090
1095
|
this.log("upload", () => ["got preflight response", resp])
|
|
1091
|
-
|
|
1096
|
+
// the preflight will reject entries beyond the max entries
|
|
1097
|
+
// so we error and cancel entries on the client that are missing from the response
|
|
1098
|
+
uploader.entries().forEach(entry => {
|
|
1099
|
+
if(resp.entries && !resp.entries[entry.ref]){
|
|
1100
|
+
this.handleFailedEntryPreflight(entry.ref, "failed preflight", uploader)
|
|
1101
|
+
}
|
|
1102
|
+
})
|
|
1103
|
+
// for auto uploads, we may have an empty entries response from the server
|
|
1104
|
+
// for form submits that contain invalid entries
|
|
1105
|
+
if(resp.error || Object.keys(resp.entries).length === 0){
|
|
1092
1106
|
this.undoRefs(ref)
|
|
1093
|
-
resp.error
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
} else {
|
|
1097
|
-
uploader.entries().map(entry => entry.cancel())
|
|
1098
|
-
}
|
|
1099
|
-
this.log("upload", () => [`error for entry ${entry_ref}`, reason])
|
|
1107
|
+
let errors = resp.error || []
|
|
1108
|
+
errors.map(([entry_ref, reason]) => {
|
|
1109
|
+
this.handleFailedEntryPreflight(entry_ref, reason, uploader)
|
|
1100
1110
|
})
|
|
1101
1111
|
} else {
|
|
1102
1112
|
let onError = (callback) => {
|
|
@@ -1110,6 +1120,17 @@ export default class View {
|
|
|
1110
1120
|
})
|
|
1111
1121
|
}
|
|
1112
1122
|
|
|
1123
|
+
handleFailedEntryPreflight(uploadRef, reason, uploader){
|
|
1124
|
+
if(uploader.isAutoUpload()){
|
|
1125
|
+
// uploadRef may be top level upload config ref or entry ref
|
|
1126
|
+
let entry = uploader.entries().find(entry => entry.ref === uploadRef.toString())
|
|
1127
|
+
if(entry){ entry.cancel() }
|
|
1128
|
+
} else {
|
|
1129
|
+
uploader.entries().map(entry => entry.cancel())
|
|
1130
|
+
}
|
|
1131
|
+
this.log("upload", () => [`error for entry ${uploadRef}`, reason])
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1113
1134
|
dispatchUploads(targetCtx, name, filesOrBlobs){
|
|
1114
1135
|
let targetElement = this.targetCtxElement(targetCtx) || this.el
|
|
1115
1136
|
let inputs = DOM.findUploadInputs(targetElement).filter(el => el.name === name)
|
package/assets/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1139,7 +1139,7 @@ var UploadEntry = class {
|
|
|
1139
1139
|
static markPreflightInProgress(file) {
|
|
1140
1140
|
file._preflightInProgress = true;
|
|
1141
1141
|
}
|
|
1142
|
-
constructor(fileEl, file, view) {
|
|
1142
|
+
constructor(fileEl, file, view, autoUpload) {
|
|
1143
1143
|
this.ref = LiveUploader.genFileRef(file);
|
|
1144
1144
|
this.fileEl = fileEl;
|
|
1145
1145
|
this.file = file;
|
|
@@ -1153,6 +1153,7 @@ var UploadEntry = class {
|
|
|
1153
1153
|
};
|
|
1154
1154
|
this._onElUpdated = this.onElUpdated.bind(this);
|
|
1155
1155
|
this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated);
|
|
1156
|
+
this.autoUpload = autoUpload;
|
|
1156
1157
|
}
|
|
1157
1158
|
metadata() {
|
|
1158
1159
|
return this.meta;
|
|
@@ -1174,6 +1175,9 @@ var UploadEntry = class {
|
|
|
1174
1175
|
}
|
|
1175
1176
|
}
|
|
1176
1177
|
}
|
|
1178
|
+
isCancelled() {
|
|
1179
|
+
return this._isCancelled;
|
|
1180
|
+
}
|
|
1177
1181
|
cancel() {
|
|
1178
1182
|
this.file._preflightInProgress = false;
|
|
1179
1183
|
this._isCancelled = true;
|
|
@@ -1186,10 +1190,13 @@ var UploadEntry = class {
|
|
|
1186
1190
|
error(reason = "failed") {
|
|
1187
1191
|
this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated);
|
|
1188
1192
|
this.view.pushFileProgress(this.fileEl, this.ref, { error: reason });
|
|
1189
|
-
if (!
|
|
1193
|
+
if (!this.isAutoUpload()) {
|
|
1190
1194
|
LiveUploader.clearFiles(this.fileEl);
|
|
1191
1195
|
}
|
|
1192
1196
|
}
|
|
1197
|
+
isAutoUpload() {
|
|
1198
|
+
return this.autoUpload;
|
|
1199
|
+
}
|
|
1193
1200
|
onDone(callback) {
|
|
1194
1201
|
this._onDone = () => {
|
|
1195
1202
|
this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated);
|
|
@@ -1313,24 +1320,35 @@ var LiveUploader = class {
|
|
|
1313
1320
|
entries.forEach((entry) => UploadEntry.markPreflightInProgress(entry.file));
|
|
1314
1321
|
}
|
|
1315
1322
|
constructor(inputEl, view, onComplete) {
|
|
1323
|
+
this.autoUpload = dom_default.isAutoUpload(inputEl);
|
|
1316
1324
|
this.view = view;
|
|
1317
1325
|
this.onComplete = onComplete;
|
|
1318
|
-
this._entries = Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || []).map((file) => new UploadEntry(inputEl, file, view));
|
|
1326
|
+
this._entries = Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || []).map((file) => new UploadEntry(inputEl, file, view, this.autoUpload));
|
|
1319
1327
|
LiveUploader.markPreflightInProgress(this._entries);
|
|
1320
1328
|
this.numEntriesInProgress = this._entries.length;
|
|
1321
1329
|
}
|
|
1330
|
+
isAutoUpload() {
|
|
1331
|
+
return this.autoUpload;
|
|
1332
|
+
}
|
|
1322
1333
|
entries() {
|
|
1323
1334
|
return this._entries;
|
|
1324
1335
|
}
|
|
1325
1336
|
initAdapterUpload(resp, onError, liveSocket) {
|
|
1326
1337
|
this._entries = this._entries.map((entry) => {
|
|
1327
|
-
entry.
|
|
1328
|
-
entry.onDone(() => {
|
|
1338
|
+
if (entry.isCancelled()) {
|
|
1329
1339
|
this.numEntriesInProgress--;
|
|
1330
1340
|
if (this.numEntriesInProgress === 0) {
|
|
1331
1341
|
this.onComplete();
|
|
1332
1342
|
}
|
|
1333
|
-
}
|
|
1343
|
+
} else {
|
|
1344
|
+
entry.zipPostFlight(resp);
|
|
1345
|
+
entry.onDone(() => {
|
|
1346
|
+
this.numEntriesInProgress--;
|
|
1347
|
+
if (this.numEntriesInProgress === 0) {
|
|
1348
|
+
this.onComplete();
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1334
1352
|
return entry;
|
|
1335
1353
|
});
|
|
1336
1354
|
let groupedEntries = this._entries.reduce((acc, entry) => {
|
|
@@ -3820,7 +3838,10 @@ var View = class {
|
|
|
3820
3838
|
} else if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) {
|
|
3821
3839
|
let [ref, els] = refGenerator();
|
|
3822
3840
|
let proxyRefGen = () => [ref, els, opts];
|
|
3823
|
-
this.uploadFiles(formEl, targetCtx, ref, cid, (
|
|
3841
|
+
this.uploadFiles(formEl, targetCtx, ref, cid, (uploads) => {
|
|
3842
|
+
if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) {
|
|
3843
|
+
return this.undoRefs(ref);
|
|
3844
|
+
}
|
|
3824
3845
|
let meta = this.extractMeta(formEl);
|
|
3825
3846
|
let formData = serializeForm(formEl, { submitter, ...meta });
|
|
3826
3847
|
this.pushWithReply(proxyRefGen, "event", {
|
|
@@ -3865,15 +3886,16 @@ var View = class {
|
|
|
3865
3886
|
this.log("upload", () => ["sending preflight request", payload]);
|
|
3866
3887
|
this.pushWithReply(null, "allow_upload", payload, (resp) => {
|
|
3867
3888
|
this.log("upload", () => ["got preflight response", resp]);
|
|
3868
|
-
|
|
3889
|
+
uploader.entries().forEach((entry) => {
|
|
3890
|
+
if (resp.entries && !resp.entries[entry.ref]) {
|
|
3891
|
+
this.handleFailedEntryPreflight(entry.ref, "failed preflight", uploader);
|
|
3892
|
+
}
|
|
3893
|
+
});
|
|
3894
|
+
if (resp.error || Object.keys(resp.entries).length === 0) {
|
|
3869
3895
|
this.undoRefs(ref);
|
|
3870
|
-
resp.error
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
} else {
|
|
3874
|
-
uploader.entries().map((entry) => entry.cancel());
|
|
3875
|
-
}
|
|
3876
|
-
this.log("upload", () => [`error for entry ${entry_ref}`, reason]);
|
|
3896
|
+
let errors = resp.error || [];
|
|
3897
|
+
errors.map(([entry_ref, reason]) => {
|
|
3898
|
+
this.handleFailedEntryPreflight(entry_ref, reason, uploader);
|
|
3877
3899
|
});
|
|
3878
3900
|
} else {
|
|
3879
3901
|
let onError = (callback) => {
|
|
@@ -3888,6 +3910,17 @@ var View = class {
|
|
|
3888
3910
|
});
|
|
3889
3911
|
});
|
|
3890
3912
|
}
|
|
3913
|
+
handleFailedEntryPreflight(uploadRef, reason, uploader) {
|
|
3914
|
+
if (uploader.isAutoUpload()) {
|
|
3915
|
+
let entry = uploader.entries().find((entry2) => entry2.ref === uploadRef.toString());
|
|
3916
|
+
if (entry) {
|
|
3917
|
+
entry.cancel();
|
|
3918
|
+
}
|
|
3919
|
+
} else {
|
|
3920
|
+
uploader.entries().map((entry) => entry.cancel());
|
|
3921
|
+
}
|
|
3922
|
+
this.log("upload", () => [`error for entry ${uploadRef}`, reason]);
|
|
3923
|
+
}
|
|
3891
3924
|
dispatchUploads(targetCtx, name, filesOrBlobs) {
|
|
3892
3925
|
let targetElement = this.targetCtxElement(targetCtx) || this.el;
|
|
3893
3926
|
let inputs = dom_default.findUploadInputs(targetElement).filter((el) => el.name === name);
|