Mercurial Hosting > linkmystyle
diff src/uploadcare/uploadcare.js @ 0:8f4df159f06b
start public repo
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 11 Jul 2025 20:57:49 -0600 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/uploadcare/uploadcare.js Fri Jul 11 20:57:49 2025 -0600 @@ -0,0 +1,267 @@ +'use strict'; + +let uploadcare = {}; + +/* + +to set an option: +uploadcare[option] = value + +from https://uploadcare.com/docs/uploads/file-uploader-options/ +publicKey, imagesOnly, doNotStore + +onError - function called with request for AJAX errors +maxFileSize - maximum file size of images in bytes + +*/ + +uploadcare.maxDim = 2000; +uploadcare.processingImage = '/uploadcare/processing.gif'; +uploadcare.cropprOptions = null; + +function logToServer(msg) { + ajax( '/log_info.js', 'msg='+encodeURIComponent(msg) ); +} + +{ + // compression + + function infoAddUrl(info) { + if( info.url ) + return; + return new Promise( function(resolve) { + let reader = new FileReader(); + reader.onload = function() { + info.url = reader.result; + resolve(); + }; + reader.readAsDataURL(info.file); + } ); + } + uploadcare.infoAddUrl = infoAddUrl; + + let croppr; + let dialog = null; + + async function infoAddCroppedImage(info) { + if( !dialog ) { + let html = ` + <dialog croppr> + <img> + <div buttons> + <button save>Save</button> + <button cancel>Cancel</button> + </div> + </dialog> +` ; + document.body.insertAdjacentHTML( 'beforeend', html ); + dialog = document.querySelector('dialog[croppr]'); + dialog.onclose = function() { + croppr.destroy(); + }; + } + await infoAddUrl(info); + let image = dialog.querySelector('img'); + image.src = info.url; + return new Promise( function(resolve) { + dialog.querySelector('button[save]').onclick = function() { + info.image = image; + info.crop = croppr.getValue(); + dialog.close(); + resolve(); + }; + dialog.querySelector('button[cancel]').onclick = function() { + info.canceled = true; + dialog.close(); + resolve(); + }; + image.onload = function() { + dialog.showModal(); + croppr = new Croppr( image, uploadcare.cropprOptions ); + }; + } ); + } + + let supportsDialog = typeof HTMLDialogElement === 'function'; + + async function infoAddImage(info) { + if( info.image ) + return; + if( uploadcare.cropprOptions && supportsDialog ) + return infoAddCroppedImage(info); + await infoAddUrl(info); + return new Promise( function(resolve) { + let image = new Image(); + info.image = image; + image.src = info.url; + image.onload = function() { + resolve(); + }; + } ); + } + + async function infoAddCanvas(info,maxDim) { + await infoAddImage(info); + if( info.canceled ) + return; + let image = info.image; + let width, height; + let crop = info.crop; + if( crop ) { + width = crop.width; + height = crop.height; + } else { + width = image.width; + height = image.height; + } + if( maxDim ) { + if( width > height ) { + if( width > maxDim ) { + height *= maxDim / width; + width = maxDim; + } + } else { + if( height > maxDim ) { + width *= maxDim / height; + height = maxDim; + } + } + } + let canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + let ctx = canvas.getContext('2d'); + if( crop ) { + ctx.drawImage( image, crop.x, crop.y, crop.width, crop.height, 0, 0, width, height ); + } else { + ctx.drawImage( image, 0, 0, width, height ); + } + info.canvas = canvas; + } + + async function infoAddBlob(info,maxDim) { + await infoAddCanvas(info,maxDim); + if( info.canceled ) + return; + return new Promise( function(resolve) { + function done(blob) { + info.blob = blob; + resolve(); + } + info.canvas.toBlob( done, 'image/jpeg' ); + } ); + } + + async function infoCompress(info) { + let file = info.file; + await infoAddBlob(info); + if( info.canceled ) + return; + let maxFileSize = uploadcare.maxFileSize; + if( !info.blob || maxFileSize && info.blob.size > maxFileSize ) { + await infoAddBlob(info,uploadcare.maxDim); + if( !info.blob ) throw 'no blob'; + } + info.compressed = info.blob; + info.compressedName = file.name.replace( /(\.[^.]*)?$/, '.jpeg' ); + } + uploadcare.infoCompress = infoCompress; + + + // uploading + + function onload(url,onSuccess,onError,count) { + count = count || 1; + let request = new XMLHttpRequest(); + request.open( 'GET', url ); + request.onload = function() { + if( request.status === 200 ) { + onSuccess(); + } else if( request.status === 404 ) { + console.log('onload failed '+count); + if( count >= 20 ) { + let text = 'Failed to get image after ' + count + ' tries, please try again'; + onError( request.status, text ); + return; + } + setTimeout( function() { + onload(url,onSuccess,onError,count+1); + }, 1000 ); + } else { + onError( request.status, request.responseText) ; + } + }; + request.send(); + } + + function call(file,filename,callback,onError) { + let request = new XMLHttpRequest(); + let url = 'https://upload.uploadcare.com/base/'; + request.open( 'POST', url ); + request.onload = function() { + if( request.status !== 200 ) { + onError( request.status, request.responseText ); + return; + } + let response = JSON.parse(request.responseText); + let uuid = response.file; + let url = 'https://ucarecdn.com/' + uuid + '/'; + function onSuccess() { + callback( uuid, file.name ); + } + onload( url, onSuccess, onError ); + }; + let formData = new FormData(); + formData.append( 'UPLOADCARE_PUB_KEY', uploadcare.publicKey ); + formData.append( 'UPLOADCARE_STORE', uploadcare.doNotStore ? '0' : '1' ); + formData.append( 'file', file, filename ); + request.send(formData); + } + + let input = null; + let img = null; + + function showImg() { + img.style.display = 'block'; + } + + function hideImg() { + img.style.display = 'none'; + } + + uploadcare.upload = function(callback) { + if( !uploadcare.publicKey ) + throw new Error('uploadcare.publicKey required'); + if( !input ) { + let html = ` + <input uploadcare type=file> + <img uploadcare src="${uploadcare.processingImage}"> +` ; + document.body.insertAdjacentHTML( 'beforeend', html ); + input = document.querySelector('input[uploadcare][type="file"]'); + img = document.querySelector('img[uploadcare]'); + } + input.accept = uploadcare.imagesOnly ? 'image/*' : ''; + input.onchange = async function() { + function onError(status,text) { + hideImg(); + if( text ) + alert(text); + if( uploadcare.onError ) + uploadcare.onError(status,text); + } + function callback2(uuid,filename) { + hideImg(); + callback(uuid,filename) + } + let info = { file: input.files[0] }; + input.value = null; + await infoCompress(info); + if( !info.canceled ) { + showImg(); + call(info.compressed,info.compressedName,callback2,onError); + } + }; + input.click(); + }; +}