pyview-web 0.4.3__tar.gz → 0.5.1__tar.gz
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.
Potentially problematic release.
This version of pyview-web might be problematic. Click here for more details.
- {pyview_web-0.4.3 → pyview_web-0.5.1}/PKG-INFO +1 -1
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyproject.toml +1 -1
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/assets/js/app.js +1 -0
- pyview_web-0.5.1/pyview/assets/js/uploaders.js +221 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/live_socket.py +7 -1
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/static/assets/app.js +31 -49
- pyview_web-0.5.1/pyview/static/assets/uploaders.js +221 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/uploads.py +274 -34
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/ws_handler.py +5 -5
- {pyview_web-0.4.3 → pyview_web-0.5.1}/LICENSE +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/assets/package-lock.json +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/assets/package.json +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/async_stream_runner.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/auth/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/auth/provider.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/auth/required.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/changesets/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/changesets/changesets.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/cli/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/cli/commands/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/cli/commands/create_view.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/cli/main.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/csrf.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/events/BaseEventHandler.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/events/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/events/info_event.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/instrumentation/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/instrumentation/interfaces.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/instrumentation/noop.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/js.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/live_routes.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/live_view.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/meta.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/phx_message.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/pyview.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/secret.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/session.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/context_processor.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/live_template.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/render_diff.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/root_template.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/serializer.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/template/utils.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/flet/pubsub/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/flet/pubsub/pub_sub.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/__init__.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/compiler.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/context.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/errors.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/filters.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/loaders.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/nodes.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/template.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/tree.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/pyview/vendor/ibis/utils.py +0 -0
- {pyview_web-0.4.3 → pyview_web-0.5.1}/readme.md +0 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PyView External S3 Uploaders
|
|
3
|
+
*
|
|
4
|
+
* Client-side uploaders for external S3 uploads.
|
|
5
|
+
*
|
|
6
|
+
* Available uploaders:
|
|
7
|
+
* - S3: Simple POST upload to S3 using presigned POST URLs
|
|
8
|
+
* - S3Multipart: Multipart upload for large files (>5GB)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
window.Uploaders = window.Uploaders || {};
|
|
12
|
+
|
|
13
|
+
// S3 Simple POST uploader
|
|
14
|
+
// Uses presigned POST URLs for direct upload to S3
|
|
15
|
+
// Works for files up to ~5GB
|
|
16
|
+
if (!window.Uploaders.S3) {
|
|
17
|
+
window.Uploaders.S3 = function (entries, onViewError) {
|
|
18
|
+
entries.forEach((entry) => {
|
|
19
|
+
let formData = new FormData();
|
|
20
|
+
let { url, fields } = entry.meta;
|
|
21
|
+
|
|
22
|
+
// Add all fields from presigned POST
|
|
23
|
+
Object.entries(fields).forEach(([key, val]) =>
|
|
24
|
+
formData.append(key, val)
|
|
25
|
+
);
|
|
26
|
+
formData.append("file", entry.file);
|
|
27
|
+
|
|
28
|
+
let xhr = new XMLHttpRequest();
|
|
29
|
+
onViewError(() => xhr.abort());
|
|
30
|
+
|
|
31
|
+
xhr.onload = () => {
|
|
32
|
+
if (xhr.status === 204 || xhr.status === 200) {
|
|
33
|
+
entry.progress(100);
|
|
34
|
+
} else {
|
|
35
|
+
entry.error(`S3 upload failed with status ${xhr.status}`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
xhr.onerror = () => entry.error("Network error during upload");
|
|
39
|
+
|
|
40
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
41
|
+
if (event.lengthComputable) {
|
|
42
|
+
let percent = Math.round((event.loaded / event.total) * 100);
|
|
43
|
+
if (percent < 100) {
|
|
44
|
+
entry.progress(percent);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
xhr.open("POST", url, true);
|
|
50
|
+
xhr.send(formData);
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// S3 Multipart uploader for large files
|
|
56
|
+
// Uploads file in chunks with retry logic and concurrency control
|
|
57
|
+
//
|
|
58
|
+
// - Exponential backoff retry (max 3 attempts per part)
|
|
59
|
+
// - Concurrency limit (max 6 parallel uploads)
|
|
60
|
+
// - Automatic cleanup on fatal errors
|
|
61
|
+
//
|
|
62
|
+
// Based on AWS best practices:
|
|
63
|
+
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html
|
|
64
|
+
//
|
|
65
|
+
// Server must:
|
|
66
|
+
// 1. Return metadata with: uploader="S3Multipart", upload_id, part_urls, chunk_size
|
|
67
|
+
// 2. Provide entry_complete callback to finalize the upload
|
|
68
|
+
if (!window.Uploaders.S3Multipart) {
|
|
69
|
+
window.Uploaders.S3Multipart = function (entries, onViewError) {
|
|
70
|
+
entries.forEach((entry) => {
|
|
71
|
+
const { upload_id, part_urls, chunk_size, key } = entry.meta;
|
|
72
|
+
const file = entry.file;
|
|
73
|
+
const parts = []; // Store {PartNumber, ETag} for each uploaded part
|
|
74
|
+
|
|
75
|
+
const MAX_RETRIES = 3;
|
|
76
|
+
const MAX_CONCURRENT = 6;
|
|
77
|
+
let uploadedParts = 0;
|
|
78
|
+
let activeUploads = 0;
|
|
79
|
+
let partIndex = 0;
|
|
80
|
+
let hasError = false;
|
|
81
|
+
const totalParts = part_urls.length;
|
|
82
|
+
|
|
83
|
+
console.log(`[S3Multipart] Starting upload for ${entry.file.name}`);
|
|
84
|
+
console.log(`[S3Multipart] Total parts: ${totalParts}, chunk size: ${chunk_size}`);
|
|
85
|
+
console.log(`[S3Multipart] Max concurrent uploads: ${MAX_CONCURRENT}, max retries: ${MAX_RETRIES}`);
|
|
86
|
+
|
|
87
|
+
// Add a custom method to send completion data directly
|
|
88
|
+
// This bypasses entry.progress() which only handles numbers
|
|
89
|
+
entry.complete = function(completionData) {
|
|
90
|
+
console.log(`[S3Multipart] Calling entry.complete with:`, completionData);
|
|
91
|
+
// Call pushFileProgress directly with the completion data
|
|
92
|
+
entry.view.pushFileProgress(entry.fileEl, entry.ref, completionData);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Upload a single part with retry logic
|
|
96
|
+
const uploadPart = (index, retryCount = 0) => {
|
|
97
|
+
if (hasError) return; // Stop if we've hit a fatal error
|
|
98
|
+
|
|
99
|
+
const partNumber = index + 1;
|
|
100
|
+
const url = part_urls[index];
|
|
101
|
+
const start = index * chunk_size;
|
|
102
|
+
const end = Math.min(start + chunk_size, file.size);
|
|
103
|
+
const chunk = file.slice(start, end);
|
|
104
|
+
|
|
105
|
+
console.log(`[S3Multipart] Starting part ${partNumber}/${totalParts}, size: ${chunk.size} bytes, attempt ${retryCount + 1}`);
|
|
106
|
+
|
|
107
|
+
const xhr = new XMLHttpRequest();
|
|
108
|
+
onViewError(() => xhr.abort());
|
|
109
|
+
|
|
110
|
+
// Track upload progress within this chunk
|
|
111
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
112
|
+
if (event.lengthComputable) {
|
|
113
|
+
// Calculate overall progress: completed parts + current part's progress
|
|
114
|
+
const completedBytes = uploadedParts * chunk_size;
|
|
115
|
+
const currentPartBytes = event.loaded;
|
|
116
|
+
const totalBytes = file.size;
|
|
117
|
+
const overallPercent = Math.round(((completedBytes + currentPartBytes) / totalBytes) * 100);
|
|
118
|
+
|
|
119
|
+
// Don't report 100% until all parts complete and we send completion data
|
|
120
|
+
if (overallPercent < 100) {
|
|
121
|
+
entry.progress(overallPercent);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
xhr.onload = () => {
|
|
127
|
+
activeUploads--;
|
|
128
|
+
|
|
129
|
+
if (xhr.status === 200) {
|
|
130
|
+
const etag = xhr.getResponseHeader('ETag');
|
|
131
|
+
console.log(`[S3Multipart] Part ${partNumber} succeeded, ETag: ${etag}`);
|
|
132
|
+
|
|
133
|
+
if (!etag) {
|
|
134
|
+
console.error(`[S3Multipart] Part ${partNumber} missing ETag!`);
|
|
135
|
+
entry.error(`Part ${partNumber} upload succeeded but no ETag returned`);
|
|
136
|
+
hasError = true;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Store the part with its ETag
|
|
141
|
+
parts.push({
|
|
142
|
+
PartNumber: partNumber,
|
|
143
|
+
ETag: etag.replace(/"/g, '')
|
|
144
|
+
});
|
|
145
|
+
uploadedParts++;
|
|
146
|
+
|
|
147
|
+
// Update progress
|
|
148
|
+
const progressPercent = Math.round((uploadedParts / totalParts) * 100);
|
|
149
|
+
console.log(`[S3Multipart] Progress: ${uploadedParts}/${totalParts} parts (${progressPercent}%)`);
|
|
150
|
+
|
|
151
|
+
if (uploadedParts < totalParts) {
|
|
152
|
+
entry.progress(progressPercent < 100 ? progressPercent : 99);
|
|
153
|
+
uploadNextPart(); // Start next part
|
|
154
|
+
} else {
|
|
155
|
+
// All parts complete!
|
|
156
|
+
const completionData = {
|
|
157
|
+
complete: true,
|
|
158
|
+
upload_id: upload_id,
|
|
159
|
+
key: key,
|
|
160
|
+
parts: parts.sort((a, b) => a.PartNumber - b.PartNumber)
|
|
161
|
+
};
|
|
162
|
+
console.log(`[S3Multipart] All parts complete! Sending completion data`);
|
|
163
|
+
entry.complete(completionData);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
// Upload failed - retry with exponential backoff
|
|
167
|
+
console.error(`[S3Multipart] Part ${partNumber} failed with status ${xhr.status}, attempt ${retryCount + 1}`);
|
|
168
|
+
|
|
169
|
+
if (retryCount < MAX_RETRIES) {
|
|
170
|
+
// Exponential backoff: 1s, 2s, 4s, max 10s
|
|
171
|
+
const delay = Math.min(1000 * (2 ** retryCount), 10000);
|
|
172
|
+
console.log(`[S3Multipart] Retrying part ${partNumber} in ${delay}ms...`);
|
|
173
|
+
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
uploadPart(index, retryCount + 1);
|
|
176
|
+
}, delay);
|
|
177
|
+
} else {
|
|
178
|
+
// Max retries exceeded - fatal error
|
|
179
|
+
console.error(`[S3Multipart] Part ${partNumber} failed after ${MAX_RETRIES} retries, aborting upload`);
|
|
180
|
+
entry.error(`Part ${partNumber} failed after ${MAX_RETRIES} attempts. Upload aborted.`);
|
|
181
|
+
hasError = true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
xhr.onerror = () => {
|
|
187
|
+
activeUploads--;
|
|
188
|
+
console.error(`[S3Multipart] Network error on part ${partNumber}, attempt ${retryCount + 1}`);
|
|
189
|
+
|
|
190
|
+
if (retryCount < MAX_RETRIES) {
|
|
191
|
+
const delay = Math.min(1000 * (2 ** retryCount), 10000);
|
|
192
|
+
console.log(`[S3Multipart] Retrying part ${partNumber} after network error in ${delay}ms...`);
|
|
193
|
+
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
uploadPart(index, retryCount + 1);
|
|
196
|
+
}, delay);
|
|
197
|
+
} else {
|
|
198
|
+
console.error(`[S3Multipart] Part ${partNumber} network error after ${MAX_RETRIES} retries, aborting upload`);
|
|
199
|
+
entry.error(`Part ${partNumber} network error after ${MAX_RETRIES} attempts. Upload aborted.`);
|
|
200
|
+
hasError = true;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
xhr.open('PUT', url, true);
|
|
205
|
+
xhr.send(chunk);
|
|
206
|
+
activeUploads++;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Upload next part if we haven't hit the concurrency limit
|
|
210
|
+
const uploadNextPart = () => {
|
|
211
|
+
while (partIndex < totalParts && activeUploads < MAX_CONCURRENT && !hasError) {
|
|
212
|
+
uploadPart(partIndex);
|
|
213
|
+
partIndex++;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Start initial batch of uploads
|
|
218
|
+
uploadNextPart();
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
}
|
|
@@ -52,12 +52,16 @@ class UnconnectedSocket(Generic[T]):
|
|
|
52
52
|
constraints: UploadConstraints,
|
|
53
53
|
auto_upload: bool = False,
|
|
54
54
|
progress: Optional[Callable] = None,
|
|
55
|
+
external: Optional[Callable] = None,
|
|
56
|
+
entry_complete: Optional[Callable] = None,
|
|
55
57
|
) -> UploadConfig:
|
|
56
58
|
return UploadConfig(
|
|
57
59
|
name=upload_name,
|
|
58
60
|
constraints=constraints,
|
|
59
61
|
autoUpload=auto_upload,
|
|
60
62
|
progress_callback=progress,
|
|
63
|
+
external_callback=external,
|
|
64
|
+
entry_complete_callback=entry_complete,
|
|
61
65
|
)
|
|
62
66
|
|
|
63
67
|
|
|
@@ -230,9 +234,11 @@ class ConnectedLiveViewSocket(Generic[T]):
|
|
|
230
234
|
constraints: UploadConstraints,
|
|
231
235
|
auto_upload: bool = False,
|
|
232
236
|
progress: Optional[Callable] = None,
|
|
237
|
+
external: Optional[Callable] = None,
|
|
238
|
+
entry_complete: Optional[Callable] = None,
|
|
233
239
|
) -> UploadConfig:
|
|
234
240
|
return self.upload_manager.allow_upload(
|
|
235
|
-
upload_name, constraints, auto_upload, progress
|
|
241
|
+
upload_name, constraints, auto_upload, progress, external, entry_complete
|
|
236
242
|
)
|
|
237
243
|
|
|
238
244
|
async def close(self):
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
mod
|
|
40
40
|
));
|
|
41
41
|
|
|
42
|
-
//
|
|
42
|
+
// node_modules/nprogress/nprogress.js
|
|
43
43
|
var require_nprogress = __commonJS({
|
|
44
|
-
"
|
|
44
|
+
"node_modules/nprogress/nprogress.js"(exports, module) {
|
|
45
45
|
(function(root, factory) {
|
|
46
46
|
if (typeof define === "function" && define.amd) {
|
|
47
47
|
define(factory);
|
|
@@ -71,8 +71,7 @@
|
|
|
71
71
|
var key, value;
|
|
72
72
|
for (key in options) {
|
|
73
73
|
value = options[key];
|
|
74
|
-
if (value !== void 0 && options.hasOwnProperty(key))
|
|
75
|
-
Settings[key] = value;
|
|
74
|
+
if (value !== void 0 && options.hasOwnProperty(key)) Settings[key] = value;
|
|
76
75
|
}
|
|
77
76
|
return this;
|
|
78
77
|
};
|
|
@@ -84,8 +83,7 @@
|
|
|
84
83
|
var progress = NProgress2.render(!started), bar = progress.querySelector(Settings.barSelector), speed = Settings.speed, ease = Settings.easing;
|
|
85
84
|
progress.offsetWidth;
|
|
86
85
|
queue(function(next) {
|
|
87
|
-
if (Settings.positionUsing === "")
|
|
88
|
-
Settings.positionUsing = NProgress2.getPositioningCSS();
|
|
86
|
+
if (Settings.positionUsing === "") Settings.positionUsing = NProgress2.getPositioningCSS();
|
|
89
87
|
css(bar, barPositionCSS(n, speed, ease));
|
|
90
88
|
if (n === 1) {
|
|
91
89
|
css(progress, {
|
|
@@ -113,23 +111,19 @@
|
|
|
113
111
|
return typeof NProgress2.status === "number";
|
|
114
112
|
};
|
|
115
113
|
NProgress2.start = function() {
|
|
116
|
-
if (!NProgress2.status)
|
|
117
|
-
NProgress2.set(0);
|
|
114
|
+
if (!NProgress2.status) NProgress2.set(0);
|
|
118
115
|
var work = function() {
|
|
119
116
|
setTimeout(function() {
|
|
120
|
-
if (!NProgress2.status)
|
|
121
|
-
return;
|
|
117
|
+
if (!NProgress2.status) return;
|
|
122
118
|
NProgress2.trickle();
|
|
123
119
|
work();
|
|
124
120
|
}, Settings.trickleSpeed);
|
|
125
121
|
};
|
|
126
|
-
if (Settings.trickle)
|
|
127
|
-
work();
|
|
122
|
+
if (Settings.trickle) work();
|
|
128
123
|
return this;
|
|
129
124
|
};
|
|
130
125
|
NProgress2.done = function(force) {
|
|
131
|
-
if (!force && !NProgress2.status)
|
|
132
|
-
return this;
|
|
126
|
+
if (!force && !NProgress2.status) return this;
|
|
133
127
|
return NProgress2.inc(0.3 + 0.5 * Math.random()).set(1);
|
|
134
128
|
};
|
|
135
129
|
NProgress2.inc = function(amount) {
|
|
@@ -171,8 +165,7 @@
|
|
|
171
165
|
};
|
|
172
166
|
})();
|
|
173
167
|
NProgress2.render = function(fromStart) {
|
|
174
|
-
if (NProgress2.isRendered())
|
|
175
|
-
return document.getElementById("nprogress");
|
|
168
|
+
if (NProgress2.isRendered()) return document.getElementById("nprogress");
|
|
176
169
|
addClass(document.documentElement, "nprogress-busy");
|
|
177
170
|
var progress = document.createElement("div");
|
|
178
171
|
progress.id = "nprogress";
|
|
@@ -213,10 +206,8 @@
|
|
|
213
206
|
}
|
|
214
207
|
};
|
|
215
208
|
function clamp(n, min, max) {
|
|
216
|
-
if (n < min)
|
|
217
|
-
|
|
218
|
-
if (n > max)
|
|
219
|
-
return max;
|
|
209
|
+
if (n < min) return min;
|
|
210
|
+
if (n > max) return max;
|
|
220
211
|
return n;
|
|
221
212
|
}
|
|
222
213
|
function toBarPerc(n) {
|
|
@@ -234,7 +225,7 @@
|
|
|
234
225
|
barCSS.transition = "all " + speed + "ms " + ease;
|
|
235
226
|
return barCSS;
|
|
236
227
|
}
|
|
237
|
-
var queue = function() {
|
|
228
|
+
var queue = /* @__PURE__ */ (function() {
|
|
238
229
|
var pending = [];
|
|
239
230
|
function next() {
|
|
240
231
|
var fn = pending.shift();
|
|
@@ -244,11 +235,10 @@
|
|
|
244
235
|
}
|
|
245
236
|
return function(fn) {
|
|
246
237
|
pending.push(fn);
|
|
247
|
-
if (pending.length == 1)
|
|
248
|
-
next();
|
|
238
|
+
if (pending.length == 1) next();
|
|
249
239
|
};
|
|
250
|
-
}();
|
|
251
|
-
var css = function() {
|
|
240
|
+
})();
|
|
241
|
+
var css = /* @__PURE__ */ (function() {
|
|
252
242
|
var cssPrefixes = ["Webkit", "O", "Moz", "ms"], cssProps = {};
|
|
253
243
|
function camelCase(string) {
|
|
254
244
|
return string.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function(match, letter) {
|
|
@@ -257,13 +247,11 @@
|
|
|
257
247
|
}
|
|
258
248
|
function getVendorProp(name) {
|
|
259
249
|
var style = document.body.style;
|
|
260
|
-
if (name in style)
|
|
261
|
-
return name;
|
|
250
|
+
if (name in style) return name;
|
|
262
251
|
var i = cssPrefixes.length, capName = name.charAt(0).toUpperCase() + name.slice(1), vendorName;
|
|
263
252
|
while (i--) {
|
|
264
253
|
vendorName = cssPrefixes[i] + capName;
|
|
265
|
-
if (vendorName in style)
|
|
266
|
-
return vendorName;
|
|
254
|
+
if (vendorName in style) return vendorName;
|
|
267
255
|
}
|
|
268
256
|
return name;
|
|
269
257
|
}
|
|
@@ -280,28 +268,25 @@
|
|
|
280
268
|
if (args.length == 2) {
|
|
281
269
|
for (prop in properties) {
|
|
282
270
|
value = properties[prop];
|
|
283
|
-
if (value !== void 0 && properties.hasOwnProperty(prop))
|
|
284
|
-
applyCss(element, prop, value);
|
|
271
|
+
if (value !== void 0 && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
|
|
285
272
|
}
|
|
286
273
|
} else {
|
|
287
274
|
applyCss(element, args[1], args[2]);
|
|
288
275
|
}
|
|
289
276
|
};
|
|
290
|
-
}();
|
|
277
|
+
})();
|
|
291
278
|
function hasClass(element, name) {
|
|
292
279
|
var list = typeof element == "string" ? element : classList(element);
|
|
293
280
|
return list.indexOf(" " + name + " ") >= 0;
|
|
294
281
|
}
|
|
295
282
|
function addClass(element, name) {
|
|
296
283
|
var oldList = classList(element), newList = oldList + name;
|
|
297
|
-
if (hasClass(oldList, name))
|
|
298
|
-
return;
|
|
284
|
+
if (hasClass(oldList, name)) return;
|
|
299
285
|
element.className = newList.substring(1);
|
|
300
286
|
}
|
|
301
287
|
function removeClass(element, name) {
|
|
302
288
|
var oldList = classList(element), newList;
|
|
303
|
-
if (!hasClass(element, name))
|
|
304
|
-
return;
|
|
289
|
+
if (!hasClass(element, name)) return;
|
|
305
290
|
newList = oldList.replace(" " + name + " ", " ");
|
|
306
291
|
element.className = newList.substring(1, newList.length - 1);
|
|
307
292
|
}
|
|
@@ -316,12 +301,11 @@
|
|
|
316
301
|
}
|
|
317
302
|
});
|
|
318
303
|
|
|
319
|
-
//
|
|
304
|
+
// node_modules/phoenix_html/priv/static/phoenix_html.js
|
|
320
305
|
(function() {
|
|
321
306
|
var PolyfillEvent = eventConstructor();
|
|
322
307
|
function eventConstructor() {
|
|
323
|
-
if (typeof window.CustomEvent === "function")
|
|
324
|
-
return window.CustomEvent;
|
|
308
|
+
if (typeof window.CustomEvent === "function") return window.CustomEvent;
|
|
325
309
|
function CustomEvent2(event, params) {
|
|
326
310
|
params = params || { bubbles: false, cancelable: false, detail: void 0 };
|
|
327
311
|
var evt = document.createEvent("CustomEvent");
|
|
@@ -343,10 +327,8 @@
|
|
|
343
327
|
form.method = element.getAttribute("data-method") === "get" ? "get" : "post";
|
|
344
328
|
form.action = to;
|
|
345
329
|
form.style.display = "hidden";
|
|
346
|
-
if (target)
|
|
347
|
-
|
|
348
|
-
else if (targetModifierKey)
|
|
349
|
-
form.target = "_blank";
|
|
330
|
+
if (target) form.target = target;
|
|
331
|
+
else if (targetModifierKey) form.target = "_blank";
|
|
350
332
|
form.appendChild(csrf);
|
|
351
333
|
form.appendChild(method);
|
|
352
334
|
document.body.appendChild(form);
|
|
@@ -354,8 +336,7 @@
|
|
|
354
336
|
}
|
|
355
337
|
window.addEventListener("click", function(e) {
|
|
356
338
|
var element = e.target;
|
|
357
|
-
if (e.defaultPrevented)
|
|
358
|
-
return;
|
|
339
|
+
if (e.defaultPrevented) return;
|
|
359
340
|
while (element && element.getAttribute) {
|
|
360
341
|
var phoenixLinkEvent = new PolyfillEvent("phoenix.link.click", {
|
|
361
342
|
"bubbles": true,
|
|
@@ -383,7 +364,7 @@
|
|
|
383
364
|
}, false);
|
|
384
365
|
})();
|
|
385
366
|
|
|
386
|
-
//
|
|
367
|
+
// node_modules/phoenix/priv/static/phoenix.mjs
|
|
387
368
|
var closure = (value) => {
|
|
388
369
|
if (typeof value === "function") {
|
|
389
370
|
return value;
|
|
@@ -1354,7 +1335,7 @@
|
|
|
1354
1335
|
}
|
|
1355
1336
|
};
|
|
1356
1337
|
|
|
1357
|
-
//
|
|
1338
|
+
// node_modules/phoenix_live_view/priv/static/phoenix_live_view.esm.js
|
|
1358
1339
|
var CONSECUTIVE_RELOADS = "consecutive-reloads";
|
|
1359
1340
|
var MAX_RELOADS = 10;
|
|
1360
1341
|
var RELOAD_JITTER_MIN = 5e3;
|
|
@@ -5457,7 +5438,7 @@ within:
|
|
|
5457
5438
|
}
|
|
5458
5439
|
};
|
|
5459
5440
|
|
|
5460
|
-
//
|
|
5441
|
+
// js/app.js
|
|
5461
5442
|
var import_nprogress = __toESM(require_nprogress());
|
|
5462
5443
|
var _a;
|
|
5463
5444
|
var Hooks2 = (_a = window.Hooks) != null ? _a : {};
|
|
@@ -5487,7 +5468,8 @@ within:
|
|
|
5487
5468
|
var csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
|
|
5488
5469
|
var liveSocket = new LiveSocket("/live", Socket, {
|
|
5489
5470
|
hooks: Hooks2,
|
|
5490
|
-
params: { _csrf_token: csrfToken }
|
|
5471
|
+
params: { _csrf_token: csrfToken },
|
|
5472
|
+
uploaders: window.Uploaders || {}
|
|
5491
5473
|
});
|
|
5492
5474
|
window.addEventListener("phx:page-loading-start", (info) => import_nprogress.default.start());
|
|
5493
5475
|
window.addEventListener("phx:page-loading-stop", (info) => import_nprogress.default.done());
|