{"version":3,"file":"custom-multifile.min.js","sources":["custom-multifile.js"],"sourcesContent":["AlectaFastigheter = window.AlectaFastigheter || {};\r\n\r\n/**\r\n * Provides functionality for selecting and uploading multiple files.\r\n * @namespace AlectaFastigheter.CustomMultifile\r\n */\r\nAlectaFastigheter.CustomMultifile = (function (document) {\r\n\r\n const uploadedFiles = [];\r\n const TEXT_FILE_TYPE = 'Filen kan inte bifogas, godkända filtyper är doc docx rtf xls xlsx csv txt pdf jpg jpeg png gif.'\r\n\r\n /**\r\n * Initializes the multifile component by adding event listeners to file input elements.\r\n */\r\n const init = (el) => {\r\n\r\n clearFiles()\r\n if (!el) {\r\n const elements = document.querySelectorAll(\r\n '[data-fn-trigger=\"multifile\"]'\r\n );\r\n\r\n elements.forEach((elm) => {\r\n handleFileInput(elm);\r\n });\r\n } else {\r\n handleFileInput(el);\r\n }\r\n };\r\n\r\n /**\r\n * Sets the ID and \"for\" attribute of the file input and label elements, respectively.\r\n * @param {HTMLElement} el - The container element that holds the file input and label elements.\r\n * @param {string} id - The ID to use for the file input element.\r\n */\r\n const setFileInputAttributes = (el, id) => {\r\n const fileInput = el.querySelector('input[type=\"file\"]');\r\n const fileLabel = el.querySelector('label');\r\n\r\n fileInput.setAttribute('id', `${id}-input`);\r\n fileLabel.setAttribute('for', `${id}-input`);\r\n };\r\n\r\n /**\r\n * Handles the upload of a single file.\r\n * @param {string} id - The ID of the file input element that triggered the upload.\r\n * @param {File} file - The file to upload.\r\n */\r\n const handleFileUpload = (file, id) => {\r\n const { name } = file;\r\n const regexp = new RegExp(document.getElementById('filtyper-pattern').value)\r\n const isValidFiletype = regexp.test(name.toLowerCase());\r\n\r\n if (\r\n !isFileInArray(uploadedFiles, file) && isValidFiletype\r\n ) {\r\n uploadedFiles.push(file);\r\n }\r\n\r\n if (!isValidFiletype) {\r\n alert(TEXT_FILE_TYPE);\r\n }\r\n };\r\n\r\n /**\r\n * Handles the change event on file input elements, triggering the upload of any selected files.\r\n * @param {HTMLElement} el - The element that is the file input component.\r\n */\r\n const handleFileInput = (el) => {\r\n const id = el.getAttribute('data-fn-target-id');\r\n const fileInput = el.querySelector('input[type=\"file\"]');\r\n\r\n setFileInputAttributes(el, id);\r\n\r\n fileInput.addEventListener('change', (e) => {\r\n const fileList = e.target.files;\r\n [...fileList].forEach((file) => {\r\n handleFileUpload(file, id);\r\n });\r\n\r\n updateFileList(id);\r\n });\r\n };\r\n\r\n /**\r\n * Updates the file list displayed on the page.\r\n * @param {string} id - The ID of the container element for the file list.\r\n */\r\n const updateFileList = (id) => {\r\n const el = document.querySelector('#' + id);\r\n const objectURL = (f) => URL.createObjectURL(f);\r\n const downloadLink = (f) =>\r\n '' +\r\n f.name +\r\n '';\r\n const listHtml = (item) => `
  • ${downloadLink(item)} ${formatBytes(item.size)}
  • `;\r\n\r\n if (uploadedFiles.length !== 0) {\r\n const list = uploadedFiles.map((data) => listHtml(data));\r\n el.innerHTML = ``;\r\n\r\n uploadedFiles.forEach((f, i) => {\r\n const button = document.createElement('button');\r\n button.innerHTML = 'Ta bort';\r\n el.querySelectorAll('li')[i].prepend(button);\r\n\r\n button.addEventListener('click', function (e) {\r\n e.preventDefault();\r\n\r\n if (window.confirm('Vill du radera filen ' + f.name + '?')) {\r\n uploadedFiles.splice(i, 1);\r\n updateFileList(id);\r\n } else {\r\n return false;\r\n }\r\n });\r\n });\r\n } else {\r\n el.textContent = '';\r\n }\r\n };\r\n\r\n /**\r\n * Check if a file is already in the array of uploaded files.\r\n * @param {File} file - The file to check if it is in the array.\r\n * @returns {boolean} - Returns true if the file is in the array, false otherwise.\r\n */\r\n const isFileInArray = (files, file) => {\r\n for (var i = 0; i < files.length; i++) {\r\n var item = files[i];\r\n if (item.size === file.size && item.name === file.name) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Formats a given number of bytes into a human-readable format with units.\r\n * @param {number} bytes - The number of bytes to be formatted.\r\n * @param {number} [decimals=2] - The number of decimal places to display. Defaults to 2 if not provided.\r\n * @returns {string} - The formatted string with units.\r\n */\r\n const formatBytes = (bytes, decimals = 2) => {\r\n if (!+bytes) return '0 Bytes'\r\n\r\n const k = 1024\r\n const dm = decimals < 0 ? 0 : decimals\r\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\r\n\r\n const i = Math.floor(Math.log(bytes) / Math.log(k))\r\n\r\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`\r\n }\r\n\r\n /**\r\n * Computes the total size of the given list of files.\r\n * @param {FileList} files - The list of files to compute the size of.\r\n * @returns {number} The total size of the files, in bytes.\r\n */\r\n const sumFileSizes = (files) => {\r\n return [...files].reduce((totalSize, file) => {\r\n return totalSize + file.size\r\n }, 0)\r\n }\r\n\r\n /**\r\n * Get a new `FormData` object with all the uploaded files appended to it.\r\n * @returns {FormData} - A new `FormData` object with all uploaded files appended to it.\r\n */\r\n const getFilesFormData = () => {\r\n let filesFormData = new FormData();\r\n uploadedFiles.forEach((file) => {\r\n filesFormData.append('files[]', file);\r\n });\r\n\r\n return filesFormData;\r\n };\r\n\r\n /**\r\n * Clear all uploaded files and remove them from the DOM.\r\n */\r\n const clearFiles = () => {\r\n const elements = document.querySelectorAll('[data-fn-filelist]');\r\n elements.forEach((el) => {\r\n el.textContent = '';\r\n });\r\n uploadedFiles.length = 0;\r\n };\r\n\r\n const getMaxFileSize = () => {\r\n return parseInt(document.getElementById('max-filstorlek').value);\r\n };\r\n\r\n const getValidationText = () => {\r\n\r\n let max_size = getMaxFileSize() / 1024;\r\n\r\n return `Den totala storleken av alla filer får vara högst ${max_size.toString()} MB.`; \r\n };\r\n\r\n return {\r\n init: init,\r\n clearFiles: clearFiles,\r\n getMaxFileSize: getMaxFileSize,\r\n getValidationText: getValidationText,\r\n sumFileSizes: sumFileSizes,\r\n getFilesFormData: getFilesFormData,\r\n uploadedFiles: uploadedFiles\r\n };\r\n})(document);\r\n\r\nAlectaFastigheter.CustomMultifile.init();"],"names":["AlectaFastigheter","window","CustomMultifile","document","uploadedFiles","setFileInputAttributes","el","id","fileInput","querySelector","fileLabel","setAttribute","handleFileUpload","file","name","isValidFiletype","RegExp","getElementById","value","test","toLowerCase","files","i","length","item","size","push","alert","handleFileInput","getAttribute","addEventListener","e","target","forEach","updateFileList","objectURL","URL","createObjectURL","f","listHtml","type","bytes","decimals","k","dm","sizes","Math","floor","log","parseFloat","pow","toFixed","list","map","data","innerHTML","join","toString","button","createElement","querySelectorAll","prepend","preventDefault","confirm","splice","textContent","clearFiles","getMaxFileSize","parseInt","init","elm","getValidationText","sumFileSizes","reduce","totalSize","getFilesFormData","let","filesFormData","FormData","append"],"mappings":"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"}