PageSourceSearch

https://www.appycouple.com/js/1773352594/common/appy/s3upload.js

js appycouple.com collected 2026-10-01 13:14:48 UTC 8,040 bytes, 191 lines download raw bytes

1var AppyS3Upload = (function () {
2    'use strict';
3
4    var _active = false;
5
6    function _cleanup(uppy) {
7        _active = false;
8        if (uppy) {
9            try { uppy.destroy(); } catch (e) { /* already destroyed */ }
10        }
11    }
12
13    function _showError(title, text) {
14        if (typeof swal === 'function') {
15            swal({ title: title, text: text, type: 'error' });
16        } else {
17            alert(title + ': ' + text);
18        }
19    }
20
21    function open(opts) {
22        opts = opts || {};
23
24        return new Promise(function (resolve) {
25            // Concurrency guard
26            if (_active) {
27                resolve(null);
28                return;
29            }
30
31            // Hard guard
32            if (!window._Uppy) {
33                if (typeof swal === 'function') {
34                    swal({ title: 'Upload library not ready', text: 'Please try again in a moment.', type: 'warning' });
35                } else {
36                    alert('Upload library not ready. Please try again in a moment.');
37                }
38                resolve(null);
39                return;
40            }
41
42            _active = true;
43            var _U = window._Uppy;
44            var resolved = false;
45            var activeXhr = null;
46
47            function done(result) {
48                if (resolved) return;
49                resolved = true;
50                // Abort any in-flight XHR
51                if (activeXhr) {
52                    try { activeXhr.abort(); } catch (e) { /* ignore */ }
53                    activeXhr = null;
54                }
55                _cleanup(uppy);
56                resolve(result);
57            }
58
59            var uppy = new _U.Uppy({
60                restrictions: {
61                    maxNumberOfFiles: opts.maxFiles || 1,
62                    maxFileSize: opts.maxFileSize || 6 * 1024 * 1024,
63                    allowedFileTypes: opts.allowedFileTypes || ['image/*']
64                }
65            });
66
67            uppy.use(_U.Dashboard, {
68                inline: false,
69                proudlyDisplayPoweredByUppy: false,
70                waitForThumbnailsBeforeUpload: true
71            });
72
73            var imageEditorOpts = {};
74            if (opts.cropRatio) {
75                imageEditorOpts.cropperOptions = {
76                    aspectRatio: opts.cropRatio
77                };
78            }
79            uppy.use(_U.ImageEditor, imageEditorOpts);
80
81            uppy.addUploader(function (fileIDs) {
82                var files = fileIDs.map(function (id) { return uppy.getFile(id); });
83
84                // Build presign URL with query parameters
85                var presignUrl = '/ajax/u/?a=s';
86                files.forEach(function (f, i) {
87                    presignUrl += '&files[' + i + '][filename]=' + encodeURIComponent(f.name);
88                    presignUrl += '&files[' + i + '][type]=' + encodeURIComponent(f.type || 'image/jpeg');
89                });
90
91                return fetch(presignUrl, { credentials: 'same-origin' })
92                    .then(function (resp) {
93                        if (resolved) return; // aborted
94                        if (!resp.ok) throw new Error('Presign request failed: ' + resp.status);
95                        return resp.json();
96                    })
97                    .then(function (presignData) {
98                        if (resolved) return; // aborted
99                        if (!presignData.status || !presignData.result || !presignData.result.uploads) {
100                            throw new Error(presignData.errors ? presignData.errors.join(', ') : 'Presign failed');
101                        }
102
103                        var uploads = presignData.result.uploads;
104                        if (uploads.length !== files.length) {
105                            throw new Error('Presign returned ' + uploads.length + ' slots for ' + files.length + ' files');
106                        }
107
108                        var uploadResults = [];
109
110                        // Serial upload chain — each file uploads after the previous completes
111                        var chain = Promise.resolve();
112
113                        files.forEach(function (file, i) {
114                            chain = chain.then(function () {
115                                if (resolved) return; // aborted
116                                var upload = uploads[i];
117                                var contentType = file.type || 'image/jpeg';
118                                return new Promise(function (res, rej) {
119                                    var xhr = new XMLHttpRequest();
120                                    activeXhr = xhr;
121                                    xhr.open('PUT', upload.upload_url, true);
122                                    xhr.setRequestHeader('Content-Type', contentType);
123                                    xhr.setRequestHeader('x-amz-acl', 'public-read');
124
125                                    xhr.upload.onprogress = function (e) {
126                                        if (e.lengthComputable) {
127                                            uppy.emit('upload-progress', file, {
128                                                bytesUploaded: e.loaded,
129                                                bytesTotal: e.total
130                                            });
131                                        }
132                                    };
133
134                                    xhr.onload = function () {
135                                        activeXhr = null;
136                                        if (xhr.status >= 200 && xhr.status < 300) {
137                                            uppy.emit('upload-success', file, { status: xhr.status });
138                                            uploadResults.push({
139                                                url: 'p:' + upload.upload_id,
140                                                filename: file.name,
141                                                type: contentType,
142                                                size: file.size,
143                                                key: i,
144                                                localUrl: URL.createObjectURL(file.data)
145                                            });
146                                            res();
147                                        } else {
148                                            var error = new Error('S3 upload failed: ' + xhr.status);
149                                            uppy.emit('upload-error', file, error);
150                                            rej(error);
151                                        }
152                                    };
153
154                                    xhr.onerror = function () {
155                                        activeXhr = null;
156                                        var error = new Error('Network error during upload');
157                                        uppy.emit('upload-error', file, error);
158                                        rej(error);
159                                    };
160
161                                    xhr.send(file.data);
162                                });
163                            });
164                        });
165
166                        return chain.then(function () {
167                            if (!resolved) {
168                                done(uploadResults);
169                            }
170                        });
171                    })
172                    .catch(function (err) {
173                        if (!resolved) {
174                            console.error('AppyS3Upload error:', err);
175                            _showError('Upload failed', err.message || 'Please try again.');
176                            done(null);
177                        }
178                    });
179            });
180
181            // Modal close: if uploading, abort; if idle, clean cancel
182            uppy.on('dashboard:modal-closed', function () {
183                done(null);
184            });
185
186            uppy.getPlugin('Dashboard').openModal();
187        });
188    }
189
190    return { open: open };
191})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.