var apx = apx || {}; apx.privatri = {}; apx.privatri.templates = {}; const apiUrl = "http://admin.apxtri.farm.test/api/apxtri/privatri" const tribe = "apxtri"; apx.privatri.loadwco = async (id, dataObj = {}, ctx = null) => { // check if not authenticate, do nothing cause by default screensignin and wait authentification // if authenticate, if url xhash then redirect if no url then change wco-link=screenmyworld // if (dayjs(apx.data.headers.xdays).diff(dayjs(), "hours") >= 24) apx.apxauth.checkisauth(); //load main.mustache of the component //when wco-xxx change it run this function console.log( `Load wconame:privatri apx.privatri.loadwco with id:${id} and ctx: ${JSON.stringify( ctx )}` ); const templatesObj = JSON.parse(localStorage.getItem("admin")).tpl; const template = Object.entries(templatesObj).find(([key]) => key.toLowerCase() === `privatri${id}`.toLocaleLowerCase())?.[1]; return Mustache.render(template, dataObj); }; async function getOldestPrivatriids(db, storeName) { const keysArray = await apx.indexedDB.getAllKeys(db, storeName); const oldestPerUuid = {}; for (const key of keysArray) { const [uuid, timestampStr] = key.split("_"); const timestamp = Number(timestampStr); if (!oldestPerUuid[uuid] || timestamp < oldestPerUuid[uuid].timestamp) { oldestPerUuid[uuid] = { key, timestamp }; }; }; const oldestKeysArray = Object.values(oldestPerUuid).map(obj => obj.key) const threadsArray = []; for (key of oldestKeysArray) { threadsArray.push(await apx.indexedDB.get(db, storeName, key)); }; return threadsArray; }; apx.privatri.syncronizeBackend = async (alias, lastConnection) => { const threadsArray = await getOldestPrivatriids("privatri", "messages"); for (const threadObj of threadsArray) { try { const response = await fetch(`${apiUrl}/${tribe}/${threadObj.thread}?since=${lastConnection}`); if (response.ok === false) { throw new Error("HTTP error"); }; console.log(response); // for (const message of response) { // await apx.indexedDB.set("privatri", "messages", message); // }; } catch (error) { const displayToastAlert = async (message) => { return await apx.privatri.loadwco("toastAlert", { message }); }; document.querySelector("body").insertAdjacentHTML("beforeend", await displayToastAlert("An error occurred while synchronizing messages. Please try again later.")); }; }; }; apx.privatri.templates.scripts = { createThread: async () => { const bodyEl = document.querySelector("body"); const autoDeletionBtnElArray = document.querySelectorAll("li.autoDeletionBtn"); const displayToastAlert = async (message) => { return await apx.privatri.loadwco("toastAlert", { message }); }; autoDeletionBtnElArray.forEach(btn => { btn.addEventListener("click", () => { autoDeletionBtnElArray.forEach(btn => btn.classList.remove("bg-base-200")); btn.classList.add("bg-base-200"); }); }); document.querySelector("#createThreadBtn").addEventListener("click", async () => { const { publicKey, privateKey } = await apx.crypto.genKey(); const messageObj = await (async (publicKey) => { const uuid = apx.crypto.genUUID(); const timestamp = Date.now(); const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("admin")).headers.xalias, publicKey); return { privatriid: `${uuid}_${timestamp}`, thread: uuid, timestamp: timestamp, owner: alias, title: await apx.crypto.encryptMessage(document.querySelector("#threadNameInput").value, publicKey), sender_alias: alias, publicKey: publicKey, aliases: [ alias ], message: await apx.crypto.encryptMessage(document.querySelector("#threadDescriptionInput").value, publicKey), dt_autodestruction: (() => { const selectedBtn = Array.from(autoDeletionBtnElArray).find(btn => btn.classList.contains("bg-base-200")); return parseInt(selectedBtn ? selectedBtn.getAttribute("data-auto-deletion") : 0, 10); })(), urgencydeletion: document.querySelector('input[type="checkbox"].toggle').checked }; })(publicKey); try { const response = await fetch(`${apiUrl}/${tribe}/${messageObj.thread}`, { method: "POST", headers: { "Content-Type": "application/json", "xdays": admin.headers.xdays, "xalias": admin.headers.xalias, "xlang": admin.headers.xlang, "xtribe": admin.headers.xtribe, "xapp": admin.headers.xapp, "xuuid": admin.headers.xuuid }, body: JSON.stringify(messageObj) }); if (response.ok === false) { throw new Error("HTTP error"); }; await apx.indexedDB.set("privatri", "threads", { uuid: messageObj.thread, privateKey: privateKey }); await apx.indexedDB.set("privatri", "messages", messageObj); bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("Thread created successfully.")); } catch (error) { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("An error occurred while creating the thread. Please try again later.")); }; }); }, inviteAlias: async () => { const url = "https://www.facebook.com/"; const bodyEl = document.querySelector("body"); const qrCodeCanvasEl = document.querySelector("#qrCodeCanvas"); const invitationLinkInputEl = document.querySelector("#invitationLinkInput"); const displayToastAlert = async (message) => { return await apx.privatri.loadwco("toastAlert", { message }); }; const qrCode = new QRCodeStyling({ width: 425, height: 425, type: "svg", data: url, image: "static/img/icons/privatri.png", dotsOptions: { color: "#ffffff", type: "rounded" }, backgroundOptions: { color: getComputedStyle(bodyEl).backgroundColor || "#000000", }, imageOptions: { crossOrigin: "anonymous", margin: 20 } }); qrCode.append(qrCodeCanvasEl); invitationLinkInputEl.value = url; copyBtn.addEventListener("click", async () => { navigator.clipboard.writeText(invitationLinkInputEl.value); bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("Invitation link copied to clipboard.")); setTimeout(() => { bodyEl.lastElementChild.remove(); }, 3000); }); }, threadAliasList: async () => { const bodyEl = document.querySelector("body"); const aliasListContainerEl = document.querySelector("#aliasListContainer"); let aliasesArray = []; const newAlias = async (alias) => { return await apx.privatri.loadwco("alias", { alias }); }; const displayToastAlert = async (message) => { return await apx.privatri.loadwco("toastAlert", { message }); }; const params = new URLSearchParams(window.location.search); const uuid = params.get("uuid"); const privateKey = (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey; const privatriidArray = await getOldestPrivatriids("privatri", "messages"); privatriidArray.forEach(async privatriid => { if (privatriid.thread === uuid) { messageObj = privatriid; aliasesArray = messageObj.aliases; const ownerAlias = messageObj.owner; for (const alias of aliasesArray) { aliasListContainerEl.insertAdjacentHTML("beforeend", await newAlias({ decrypted: (await apx.crypto.decryptMessage(alias, privateKey)).data, crypted: alias })); }; document.querySelectorAll("button.removeAliasBtn").forEach(btn => { btn.addEventListener("click", async () => { if (JSON.parse(localStorage.getItem("admin")).headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) { if (btn.getAttribute("data-alias") !== ownerAlias) { const alias = btn.getAttribute("data-alias"); aliasesArray = aliasesArray.filter(a => a !== alias); btn.parentElement.parentElement.remove(); privatriidArray.forEach(async privatriid => { if (privatriid.split("_")[0] === uuid) { const messageObj = await apx.indexedDB.get("privatri", "messages", privatriid); messageObj.aliases = aliasesArray; await apx.indexedDB.set("privatri", "messages", messageObj); }; }); } else { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You cannot remove the owner of the thread.")); setTimeout(() => { bodyEl.lastElementChild.remove(); }, 3000); }; } else { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to remove this alias.")); setTimeout(() => { bodyEl.lastElementChild.remove(); }, 3000); }; }); }); }; }); }, threadSettings: async () => { const bodyEl = document.querySelector("body"); const threadNameInputEl = document.querySelector("#threadNameInput"); const autoDeletionBtnElArray = document.querySelectorAll("li.autoDeletionBtn"); const applyModificationsBtnEl = document.querySelector("#applyModificationsBtn"); const displayToastAlert = async (message) => { return await apx.privatri.loadwco("toastAlert", { message }); }; let messageObj = {}; const params = new URLSearchParams(window.location.search); const uuid = params.get("uuid"); const privateKey = (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey; const privatriidArray = await getOldestPrivatriids("privatri", "messages"); let ownerAlias = ""; privatriidArray.forEach(async privatriid => { if (privatriid.thread === uuid) { messageObj = privatriid; ownerAlias = messageObj.owner; threadNameInputEl.value = (await apx.crypto.decryptMessage(messageObj.title, privateKey)).data; (Array.from(autoDeletionBtnElArray).find(el => el.getAttribute("data-auto-deletion") === String(messageObj.dt_autodestruction))).classList.add("bg-base-200"); if (messageObj.urgencydeletion === true) { document.querySelector('input[type="checkbox"].toggle').checked = true; }; }; }); applyModificationsBtnEl.addEventListener("click", async () => { if (JSON.parse(localStorage.getItem("admin")).headers.xalias === (await apx.crypto.decryptMessage(ownerAlias, privateKey)).data) { messageObj.title = await apx.crypto.encryptMessage(threadNameInputEl.value, privateKey); messageObj.dt_autodestruction = (() => { const selectedBtn = Array.from(autoDeletionBtnElArray).find(btn => btn.classList.contains("bg-base-200")); return parseInt(selectedBtn ? selectedBtn.getAttribute("data-auto-deletion") : 0, 10); })(); messageObj.urgencydeletion = document.querySelector('input[type="checkbox"].toggle').checked; await apx.indexedDB.set("privatri", "messages", messageObj); } else { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this thread.")); setTimeout(() => { bodyEl.lastElementChild.remove(); }, 3000); }; }); autoDeletionBtnElArray.forEach(btn => { btn.addEventListener("click", () => { autoDeletionBtnElArray.forEach(btn => btn.classList.remove("bg-base-200")); btn.classList.add("bg-base-200"); }); }); } }; apx.ready(async () => { document.querySelector("body").innerHTML = await apx.privatri.loadwco("main", JSON.parse(localStorage.getItem("admin")).tpldata.privatri_main_privatri); const bodyEl = document.querySelector("body"); const searchInputEl = document.querySelector("#threadSearchBar"); const threadFilterOptionsElArray = document.querySelector("#threadFilterOptions").querySelectorAll("li"); const threadsContainerEl = document.querySelector("#threadsContainer"); const threadPageEl = document.querySelector("#threadPage"); const messageInputEl = document.getElementById("messageInput"); const messagesContainerEl = document.querySelector("#messagesContainer"); const attachmentsInputEl = document.querySelector("#attachmentsInput"); await (async () => { const lastConnection = JSON.parse(localStorage.getItem("lastConnection")) || Date.now(); // await apx.privatri.syncronizeBackend(apx.data.headers.xalias, lastConnection); const privatriidArray = await getOldestPrivatriids("privatri", "messages"); console.log(privatriidArray); const thread = async (name, uuid) => { return await apx.privatri.loadwco("thread", { uuid, name }); }; for (const privatriidObj of privatriidArray) { const obj = await apx.indexedDB.get("privatri", "messages", privatriidObj.privatriid) const privateKey = (await apx.indexedDB.get("privatri", "threads", obj.thread)).privateKey; const name = (await apx.crypto.decryptMessage(obj.title, privateKey)).data; threadsContainerEl.insertAdjacentHTML("beforeend", await thread(name, obj.thread)); }; Array.from(threadsContainerEl.children).forEach(child => { child.addEventListener("click", async () => { const uuid = child.getAttribute("data-uuid"); const messagesObj = await new Promise((resolve, reject) => { const request = indexedDB.open("privatri", 1); request.onsuccess = (event) => { const db = event.target.result; const transaction = db.transaction("messages", "readonly"); const store = transaction.objectStore("messages"); const cursorRequest = store.openCursor(); const result = []; cursorRequest.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { const obj = cursor.value; const keyUuid = obj.privatriid.split("_")[0]; if (keyUuid === uuid) { result.push(obj); }; cursor.continue(); } else { resolve(result); }; }; cursorRequest.onerror = (event) => reject(event); }; request.onerror = (event) => reject(event); }); threadPageEl.setAttribute("data-uuid", uuid); threadPageEl.querySelector("#threadName").innerText = (await apx.crypto.decryptMessage(messagesObj[0].title, (await apx.indexedDB.get("privatri", "threads", uuid)).privateKey)).data; messagesContainerEl.innerHTML = ""; let privateKey = ""; for (const message of messagesObj) { if (privateKey === "") { privateKey = (await apx.indexedDB.get("privatri", "threads", message.thread)).privateKey; }; const decryptedMessage = (await apx.crypto.decryptMessage(message.message, privateKey)).data; let decryptedAttachments = []; if (message.attachments !== undefined) { decryptedAttachments = await (async () => { const attachmentsArray = []; if (message.attachments.length > 0) { for (const attachment of message.attachments) { attachmentsArray.push({ fileType: attachment.fileType, filename: attachment.filename, content: (await apx.crypto.decryptMessage(attachment.content, privateKey)).data }); }; }; return attachmentsArray; })(); }; messagesContainerEl.insertAdjacentHTML("beforeend", await sendNewMessage(message.timestamp, decryptedMessage, decryptedAttachments)); }; }); }); threadsContainerEl.children[0]?.click(); document.querySelectorAll("a").forEach(link => { link.addEventListener("click", async (event) => { event.preventDefault(); window.history.replaceState({}, document.title, window.location.pathname); const templateName = link.getAttribute("data-template"); if (templateName === "threadAliasList" || templateName === "threadSettings") { window.history.pushState({}, "", `${window.location.pathname}?uuid=${threadPageEl.getAttribute("data-uuid")}`); }; bodyEl.innerHTML = await apx.privatri.loadwco(templateName); await apx.privatri.templates.scripts[templateName](); }); }); })(); function formatDate(timestamp) { const date = new Date(timestamp); const day = String(date.getDate()).padStart(2, "0"); const month = String(date.getMonth() + 1).padStart(2, "0"); const year = date.getFullYear(); const hours = String(date.getHours()).padStart(2, "0"); const minutes = String(date.getMinutes()).padStart(2, "0"); return `${day}/${month}/${year} ${hours}:${minutes}`; }; searchInputEl.addEventListener("input", () => { const value = searchInputEl.value.toLowerCase(); Array.from(threadsContainerEl.children).forEach(child => { if (child.querySelector("li > div").textContent.toLowerCase().includes(value)) { child.style.display = "block"; } else { child.style.display = "none"; }; }); }); threadFilterOptionsElArray.forEach(option => { option.addEventListener("click", async () => { const filter = option.getAttribute("data-filter"); if (filter === "date") { Array.from(threadsContainerEl.children).sort((a, b) => { return a.querySelector("li > span").getAttribute("data-timestamp") - b.querySelector("li > span").getAttribute("data-timestamp"); }).forEach(child => { threadsContainerEl.appendChild(child); }); } else if (filter === "name") { Array.from(threadsContainerEl.children).sort((a, b) => { return a.querySelector("li > div").textContent.localeCompare(b.querySelector("li > div").textContent); }).forEach(child => { threadsContainerEl.appendChild(child); }); }; }); }); const sendNewMessage = async (timestamp, message, attachmentsArray) => { const messageTemplate = await apx.privatri.loadwco("message", { timestamp, message, date: formatDate(timestamp) }); const tempNode = document.createElement("div"); tempNode.innerHTML = messageTemplate; const messageNode = tempNode.firstElementChild; attachmentsArray.forEach(attachment => { messageNode.querySelector("div.attachmentsContainer").insertAdjacentHTML("beforeend", `${attachment.filename}`); }); return messageNode.outerHTML; }; const editMessage = async (timestamp, message) => { return await apx.privatri.loadwco("editMessage", { message, date: formatDate(timestamp) }); }; const displayToastAlert = async (message) => { return await apx.privatri.loadwco("toastAlert", { message }); }; sendMessageBtn.addEventListener("click", async () => { const message = messageInputEl.value.trim(); if (message !== "") { const messageObj = await (async (publicKey) => { const timestamp = Date.now(); const alias = await apx.crypto.encryptMessage(JSON.parse(localStorage.getItem("admin")).headers.xalias, publicKey); return { privatriid: `${threadPageEl.getAttribute("data-uuid")}_${timestamp}`, timestamp: timestamp, sender_alias: alias, message: await apx.crypto.encryptMessage(message, publicKey), attachments: await (async () => { const attachmentsArray = []; const localAttachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || []; if (localAttachmentsArray.length > 0) { for (const attachment of localAttachmentsArray) { attachmentsArray.push( { fileType: attachment.fileType, filename: attachment.filename, content: await apx.crypto.encryptMessage(attachment.content, publicKey) } ); }; }; return attachmentsArray; })() }; })((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messagesContainerEl.firstElementChild.getAttribute("data-timestamp")}`)).publicKey); const newMessageHTML = await sendNewMessage(messageObj.timestamp, message, JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)) || []); sessionStorage.removeItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`); messagesContainerEl.insertAdjacentHTML("beforeend", newMessageHTML); messageInputEl.value = ""; try { const response = await fetch(`${apiUrl}/`); if (response.ok === false) { throw new Error("HTTP error"); }; await apx.indexedDB.set("privatri", "messages", messageObj); } catch (error) { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("An error occurred while sending the message. Please try again later.")); }; }; }); window.addEventListener("beforeunload", () => { localStorage.setItem("lastConnection", JSON.stringify(Date.now())); }); window.attachDeleteMessageEvent = async function attachDeleteMessageEvent(btn) { const messageEl = btn.parentElement.parentElement.parentElement; const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey; const signatureMessage = `${JSON.parse(localStorage.getItem("admin")).headers.xalias}_${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`; const signature = await apx.crypto.sign(signatureMessage, privateKey); let verified = false; // try { // verified = await fetch("", { // method: "GET", // body: JSON.stringify({ // message: signatureMessage, // signature: signature, // uuid: threadPageEl.getAttribute("data-uuid"), // timestamp: messageEl.getAttribute("data-timestamp"), // }) // }); // } catch (error) { // console.error("Error while verifying signature:", error); // }; const authorAlias = (await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, privateKey)).data; if ((JSON.parse(localStorage.getItem("admin")).headers.xalias === authorAlias) && (verified === true)) { await apx.indexedDB.del("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`); messageEl.remove(); } else { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to delete this message.")); setTimeout(() => { bodyEl.lastElementChild.remove(); }, 3000); }; }; window.attachEditMessageEvent = async function attachEditMessageEvent(btn) { const messageEl = btn.parentElement.parentElement.parentElement; const authorAlias = (await apx.crypto.decryptMessage((await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`)).sender_alias, (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey)).data; if (JSON.parse(localStorage.getItem("admin")).headers.xalias === authorAlias) { const messageValue = messageEl.querySelector("div.message").innerText; const attachmentsArray = (() => { const attachmentsArray = []; messageEl.querySelector("div.attachmentsContainer").querySelectorAll("img").forEach(img => { attachmentsArray.push( { fileType: img.getAttribute("src").match(/^data:(.*);base64,/)[1], filename: img.getAttribute("alt"), content: img.getAttribute("src").split(",")[1] } ); }); return attachmentsArray; })(); messageEl.innerHTML = await editMessage(parseInt(messageEl.getAttribute("data-timestamp"), 10), messageEl.querySelector("div.message").innerText); messageEl.querySelector("button.cancelEditBtn").addEventListener("click", async () => { const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`); messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, messageValue, attachmentsArray); }); messageEl.querySelector("button.saveEditBtn").addEventListener("click", async () => { const newMessageValue = messageEl.querySelector("textarea").value.trim(); if (newMessageValue !== "") { const privateKey = (await apx.indexedDB.get("privatri", "threads", threadPageEl.getAttribute("data-uuid"))).privateKey; const messageObj = await apx.indexedDB.get("privatri", "messages", `${threadPageEl.getAttribute("data-uuid")}_${messageEl.getAttribute("data-timestamp")}`); messageObj.message = await apx.crypto.encryptMessage(newMessageValue, privateKey), await apx.indexedDB.set("privatri", "messages", messageObj); messageEl.innerHTML = await sendNewMessage(messageObj.timestamp, newMessageValue, attachmentsArray); }; }); } else { bodyEl.insertAdjacentHTML("beforeend", await displayToastAlert("You don't have the permissions to edit this message.")); setTimeout(() => { bodyEl.lastElementChild.remove(); }, 3000); }; }; window.attachEventDisplayAttachment = function(img) { let overlay = document.getElementById("imageOverlay"); if (overlay === null) { overlay = document.createElement('div'); overlay.id = "imageOverlay"; overlay.style.position = "fixed"; overlay.style.top = 0; overlay.style.left = 0; overlay.style.width = "100vw"; overlay.style.height = "100vh"; overlay.style.background = "rgba(0, 0, 0, 0.75)"; overlay.style.display = "flex"; overlay.style.alignItems = "center"; overlay.style.justifyContent = "center"; overlay.style.zIndex = 999; overlay.onclick = () => { overlay.remove(); }; document.body.appendChild(overlay); } else { overlay.innerHTML = ""; overlay.style.display = "flex"; }; const fullScreenImage = document.createElement("img"); fullScreenImage.src = img.src; fullScreenImage.alt = img.alt; fullScreenImage.style.maxWidth = "90vw"; fullScreenImage.style.maxHeight = "90vh"; overlay.appendChild(fullScreenImage); }; document.querySelector("#attachmentsBtn").addEventListener("click", () => { attachmentsInputEl.click(); }); attachmentsInputEl.addEventListener("change", async () => { const filesArray = Array.from(attachmentsInputEl.files); const maxFileSize = 5 * 1024 * 1024; const maxSize = 512; for (const file of filesArray) { if (file.size <= maxFileSize) { const attachmentObj = await new Promise((resolve, reject) => { const attachmentObj = { fileType: file.type, filename: file.name, content: "" }; const img = new Image(); img.onload = () => { if (img.width > maxSize || img.height > maxSize) { let width = img.width; let height = img.height; if (width > maxSize) { height *= maxSize / width; width = maxSize; }; if (height > maxSize) { width *= maxSize / height; height = maxSize; }; const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); canvas.toBlob(blob => { const reader = new FileReader(); reader.onload = (event) => { attachmentObj.content = event.target.result.split(",")[1]; resolve(attachmentObj); }; reader.onerror = reject; reader.readAsDataURL(blob); }, "image/jpeg", 0.8); } else { const reader = new FileReader(); reader.onload = (event) => { attachmentObj.content = event.target.result.split(",")[1]; resolve(attachmentObj); }; reader.onerror = reject; reader.readAsDataURL(file); }; }; img.onerror = reject; img.src = URL.createObjectURL(file); return attachmentObj; }); if (sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`) === null) { sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify([attachmentObj])); } else { const attachmentsArray = JSON.parse(sessionStorage.getItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`)); attachmentsArray.push(attachmentObj); sessionStorage.setItem(`attachmentsArray_${threadPageEl.getAttribute("data-uuid")}`, JSON.stringify(attachmentsArray)); }; }; }; }); });