0
|
1 'use strict';
|
|
2
|
|
3 let uploadcare = {};
|
|
4
|
|
5 /*
|
|
6
|
|
7 to set an option:
|
|
8 uploadcare[option] = value
|
|
9
|
|
10 from https://uploadcare.com/docs/uploads/file-uploader-options/
|
|
11 publicKey, imagesOnly, doNotStore
|
|
12
|
|
13 onError - function called with request for AJAX errors
|
|
14 maxFileSize - maximum file size of images in bytes
|
|
15
|
|
16 */
|
|
17
|
|
18 uploadcare.maxDim = 2000;
|
|
19 uploadcare.processingImage = '/uploadcare/processing.gif';
|
|
20 uploadcare.cropprOptions = null;
|
|
21
|
|
22 function logToServer(msg) {
|
|
23 ajax( '/log_info.js', 'msg='+encodeURIComponent(msg) );
|
|
24 }
|
|
25
|
|
26 {
|
|
27 // compression
|
|
28
|
|
29 function infoAddUrl(info) {
|
|
30 if( info.url )
|
|
31 return;
|
|
32 return new Promise( function(resolve) {
|
|
33 let reader = new FileReader();
|
|
34 reader.onload = function() {
|
|
35 info.url = reader.result;
|
|
36 resolve();
|
|
37 };
|
|
38 reader.readAsDataURL(info.file);
|
|
39 } );
|
|
40 }
|
|
41 uploadcare.infoAddUrl = infoAddUrl;
|
|
42
|
|
43 let croppr;
|
|
44 let dialog = null;
|
|
45
|
|
46 async function infoAddCroppedImage(info) {
|
|
47 if( !dialog ) {
|
|
48 let html = `
|
|
49 <dialog croppr>
|
|
50 <img>
|
|
51 <div buttons>
|
|
52 <button save>Save</button>
|
|
53 <button cancel>Cancel</button>
|
|
54 </div>
|
|
55 </dialog>
|
|
56 ` ;
|
|
57 document.body.insertAdjacentHTML( 'beforeend', html );
|
|
58 dialog = document.querySelector('dialog[croppr]');
|
|
59 dialog.onclose = function() {
|
|
60 croppr.destroy();
|
|
61 };
|
|
62 }
|
|
63 await infoAddUrl(info);
|
|
64 let image = dialog.querySelector('img');
|
|
65 image.src = info.url;
|
|
66 return new Promise( function(resolve) {
|
|
67 dialog.querySelector('button[save]').onclick = function() {
|
|
68 info.image = image;
|
|
69 info.crop = croppr.getValue();
|
|
70 dialog.close();
|
|
71 resolve();
|
|
72 };
|
|
73 dialog.querySelector('button[cancel]').onclick = function() {
|
|
74 info.canceled = true;
|
|
75 dialog.close();
|
|
76 resolve();
|
|
77 };
|
|
78 image.onload = function() {
|
|
79 dialog.showModal();
|
|
80 croppr = new Croppr( image, uploadcare.cropprOptions );
|
|
81 };
|
|
82 } );
|
|
83 }
|
|
84
|
|
85 let supportsDialog = typeof HTMLDialogElement === 'function';
|
|
86
|
|
87 async function infoAddImage(info) {
|
|
88 if( info.image )
|
|
89 return;
|
|
90 if( uploadcare.cropprOptions && supportsDialog )
|
|
91 return infoAddCroppedImage(info);
|
|
92 await infoAddUrl(info);
|
|
93 return new Promise( function(resolve) {
|
|
94 let image = new Image();
|
|
95 info.image = image;
|
|
96 image.src = info.url;
|
|
97 image.onload = function() {
|
|
98 resolve();
|
|
99 };
|
|
100 } );
|
|
101 }
|
|
102
|
|
103 async function infoAddCanvas(info,maxDim) {
|
|
104 await infoAddImage(info);
|
|
105 if( info.canceled )
|
|
106 return;
|
|
107 let image = info.image;
|
|
108 let width, height;
|
|
109 let crop = info.crop;
|
|
110 if( crop ) {
|
|
111 width = crop.width;
|
|
112 height = crop.height;
|
|
113 } else {
|
|
114 width = image.width;
|
|
115 height = image.height;
|
|
116 }
|
|
117 if( maxDim ) {
|
|
118 if( width > height ) {
|
|
119 if( width > maxDim ) {
|
|
120 height *= maxDim / width;
|
|
121 width = maxDim;
|
|
122 }
|
|
123 } else {
|
|
124 if( height > maxDim ) {
|
|
125 width *= maxDim / height;
|
|
126 height = maxDim;
|
|
127 }
|
|
128 }
|
|
129 }
|
|
130 let canvas = document.createElement('canvas');
|
|
131 canvas.width = width;
|
|
132 canvas.height = height;
|
|
133 let ctx = canvas.getContext('2d');
|
|
134 if( crop ) {
|
|
135 ctx.drawImage( image, crop.x, crop.y, crop.width, crop.height, 0, 0, width, height );
|
|
136 } else {
|
|
137 ctx.drawImage( image, 0, 0, width, height );
|
|
138 }
|
|
139 info.canvas = canvas;
|
|
140 }
|
|
141
|
|
142 async function infoAddBlob(info,maxDim) {
|
|
143 await infoAddCanvas(info,maxDim);
|
|
144 if( info.canceled )
|
|
145 return;
|
|
146 return new Promise( function(resolve) {
|
|
147 function done(blob) {
|
|
148 info.blob = blob;
|
|
149 resolve();
|
|
150 }
|
|
151 info.canvas.toBlob( done, 'image/jpeg' );
|
|
152 } );
|
|
153 }
|
|
154
|
|
155 async function infoCompress(info) {
|
|
156 let file = info.file;
|
|
157 await infoAddBlob(info);
|
|
158 if( info.canceled )
|
|
159 return;
|
|
160 let maxFileSize = uploadcare.maxFileSize;
|
|
161 if( !info.blob || maxFileSize && info.blob.size > maxFileSize ) {
|
|
162 await infoAddBlob(info,uploadcare.maxDim);
|
|
163 if( !info.blob ) throw 'no blob';
|
|
164 }
|
|
165 info.compressed = info.blob;
|
|
166 info.compressedName = file.name.replace( /(\.[^.]*)?$/, '.jpeg' );
|
|
167 }
|
|
168 uploadcare.infoCompress = infoCompress;
|
|
169
|
|
170
|
|
171 // uploading
|
|
172
|
|
173 function onload(url,onSuccess,onError,count) {
|
|
174 count = count || 1;
|
|
175 let request = new XMLHttpRequest();
|
|
176 request.open( 'GET', url );
|
|
177 request.onload = function() {
|
|
178 if( request.status === 200 ) {
|
|
179 onSuccess();
|
|
180 } else if( request.status === 404 ) {
|
|
181 console.log('onload failed '+count);
|
|
182 if( count >= 20 ) {
|
|
183 let text = 'Failed to get image after ' + count + ' tries, please try again';
|
|
184 onError( request.status, text );
|
|
185 return;
|
|
186 }
|
|
187 setTimeout( function() {
|
|
188 onload(url,onSuccess,onError,count+1);
|
|
189 }, 1000 );
|
|
190 } else {
|
|
191 onError( request.status, request.responseText) ;
|
|
192 }
|
|
193 };
|
|
194 request.send();
|
|
195 }
|
|
196
|
|
197 function call(file,filename,callback,onError) {
|
|
198 let request = new XMLHttpRequest();
|
|
199 let url = 'https://upload.uploadcare.com/base/';
|
|
200 request.open( 'POST', url );
|
|
201 request.onload = function() {
|
|
202 if( request.status !== 200 ) {
|
|
203 onError( request.status, request.responseText );
|
|
204 return;
|
|
205 }
|
|
206 let response = JSON.parse(request.responseText);
|
|
207 let uuid = response.file;
|
|
208 let url = 'https://ucarecdn.com/' + uuid + '/';
|
|
209 function onSuccess() {
|
|
210 callback( uuid, file.name );
|
|
211 }
|
|
212 onload( url, onSuccess, onError );
|
|
213 };
|
|
214 let formData = new FormData();
|
|
215 formData.append( 'UPLOADCARE_PUB_KEY', uploadcare.publicKey );
|
|
216 formData.append( 'UPLOADCARE_STORE', uploadcare.doNotStore ? '0' : '1' );
|
|
217 formData.append( 'file', file, filename );
|
|
218 request.send(formData);
|
|
219 }
|
|
220
|
|
221 let input = null;
|
|
222 let img = null;
|
|
223
|
|
224 function showImg() {
|
|
225 img.style.display = 'block';
|
|
226 }
|
|
227
|
|
228 function hideImg() {
|
|
229 img.style.display = 'none';
|
|
230 }
|
|
231
|
|
232 uploadcare.upload = function(callback) {
|
|
233 if( !uploadcare.publicKey )
|
|
234 throw new Error('uploadcare.publicKey required');
|
|
235 if( !input ) {
|
|
236 let html = `
|
|
237 <input uploadcare type=file>
|
|
238 <img uploadcare src="${uploadcare.processingImage}">
|
|
239 ` ;
|
|
240 document.body.insertAdjacentHTML( 'beforeend', html );
|
|
241 input = document.querySelector('input[uploadcare][type="file"]');
|
|
242 img = document.querySelector('img[uploadcare]');
|
|
243 }
|
|
244 input.accept = uploadcare.imagesOnly ? 'image/*' : '';
|
|
245 input.onchange = async function() {
|
|
246 function onError(status,text) {
|
|
247 hideImg();
|
|
248 if( text )
|
|
249 alert(text);
|
|
250 if( uploadcare.onError )
|
|
251 uploadcare.onError(status,text);
|
|
252 }
|
|
253 function callback2(uuid,filename) {
|
|
254 hideImg();
|
|
255 callback(uuid,filename)
|
|
256 }
|
|
257 let info = { file: input.files[0] };
|
|
258 input.value = null;
|
|
259 await infoCompress(info);
|
|
260 if( !info.canceled ) {
|
|
261 showImg();
|
|
262 call(info.compressed,info.compressedName,callback2,onError);
|
|
263 }
|
|
264 };
|
|
265 input.click();
|
|
266 };
|
|
267 }
|