607 lines
22 KiB
JavaScript
607 lines
22 KiB
JavaScript
var Oqtane = Oqtane || {};
|
|
|
|
Oqtane.Interop = {
|
|
setCookie: function (name, value, days, secure, sameSite) {
|
|
var d = new Date();
|
|
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
var expires = "expires=" + d.toUTCString();
|
|
var cookieString = name + "=" + value + ";" + expires + ";path=/";
|
|
if (secure) {
|
|
cookieString += "; secure";
|
|
}
|
|
if (sameSite === "Lax" || sameSite === "Strict" || sameSite === "None") {
|
|
cookieString += "; SameSite=" + sameSite;
|
|
}
|
|
document.cookie = cookieString;
|
|
},
|
|
getCookie: function (name) {
|
|
name = name + "=";
|
|
var decodedCookie = decodeURIComponent(document.cookie);
|
|
var ca = decodedCookie.split(';');
|
|
for (var i = 0; i < ca.length; i++) {
|
|
var c = ca[i];
|
|
while (c.charAt(0) === ' ') {
|
|
c = c.substring(1);
|
|
}
|
|
if (c.indexOf(name) === 0) {
|
|
return c.substring(name.length, c.length);
|
|
}
|
|
}
|
|
return "";
|
|
},
|
|
updateTitle: function (title) {
|
|
if (document.title !== title) {
|
|
document.title = title;
|
|
}
|
|
},
|
|
includeMeta: function (id, attribute, name, content) {
|
|
var meta = document.querySelector("meta[" + attribute + "=\"" + CSS.escape(name) + "\"]");
|
|
if (meta === null) {
|
|
meta = document.createElement("meta");
|
|
meta.setAttribute(attribute, name);
|
|
if (id !== "") {
|
|
meta.id = id;
|
|
}
|
|
meta.content = content;
|
|
document.head.appendChild(meta);
|
|
}
|
|
else {
|
|
if (id !== "") {
|
|
meta.setAttribute("id", id);
|
|
}
|
|
if (meta.content !== content) {
|
|
meta.setAttribute("content", content);
|
|
}
|
|
}
|
|
},
|
|
includeLink: function (id, rel, href, type, integrity, crossorigin, insertbefore) {
|
|
var link = document.querySelector("link[href=\"" + CSS.escape(href) + "\"]");
|
|
if (link === null) {
|
|
link = document.createElement("link");
|
|
if (id !== "") {
|
|
link.id = id;
|
|
}
|
|
link.rel = rel;
|
|
if (type !== "") {
|
|
link.type = type;
|
|
}
|
|
link.href = href;
|
|
if (integrity !== "") {
|
|
link.integrity = integrity;
|
|
}
|
|
if (crossorigin !== "") {
|
|
link.crossOrigin = crossorigin;
|
|
}
|
|
if (insertbefore === "") {
|
|
document.head.appendChild(link);
|
|
}
|
|
else {
|
|
var sibling = document.getElementById(insertbefore);
|
|
sibling.parentNode.insertBefore(link, sibling);
|
|
}
|
|
}
|
|
else {
|
|
if (link.id !== id) {
|
|
link.setAttribute('id', id);
|
|
}
|
|
if (link.rel !== rel) {
|
|
link.setAttribute('rel', rel);
|
|
}
|
|
if (type !== "") {
|
|
if (link.type !== type) {
|
|
link.setAttribute('type', type);
|
|
}
|
|
} else {
|
|
link.removeAttribute('type');
|
|
}
|
|
if (link.href !== this.getAbsoluteUrl(href)) {
|
|
link.removeAttribute('integrity');
|
|
link.removeAttribute('crossorigin');
|
|
link.setAttribute('href', href);
|
|
}
|
|
if (integrity !== "") {
|
|
if (link.integrity !== integrity) {
|
|
link.setAttribute('integrity', integrity);
|
|
}
|
|
} else {
|
|
link.removeAttribute('integrity');
|
|
}
|
|
if (crossorigin !== "") {
|
|
if (link.crossOrigin !== crossorigin) {
|
|
link.setAttribute('crossorigin', crossorigin);
|
|
}
|
|
} else {
|
|
link.removeAttribute('crossorigin');
|
|
}
|
|
}
|
|
},
|
|
includeLinks: function (links) {
|
|
for (let i = 0; i < links.length; i++) {
|
|
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, dataAttributes) {
|
|
var script;
|
|
if (src !== "") {
|
|
script = document.querySelector("script[src=\"" + CSS.escape(src) + "\"]");
|
|
}
|
|
else {
|
|
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();
|
|
script = null;
|
|
}
|
|
if (script === null) {
|
|
script = document.createElement("script");
|
|
if (id !== "") {
|
|
script.id = id;
|
|
}
|
|
if (type !== "") {
|
|
script.type = type;
|
|
}
|
|
if (src !== "") {
|
|
script.src = src;
|
|
if (integrity !== "") {
|
|
script.integrity = integrity;
|
|
}
|
|
if (crossorigin !== "") {
|
|
script.crossOrigin = crossorigin;
|
|
}
|
|
}
|
|
else {
|
|
script.innerHTML = content;
|
|
}
|
|
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) {
|
|
return new Promise((resolve, reject) => {
|
|
script.async = false;
|
|
script.defer = false;
|
|
|
|
script.onload = () => resolve();
|
|
script.onerror = (error) => reject(error);
|
|
|
|
if (location === 'head') {
|
|
document.head.appendChild(script);
|
|
} else {
|
|
document.body.appendChild(script);
|
|
}
|
|
});
|
|
},
|
|
includeScripts: async function (scripts) {
|
|
const bundles = [];
|
|
for (let s = 0; s < scripts.length; s++) {
|
|
if (scripts[s].bundle === '') {
|
|
scripts[s].bundle = scripts[s].href;
|
|
}
|
|
if (!bundles.includes(scripts[s].bundle)) {
|
|
bundles.push(scripts[s].bundle);
|
|
}
|
|
}
|
|
const promises = [];
|
|
for (let b = 0; b < bundles.length; b++) {
|
|
const urls = [];
|
|
for (let s = 0; s < scripts.length; s++) {
|
|
if (scripts[s].bundle === bundles[b]) {
|
|
urls.push(scripts[s].href);
|
|
}
|
|
}
|
|
promises.push(new Promise((resolve, reject) => {
|
|
if (loadjs.isDefined(bundles[b])) {
|
|
loadjs.ready(bundles[b], () => {
|
|
resolve(true);
|
|
});
|
|
}
|
|
else {
|
|
loadjs(urls, bundles[b], {
|
|
async: false,
|
|
returnPromise: true,
|
|
before: function (path, element) {
|
|
for (let s = 0; s < scripts.length; s++) {
|
|
if (path === scripts[s].href) {
|
|
if (scripts[s].integrity !== '') {
|
|
element.integrity = scripts[s].integrity;
|
|
}
|
|
if (scripts[s].crossorigin !== '') {
|
|
element.crossOrigin = scripts[s].crossorigin;
|
|
}
|
|
if (scripts[s].type !== '') {
|
|
element.type = scripts[s].type;
|
|
}
|
|
if (scripts[s].dataAttributes !== null) {
|
|
for (var key in scripts[s].dataAttributes) {
|
|
element.setAttribute(key, scripts[s].dataAttributes[key]);
|
|
}
|
|
}
|
|
if (scripts[s].location === 'body') {
|
|
document.body.appendChild(element);
|
|
return false; // return false to bypass default DOM insertion mechanism
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.then(function () { resolve(true) })
|
|
.catch(function (pathsNotFound) { reject(false) });
|
|
}
|
|
}));
|
|
}
|
|
if (promises.length !== 0) {
|
|
await Promise.all(promises);
|
|
}
|
|
},
|
|
getAbsoluteUrl: function (url) {
|
|
var a = document.createElement('a');
|
|
getAbsoluteUrl = function (url) {
|
|
a.href = url;
|
|
return a.href;
|
|
}
|
|
return getAbsoluteUrl(url);
|
|
},
|
|
removeElementsById: function (prefix, first, last) {
|
|
var elements = document.querySelectorAll('[id^=' + prefix + ']');
|
|
for (var i = elements.length - 1; i >= 0; i--) {
|
|
var element = elements[i];
|
|
if (element.id.startsWith(prefix) && (first === '' || element.id >= first) && (last === '' || element.id <= last)) {
|
|
element.parentNode.removeChild(element);
|
|
}
|
|
}
|
|
},
|
|
getElementByName: function (name) {
|
|
var elements = document.getElementsByName(name);
|
|
if (elements.length) {
|
|
return elements[0].value;
|
|
} else {
|
|
return "";
|
|
}
|
|
},
|
|
submitForm: function (path, fields) {
|
|
const form = document.createElement('form');
|
|
form.method = 'post';
|
|
form.action = path;
|
|
|
|
for (const key in fields) {
|
|
if (fields.hasOwnProperty(key)) {
|
|
const hiddenField = document.createElement('input');
|
|
hiddenField.type = 'hidden';
|
|
hiddenField.name = key;
|
|
hiddenField.value = fields[key];
|
|
form.appendChild(hiddenField);
|
|
}
|
|
}
|
|
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
},
|
|
getFiles: function (id) {
|
|
var files = [];
|
|
var fileinput = document.getElementById(id);
|
|
if (fileinput !== null) {
|
|
for (var i = 0; i < fileinput.files.length; i++) {
|
|
files.push(fileinput.files[i].name + ":" + fileinput.files[i].size);
|
|
}
|
|
}
|
|
return files;
|
|
},
|
|
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; // 1 MB default
|
|
}
|
|
|
|
if (progressinfo !== null && progressbar !== null) {
|
|
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;
|
|
}
|
|
|
|
const uploadFiles = Array.from(fileinput.files).map(file => {
|
|
const uploadFile = () => {
|
|
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();
|
|
};
|
|
|
|
return uploadFile();
|
|
});
|
|
|
|
try {
|
|
await Promise.all(uploadFiles);
|
|
} catch (error) {
|
|
success = false;
|
|
}
|
|
|
|
fileinput.value = '';
|
|
return success;
|
|
},
|
|
uploadFile: function (posturl, folder, id, antiforgerytoken, jwt, chunksize, totalsize, file) {
|
|
var fileinput = document.getElementById('FileInput_' + id);
|
|
var progressinfo = document.getElementById('ProgressInfo_' + id);
|
|
var progressbar = document.getElementById('ProgressBar_' + id);
|
|
|
|
if (file === null && fileinput !== null) {
|
|
file = fileinput.files[0];
|
|
totalsize = file.size;
|
|
}
|
|
|
|
if (progressinfo !== null && progressbar !== null && fileinput.files.length === 1) {
|
|
progressinfo.setAttribute("style", "display: inline;");
|
|
progressinfo.innerHTML = file.name;
|
|
progressbar.setAttribute("style", "width: 100%; display: inline;");
|
|
progressbar.value = 0;
|
|
}
|
|
|
|
if (!chunksize) {
|
|
chunksize = 1; // 1 MB default
|
|
}
|
|
const chunkSize = chunksize * (1024 * 1024);
|
|
let uploadSize = 0;
|
|
const totalParts = Math.ceil(file.size / chunkSize);
|
|
let partCount = 0;
|
|
const maxThreads = 1;
|
|
let threadCount = 1;
|
|
|
|
const uploadPart = () => {
|
|
const start = partCount * chunkSize;
|
|
const end = Math.min(start + chunkSize, file.size);
|
|
const chunk = file.slice(start, end);
|
|
|
|
while (threadCount > maxThreads) {
|
|
// wait for thread to become available
|
|
}
|
|
threadCount++;
|
|
|
|
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');
|
|
}
|
|
if (progressbar !== null) {
|
|
progressbar.value = 1;
|
|
}
|
|
return;
|
|
})
|
|
.then(data => {
|
|
partCount++;
|
|
if (progressbar !== null) {
|
|
uploadSize += chunk.size;
|
|
var percent = Math.ceil((uploadSize / totalsize) * 100);
|
|
progressbar.value = (percent / 100);
|
|
}
|
|
threadCount--;
|
|
if (partCount < totalParts) {
|
|
uploadPart().then(resolve).catch(reject);
|
|
}
|
|
else {
|
|
resolve(data);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
reject(error);
|
|
});
|
|
});
|
|
};
|
|
|
|
return uploadPart();
|
|
},
|
|
refreshBrowser: function (verify, wait) {
|
|
async function attemptReload (verify) {
|
|
if (verify) {
|
|
await fetch('');
|
|
}
|
|
window.location.reload();
|
|
}
|
|
attemptReload(verify);
|
|
setInterval(attemptReload, wait * 1000);
|
|
},
|
|
redirectBrowser: function (url, wait) {
|
|
setInterval(function () {
|
|
window.location.href = url;
|
|
}, wait * 1000);
|
|
},
|
|
formValid: function (formRef) {
|
|
return formRef.checkValidity();
|
|
},
|
|
setElementAttribute: function (id, attribute, value) {
|
|
var element = document.getElementById(id);
|
|
if (element !== null) {
|
|
element.setAttribute(attribute, value);
|
|
}
|
|
},
|
|
scrollTo: function (top, left, behavior) {
|
|
const modal = document.querySelector('.modal');
|
|
if (modal) {
|
|
modal.scrollTo({
|
|
top: top,
|
|
left: left,
|
|
behavior: behavior
|
|
});
|
|
} else {
|
|
window.scrollTo({
|
|
top: top,
|
|
left: left,
|
|
behavior: behavior
|
|
});
|
|
}
|
|
},
|
|
scrollToId: function (id) {
|
|
var element = document.getElementById(id);
|
|
if (element instanceof HTMLElement) {
|
|
element.scrollIntoView({
|
|
behavior: "smooth",
|
|
block: "start",
|
|
inline: "nearest"
|
|
});
|
|
}
|
|
},
|
|
getCaretPosition: function (id) {
|
|
var element = document.getElementById(id);
|
|
return element.selectionStart;
|
|
},
|
|
manageIndexedDBItems: async function (action, key, value) {
|
|
var idb = indexedDB.open("oqtane", 1);
|
|
|
|
idb.onupgradeneeded = function () {
|
|
let db = idb.result;
|
|
db.createObjectStore("items");
|
|
}
|
|
|
|
if (action.startsWith("get")) {
|
|
let request = new Promise((resolve) => {
|
|
idb.onsuccess = function () {
|
|
let transaction = idb.result.transaction("items", "readonly");
|
|
let collection = transaction.objectStore("items");
|
|
let result;
|
|
if (action === "get") {
|
|
result = collection.get(key);
|
|
}
|
|
if (action === "getallkeys") {
|
|
result = collection.getAllKeys();
|
|
}
|
|
|
|
result.onsuccess = function (e) {
|
|
resolve(result.result);
|
|
}
|
|
}
|
|
});
|
|
|
|
let result = await request;
|
|
|
|
return result;
|
|
}
|
|
else {
|
|
idb.onsuccess = function () {
|
|
let transaction = idb.result.transaction("items", "readwrite");
|
|
let collection = transaction.objectStore("items");
|
|
if (action === "put") {
|
|
collection.put(value, key);
|
|
}
|
|
if (action === "delete") {
|
|
collection.delete(key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|