1function downloadChunkUploadToken() { 2 var bytes = new Uint8Array(16); 3 window.crypto.getRandomValues(bytes); 4 return Array.from(bytes, function (byte) { 5 return byte.toString(16).padStart(2, "0"); 6 }).join(""); 7} 8 9function csrfToken() { 10 var meta = document.querySelector("meta[name='csrf-token']"); 11 return meta ? meta.getAttribute("content") : ""; 12} 13 14async function uploadDownloadChunk(url, uploadId, file, chunk, chunkIndex, totalChunks, form) { 15 var formData = new FormData(); 16 formData.append("upload_id", uploadId); 17 formData.append("chunk_index", chunkIndex); 18 formData.append("total_chunks", totalChunks); 19 formData.append("total_size", file.size); 20 formData.append("filename", file.name); 21 formData.append("content_type", file.type || "application/octet-stream"); 22 formData.append("chunk", chunk, file.name + ".part"); 23 24 if (form) { 25 new FormData(form).forEach(function (value, key) { 26 if (key !== "download[archivo]" && key !== "_method") formData.append(key, value); 27 }); 28 } 29 30 var response = await fetch(url, { 31 method: "POST", 32 headers: { 33 "X-CSRF-Token": csrfToken(), 34 "Accept": "application/json" 35 }, 36 body: formData, 37 credentials: "same-origin" 38 }); 39 40 var data = await response.json().catch(function () { 41 return {}; 42 }); 43 44 if (!response.ok) { 45 throw new Error(data.error || "No se pudo cargar una parte del archivo"); 46 } 47 48 return data; 49} 50 51function setDownloadChunkStatus(form, message) { 52 var status = form.querySelector("[data-download-chunk-status]"); 53 if (status) status.textContent = message || ""; 54} 55 56function bindDownloadChunkUploadForms() { 57 document.querySelectorAll("form[data-download-chunk-form='true']").forEach(function (form) { 58 if (form.dataset.downloadChunkBound === "true") return; 59 form.dataset.downloadChunkBound = "true"; 60 61 form.addEventListener("submit", async function (event) { 62 var input = form.querySelector("input[type='file'][name='download[archivo]']"); 63 var uploadUrl = form.dataset.chunkUploadUrl; 64 if (!input || !uploadUrl || !input.files || input.files.length === 0) return; 65 66 var file = input.files[0]; 67 var threshold = parseInt(form.dataset.chunkThresholdBytes, 10) || (4 * 1024 * 1024); 68 var chunkSize = parseInt(form.dataset.chunkSizeBytes, 10) || (1 * 1024 * 1024); 69 var maxUploadSize = parseInt(form.dataset.maxUploadSizeBytes, 10) || (100 * 1024 * 1024); 70 var maxUploadSizeMb = parseInt(form.dataset.maxUploadSizeMb, 10) || 100; 71 72 if (file.size > maxUploadSize) { 73 event.preventDefault(); 74 alert("El archivo \"" + file.name + "\" excede el tamaño máximo permitido de " + maxUploadSizeMb + " MB."); 75 return; 76 } 77 78 if (file.size <= threshold) return; 79 80 event.preventDefault(); 81 82 var submit = form.querySelector("input[type='submit'], button[type='submit']"); 83 var originalSubmitText = submit ? submit.value || submit.textContent : ""; 84 if (submit) { 85 submit.disabled = true; 86 if (submit.value !== undefined) submit.value = "Cargando archivo..."; 87 else submit.textContent = "Cargando archivo..."; 88 } 89 90 try { 91 var uploadId = downloadChunkUploadToken(); 92 var totalChunks = Math.ceil(file.size / chunkSize); 93 94 for (var index = 0; index < totalChunks; index++) { 95 var start = index * chunkSize; 96 var end = Math.min(start + chunkSize, file.size); 97 var chunk = file.slice(start, end); 98 99 var percent = Math.round(((index + 1) / totalChunks) * 100); 100 if (index === totalChunks - 1) { 101 setDownloadChunkStatus(form, "Procesando archivo final..."); 102 } else { 103 setDownloadChunkStatus(form, "Cargando archivo " + percent + "% (" + (index + 1) + " de " + totalChunks + ")..."); 104 } 105 106 var data = await uploadDownloadChunk(uploadUrl, uploadId, file, chunk, index, totalChunks, form); 107 if (data.complete) { 108 setDownloadChunkStatus(form, "Archivo cargado. Redirigiendo..."); 109 window.location.href = data.redirect_url || form.action; 110 return; 111 } 112 } 113 114 throw new Error("No se pudo completar la carga del archivo. Intenta cargarlo nuevamente."); 115 } catch (error) { 116 setDownloadChunkStatus(form, ""); 117 alert(error.message || "No se pudo cargar el archivo por partes."); 118 if (submit) { 119 submit.disabled = false;
120 if (submit.value !== undefined) submit.value = originalSubmitText; 121 else submit.textContent = originalSubmitText; 122 } 123 } 124 }); 125 }); 126} 127 128document.addEventListener("turbo:load", bindDownloadChunkUploadForms); 129document.addEventListener("DOMContentLoaded", bindDownloadChunkUploadForms); 130 131if (document.readyState !== "loading") { 132 bindDownloadChunkUploadForms(); 133};
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.