diff --git a/Oqtane.Maui/wwwroot/js/interop.js b/Oqtane.Maui/wwwroot/js/interop.js index 675cebca..719eb63e 100644 --- a/Oqtane.Maui/wwwroot/js/interop.js +++ b/Oqtane.Maui/wwwroot/js/interop.js @@ -120,13 +120,22 @@ Oqtane.Interop = { this.includeLink(links[i].id, links[i].rel, links[i].href, links[i].type, links[i].integrity, links[i].crossorigin, links[i].insertbefore); } }, - includeScript: function (id, src, integrity, crossorigin, type, content, location) { + includeScript: function (id, src, integrity, crossorigin, type, content, location, dataAttributes) { var script; if (src !== "") { script = document.querySelector("script[src=\"" + CSS.escape(src) + "\"]"); } else { - script = document.getElementById(id); + if (id !== "") { + script = document.getElementById(id); + } else { + const scripts = document.querySelectorAll("script:not([src])"); + for (let i = 0; i < scripts.length; i++) { + if (scripts[i].textContent.includes(content)) { + script = scripts[i]; + } + } + } } if (script !== null) { script.remove(); @@ -152,37 +161,36 @@ Oqtane.Interop = { else { script.innerHTML = content; } - script.async = false; - this.addScript(script, location) - .then(() => { - if (src !== "") { - console.log(src + ' loaded'); - } - else { - console.log(id + ' loaded'); - } - }) - .catch(() => { - if (src !== "") { - console.error(src + ' failed'); - } - else { - console.error(id + ' failed'); - } - }); + if (dataAttributes !== null) { + for (var key in dataAttributes) { + script.setAttribute(key, dataAttributes[key]); + } + } + + try { + this.addScript(script, location); + } catch (error) { + if (src !== "") { + console.error("Failed to load external script: ${src}", error); + } else { + console.error("Failed to load inline script: ${content}", error); + } + } } }, addScript: function (script, location) { - if (location === 'head') { - document.head.appendChild(script); - } - if (location === 'body') { - document.body.appendChild(script); - } + return new Promise((resolve, reject) => { + script.async = false; + script.defer = false; - return new Promise((res, rej) => { - script.onload = res(); - script.onerror = rej(); + script.onload = () => resolve(); + script.onerror = (error) => reject(error); + + if (location === 'head') { + document.head.appendChild(script); + } else { + document.body.appendChild(script); + } }); }, includeScripts: async function (scripts) { @@ -222,10 +230,10 @@ Oqtane.Interop = { if (scripts[s].crossorigin !== '') { element.crossOrigin = scripts[s].crossorigin; } - if (scripts[s].es6module === true) { - element.type = "module"; + if (scripts[s].type !== '') { + element.type = scripts[s].type; } - if (typeof scripts[s].dataAttributes !== "undefined" && scripts[s].dataAttributes !== null) { + if (scripts[s].dataAttributes !== null) { for (var key in scripts[s].dataAttributes) { element.setAttribute(key, scripts[s].dataAttributes[key]); } @@ -300,97 +308,107 @@ Oqtane.Interop = { } return files; }, - uploadFiles: function (posturl, folder, id, antiforgerytoken, jwt) { + uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize) { + var success = true; var fileinput = document.getElementById('FileInput_' + id); var progressinfo = document.getElementById('ProgressInfo_' + id); var progressbar = document.getElementById('ProgressBar_' + id); + var totalSize = 0; + for (var i = 0; i < fileinput.files.length; i++) { + totalSize += fileinput.files[i].size; + } + let uploadSize = 0; + + if (!chunksize || chunksize < 1) { + chunksize = 1; // 1 MB default + } + if (progressinfo !== null && progressbar !== null) { - progressinfo.setAttribute("style", "display: inline;"); - progressinfo.innerHTML = ''; - progressbar.setAttribute("style", "width: 100%; display: inline;"); + progressinfo.setAttribute('style', 'display: inline;'); + if (fileinput.files.length > 1) { + progressinfo.innerHTML = fileinput.files[0].name + ', ...'; + } + else { + progressinfo.innerHTML = fileinput.files[0].name; + } + progressbar.setAttribute('style', 'width: 100%; display: inline;'); progressbar.value = 0; } - var files = fileinput.files; - var totalSize = 0; - for (var i = 0; i < files.length; i++) { - totalSize = totalSize + files[i].size; + const uploadFile = (file) => { + const chunkSize = chunksize * (1024 * 1024); + const totalParts = Math.ceil(file.size / chunkSize); + let partCount = 0; + + const uploadPart = () => { + const start = partCount * chunkSize; + const end = Math.min(start + chunkSize, file.size); + const chunk = file.slice(start, end); + + return new Promise((resolve, reject) => { + let formdata = new FormData(); + formdata.append('__RequestVerificationToken', antiforgerytoken); + formdata.append('folder', folder); + formdata.append('formfile', chunk, file.name); + + var credentials = 'same-origin'; + var headers = new Headers(); + headers.append('PartCount', partCount + 1); + headers.append('TotalParts', totalParts); + if (jwt !== "") { + headers.append('Authorization', 'Bearer ' + jwt); + credentials = 'include'; + } + + return fetch(posturl, { + method: 'POST', + headers: headers, + credentials: credentials, + body: formdata + }) + .then(response => { + if (!response.ok) { + if (progressinfo !== null) { + progressinfo.innerHTML = 'Error: ' + response.statusText; + } + throw new Error('Failed'); + } + return; + }) + .then(data => { + partCount++; + if (progressbar !== null) { + uploadSize += chunk.size; + var percent = Math.ceil((uploadSize / totalSize) * 100); + progressbar.value = (percent / 100); + } + if (partCount < totalParts) { + uploadPart().then(resolve).catch(reject); + } + else { + resolve(data); + } + }) + .catch(error => { + reject(error); + }); + }); + }; + + return uploadPart(); + }; + + try { + for (const file of fileinput.files) { + await uploadFile(file); + } + } catch (error) { + success = false; } - var maxChunkSizeMB = 1; - var bufferChunkSize = maxChunkSizeMB * (1024 * 1024); - var uploadedSize = 0; - - for (var i = 0; i < files.length; i++) { - var fileChunk = []; - var file = files[i]; - var fileStreamPos = 0; - var endPos = bufferChunkSize; - - while (fileStreamPos < file.size) { - fileChunk.push(file.slice(fileStreamPos, endPos)); - fileStreamPos = endPos; - endPos = fileStreamPos + bufferChunkSize; - } - - var totalParts = fileChunk.length; - var partCount = 0; - - while (chunk = fileChunk.shift()) { - partCount++; - var fileName = file.name + ".part_" + partCount.toString().padStart(3, '0') + "_" + totalParts.toString().padStart(3, '0'); - - var data = new FormData(); - data.append('__RequestVerificationToken', antiforgerytoken); - data.append('folder', folder); - data.append('formfile', chunk, fileName); - var request = new XMLHttpRequest(); - request.open('POST', posturl, true); - if (jwt !== "") { - request.setRequestHeader('Authorization', 'Bearer ' + jwt); - request.withCredentials = true; - } - request.upload.onloadstart = function (e) { - if (progressinfo !== null && progressbar !== null && progressinfo.innerHTML === '') { - if (files.length === 1) { - progressinfo.innerHTML = file.name; - } - else { - progressinfo.innerHTML = file.name + ", ..."; - } - } - }; - request.upload.onprogress = function (e) { - if (progressinfo !== null && progressbar !== null) { - var percent = Math.ceil(((uploadedSize + e.loaded) / totalSize) * 100); - progressbar.value = (percent / 100); - } - }; - request.upload.onloadend = function (e) { - if (progressinfo !== null && progressbar !== null) { - uploadedSize = uploadedSize + e.total; - var percent = Math.ceil((uploadedSize / totalSize) * 100); - progressbar.value = (percent / 100); - } - }; - request.upload.onerror = function() { - if (progressinfo !== null && progressbar !== null) { - if (files.length === 1) { - progressinfo.innerHTML = file.name + ' Error: ' + request.statusText; - } - else { - progressinfo.innerHTML = ' Error: ' + request.statusText; - } - } - }; - request.send(data); - } - - if (i === files.length - 1) { - fileinput.value = ''; - } - } + fileinput.value = ''; + return success; }, refreshBrowser: function (verify, wait) { async function attemptReload (verify) {