@formio/js 5.0.0-dev.5642.f9208f7 → 5.0.0-dev.5643.9c5173a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5689,7 +5689,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
5689
5689
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
5690
5690
 
5691
5691
  "use strict";
5692
- eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst Field_1 = __importDefault(__webpack_require__(/*! ../_classes/field/Field */ \"./lib/cjs/components/_classes/field/Field.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst downloadjs_1 = __importDefault(__webpack_require__(/*! downloadjs */ \"./node_modules/downloadjs/download.js\"));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst fileProcessor_1 = __importDefault(__webpack_require__(/*! ../../providers/processor/fileProcessor */ \"./lib/cjs/providers/processor/fileProcessor.js\"));\nconst browser_md5_file_1 = __importDefault(__webpack_require__(/*! browser-md5-file */ \"./node_modules/browser-md5-file/dist/index.umd.js\"));\nlet Camera;\nlet webViewCamera = 'undefined' !== typeof window ? navigator.camera : Camera;\n// canvas.toBlob polyfill.\nlet htmlCanvasElement;\nif (typeof window !== 'undefined') {\n htmlCanvasElement = window.HTMLCanvasElement;\n}\nelse if (typeof __webpack_require__.g !== 'undefined') {\n htmlCanvasElement = __webpack_require__.g.HTMLCanvasElement;\n}\nif (htmlCanvasElement && !htmlCanvasElement.prototype.toBlob) {\n Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {\n value: function (callback, type, quality) {\n var canvas = this;\n setTimeout(function () {\n var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]), len = binStr.length, arr = new Uint8Array(len);\n for (var i = 0; i < len; i++) {\n arr[i] = binStr.charCodeAt(i);\n }\n callback(new Blob([arr], { type: type || 'image/png' }));\n });\n }\n });\n}\nconst createRandomString = () => Math.random().toString(36).substring(2, 15);\nclass FileComponent extends Field_1.default {\n static schema(...extend) {\n return Field_1.default.schema({\n type: 'file',\n label: 'Upload',\n key: 'file',\n image: false,\n privateDownload: false,\n imageSize: '200',\n filePattern: '*',\n fileMinSize: '0KB',\n fileMaxSize: '1GB',\n uploadOnly: false,\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'File',\n group: 'premium',\n icon: 'file',\n documentation: '/userguide/form-building/premium-components#file',\n weight: 100,\n schema: FileComponent.schema(),\n };\n }\n static get serverConditionSettings() {\n return FileComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { operators: ['isEmpty', 'isNotEmpty'] });\n }\n static savedValueTypes(schema) {\n schema = schema || {};\n return (0, utils_1.getComponentSavedTypes)(schema) || [utils_1.componentValueTypes.object];\n }\n init() {\n super.init();\n webViewCamera = navigator.camera || Camera;\n const fileReaderSupported = (typeof FileReader !== 'undefined');\n const formDataSupported = typeof window !== 'undefined' ? Boolean(window.FormData) : false;\n const progressSupported = (typeof window !== 'undefined' && window.XMLHttpRequest) ? ('upload' in new XMLHttpRequest) : false;\n this.support = {\n filereader: fileReaderSupported,\n formdata: formDataSupported,\n hasWarning: !fileReaderSupported || !formDataSupported || !progressSupported,\n progress: progressSupported,\n };\n this.cameraMode = false;\n this.fileDropHidden = false;\n this.filesToSync = {\n filesToUpload: [],\n filesToDelete: [],\n };\n this.isSyncing = false;\n this.abortUploads = [];\n }\n get dataReady() {\n return this.filesReady || Promise.resolve();\n }\n get defaultSchema() {\n return FileComponent.schema();\n }\n loadImage(fileInfo) {\n if (this.component.privateDownload) {\n fileInfo.private = true;\n }\n return this.fileService.downloadFile(fileInfo).then((result) => result.url);\n }\n get emptyValue() {\n return [];\n }\n getValueAsString(value) {\n if (lodash_1.default.isArray(value)) {\n return lodash_1.default.map(value, 'originalName').join(', ');\n }\n return lodash_1.default.get(value, 'originalName', '');\n }\n getValue() {\n return this.dataValue;\n }\n get defaultValue() {\n const value = super.defaultValue;\n return Array.isArray(value) ? value : [];\n }\n get hasTypes() {\n return this.component.fileTypes &&\n Array.isArray(this.component.fileTypes) &&\n this.component.fileTypes.length !== 0 &&\n (this.component.fileTypes[0].label !== '' || this.component.fileTypes[0].value !== '');\n }\n get fileDropHidden() {\n return this._fileBrowseHidden;\n }\n set fileDropHidden(value) {\n if (typeof value !== 'boolean' || this.component.multiple) {\n return;\n }\n this._fileBrowseHidden = value;\n }\n get shouldSyncFiles() {\n return Boolean(this.filesToSync.filesToDelete.length || this.filesToSync.filesToUpload.length);\n }\n get autoSync() {\n return lodash_1.default.get(this, 'component.autoSync', false);\n }\n get columnsSize() {\n const actionsColumn = this.disabled ? 0 : this.autoSync ? 2 : 1;\n const typeColumn = this.hasTypes ? 2 : 0;\n const sizeColumn = 2;\n const nameColumn = 12 - actionsColumn - typeColumn - sizeColumn;\n return {\n name: nameColumn,\n size: sizeColumn,\n type: typeColumn,\n actions: actionsColumn,\n };\n }\n render() {\n const { filesToDelete, filesToUpload } = this.filesToSync;\n return super.render(this.renderTemplate('file', {\n fileSize: this.fileSize,\n files: this.dataValue || [],\n filesToDelete,\n filesToUpload,\n disabled: this.disabled,\n support: this.support,\n fileDropHidden: this.fileDropHidden,\n showSyncButton: this.autoSync && (filesToDelete.length || filesToUpload.length),\n isSyncing: this.isSyncing,\n columns: this.columnsSize,\n }));\n }\n getVideoStream(constraints) {\n return navigator.mediaDevices.getUserMedia({\n video: Object.assign({ width: { min: 640, ideal: 1920 }, height: { min: 360, ideal: 1080 }, aspectRatio: { ideal: 16 / 9 } }, constraints),\n audio: false,\n });\n }\n stopVideoStream(videoStream) {\n videoStream.getVideoTracks().forEach((track) => track.stop());\n }\n getFrame(videoPlayer) {\n return new Promise((resolve) => {\n const canvas = document.createElement('canvas');\n canvas.height = videoPlayer.videoHeight;\n canvas.width = videoPlayer.videoWidth;\n const context = canvas.getContext('2d');\n context.drawImage(videoPlayer, 0, 0);\n canvas.toBlob(resolve);\n });\n }\n startVideo() {\n this.getVideoStream()\n .then((stream) => {\n this.videoStream = stream;\n const { videoPlayer } = this.refs;\n if (!videoPlayer) {\n console.warn('Video player not found in template.');\n this.cameraMode = false;\n this.redraw();\n return;\n }\n videoPlayer.srcObject = stream;\n const width = parseInt(this.component.webcamSize) || 320;\n videoPlayer.setAttribute('width', width);\n videoPlayer.play();\n })\n .catch((err) => {\n console.error(err);\n this.cameraMode = false;\n this.redraw();\n });\n }\n stopVideo() {\n if (this.videoStream) {\n this.stopVideoStream(this.videoStream);\n this.videoStream = null;\n }\n }\n takePicture() {\n const { videoPlayer } = this.refs;\n if (!videoPlayer) {\n console.warn('Video player not found in template.');\n this.cameraMode = false;\n this.redraw();\n return;\n }\n this.getFrame(videoPlayer)\n .then((frame) => {\n frame.name = `photo-${Date.now()}.png`;\n this.handleFilesToUpload([frame]);\n this.cameraMode = false;\n this.redraw();\n });\n }\n browseFiles(attrs = {}) {\n return new Promise((resolve) => {\n const fileInput = this.ce('input', Object.assign({ type: 'file', style: 'height: 0; width: 0; visibility: hidden;', tabindex: '-1' }, attrs));\n document.body.appendChild(fileInput);\n fileInput.addEventListener('change', () => {\n resolve(fileInput.files);\n document.body.removeChild(fileInput);\n }, true);\n // There is no direct way to trigger a file dialog. To work around this, create an input of type file and trigger\n // a click event on it.\n if (typeof fileInput.trigger === 'function') {\n fileInput.trigger('click');\n }\n else {\n fileInput.click();\n }\n });\n }\n set cameraMode(value) {\n this._cameraMode = value;\n if (value) {\n this.startVideo();\n }\n else {\n this.stopVideo();\n }\n }\n get cameraMode() {\n return this._cameraMode;\n }\n get useWebViewCamera() {\n return this.imageUpload && webViewCamera;\n }\n get imageUpload() {\n return Boolean(this.component.image);\n }\n get browseOptions() {\n const options = {};\n if (this.component.multiple) {\n options.multiple = true;\n }\n if (this.component.capture) {\n options.capture = this.component.capture;\n }\n //use \"accept\" attribute only for desktop devices because of its limited support by mobile browsers\n const filePattern = this.component.filePattern.trim() || '';\n if (!this.isMobile.any) {\n const imagesPattern = 'image/*';\n if (this.imageUpload && (!filePattern || filePattern === '*')) {\n options.accept = imagesPattern;\n }\n else if (this.imageUpload && !filePattern.includes(imagesPattern)) {\n options.accept = `${imagesPattern},${filePattern}`;\n }\n else {\n options.accept = filePattern;\n }\n }\n // if input capture is set, we need the \"accept\" attribute to determine which device to launch\n else if (this.component.capture) {\n if (filePattern.includes('video')) {\n options.accept = 'video/*';\n }\n else if (filePattern.includes('audio')) {\n options.accept = 'audio/*';\n }\n else {\n options.accept = 'image/*';\n }\n }\n return options;\n }\n get actions() {\n return {\n abort: this.abortRequest.bind(this),\n };\n }\n attach(element) {\n this.loadRefs(element, {\n fileDrop: 'single',\n fileBrowse: 'single',\n galleryButton: 'single',\n cameraButton: 'single',\n takePictureButton: 'single',\n toggleCameraMode: 'single',\n videoPlayer: 'single',\n fileLink: 'multiple',\n removeLink: 'multiple',\n fileToSyncRemove: 'multiple',\n fileImage: 'multiple',\n fileType: 'multiple',\n fileProcessingLoader: 'single',\n syncNow: 'single',\n restoreFile: 'multiple',\n progress: 'multiple',\n });\n // Ensure we have an empty input refs. We need this for the setValue method to redraw the control when it is set.\n this.refs.input = [];\n const superAttach = super.attach(element);\n if (this.refs.fileDrop) {\n // if (!this.statuses.length) {\n // this.refs.fileDrop.removeAttribute('hidden');\n // }\n const _this = this;\n this.addEventListener(this.refs.fileDrop, 'dragover', function (event) {\n this.className = 'fileSelector fileDragOver';\n event.preventDefault();\n });\n this.addEventListener(this.refs.fileDrop, 'dragleave', function (event) {\n this.className = 'fileSelector';\n event.preventDefault();\n });\n this.addEventListener(this.refs.fileDrop, 'drop', function (event) {\n this.className = 'fileSelector';\n event.preventDefault();\n _this.handleFilesToUpload(event.dataTransfer.files);\n });\n }\n this.addEventListener(element, 'click', (event) => {\n this.handleAction(event);\n });\n if (this.refs.fileBrowse) {\n this.addEventListener(this.refs.fileBrowse, 'click', (event) => {\n event.preventDefault();\n this.browseFiles(this.browseOptions)\n .then((files) => {\n this.handleFilesToUpload(files);\n });\n });\n }\n this.refs.fileLink.forEach((fileLink, index) => {\n this.addEventListener(fileLink, 'click', (event) => {\n event.preventDefault();\n this.getFile(this.dataValue[index]);\n });\n });\n this.refs.removeLink.forEach((removeLink, index) => {\n this.addEventListener(removeLink, 'click', (event) => {\n event.preventDefault();\n const fileInfo = this.dataValue[index];\n this.handleFileToRemove(fileInfo);\n });\n });\n this.refs.fileToSyncRemove.forEach((fileToSyncRemove, index) => {\n this.addEventListener(fileToSyncRemove, 'click', (event) => {\n event.preventDefault();\n this.filesToSync.filesToUpload.splice(index, 1);\n this.redraw();\n });\n });\n this.refs.restoreFile.forEach((fileToRestore, index) => {\n this.addEventListener(fileToRestore, 'click', (event) => {\n event.preventDefault();\n const fileInfo = this.filesToSync.filesToDelete[index];\n delete fileInfo.status;\n delete fileInfo.message;\n this.filesToSync.filesToDelete.splice(index, 1);\n this.dataValue.push(fileInfo);\n this.triggerChange();\n this.redraw();\n });\n });\n if (this.refs.galleryButton && webViewCamera) {\n this.addEventListener(this.refs.galleryButton, 'click', (event) => {\n event.preventDefault();\n webViewCamera.getPicture((success) => {\n window.resolveLocalFileSystemURL(success, (fileEntry) => {\n fileEntry.file((file) => {\n const reader = new FileReader();\n reader.onloadend = (evt) => {\n const blob = new Blob([new Uint8Array(evt.target.result)], { type: file.type });\n blob.name = file.name;\n this.handleFilesToUpload([blob]);\n };\n reader.readAsArrayBuffer(file);\n });\n });\n }, (err) => {\n console.error(err);\n }, {\n sourceType: webViewCamera.PictureSourceType.PHOTOLIBRARY,\n });\n });\n }\n if (this.refs.cameraButton && webViewCamera) {\n this.addEventListener(this.refs.cameraButton, 'click', (event) => {\n event.preventDefault();\n webViewCamera.getPicture((success) => {\n window.resolveLocalFileSystemURL(success, (fileEntry) => {\n fileEntry.file((file) => {\n const reader = new FileReader();\n reader.onloadend = (evt) => {\n const blob = new Blob([new Uint8Array(evt.target.result)], { type: file.type });\n blob.name = file.name;\n this.handleFilesToUpload([blob]);\n };\n reader.readAsArrayBuffer(file);\n });\n });\n }, (err) => {\n console.error(err);\n }, {\n sourceType: webViewCamera.PictureSourceType.CAMERA,\n encodingType: webViewCamera.EncodingType.PNG,\n mediaType: webViewCamera.MediaType.PICTURE,\n saveToPhotoAlbum: true,\n correctOrientation: false,\n });\n });\n }\n if (this.refs.takePictureButton) {\n this.addEventListener(this.refs.takePictureButton, 'click', (event) => {\n event.preventDefault();\n this.takePicture();\n });\n }\n if (this.refs.toggleCameraMode) {\n this.addEventListener(this.refs.toggleCameraMode, 'click', (event) => {\n event.preventDefault();\n this.cameraMode = !this.cameraMode;\n this.redraw();\n });\n }\n this.refs.fileType.forEach((fileType, index) => {\n if (!this.dataValue[index]) {\n return;\n }\n this.dataValue[index].fileType = this.dataValue[index].fileType || this.component.fileTypes[0].label;\n this.addEventListener(fileType, 'change', (event) => {\n event.preventDefault();\n const fileType = this.component.fileTypes.find((typeObj) => typeObj.value === event.target.value);\n this.dataValue[index].fileType = fileType.label;\n });\n });\n this.addEventListener(this.refs.syncNow, 'click', (event) => {\n event.preventDefault();\n this.syncFiles();\n });\n const fileService = this.fileService;\n if (fileService) {\n const loadingImages = [];\n this.filesReady = new Promise((resolve, reject) => {\n this.filesReadyResolve = resolve;\n this.filesReadyReject = reject;\n });\n this.refs.fileImage.forEach((image, index) => {\n loadingImages.push(this.loadImage(this.dataValue[index]).then((url) => (image.src = url)));\n });\n if (loadingImages.length) {\n Promise.all(loadingImages).then(() => {\n this.filesReadyResolve();\n }).catch(() => this.filesReadyReject());\n }\n else {\n this.filesReadyResolve();\n }\n }\n return superAttach;\n }\n /* eslint-disable max-len */\n fileSize(a, b, c, d, e) {\n return `${(b = Math, c = b.log, d = 1024, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(2)} ${e ? `${'kMGTPEZY'[--e]}B` : 'Bytes'}`;\n }\n /* eslint-enable max-len */\n /* eslint-disable max-depth */\n globStringToRegex(str) {\n str = str.replace(/\\s/g, '');\n let regexp = '', excludes = [];\n if (str.length > 2 && str[0] === '/' && str[str.length - 1] === '/') {\n regexp = str.substring(1, str.length - 1);\n }\n else {\n const split = str.split(',');\n if (split.length > 1) {\n for (let i = 0; i < split.length; i++) {\n const r = this.globStringToRegex(split[i]);\n if (r.regexp) {\n regexp += `(${r.regexp})`;\n if (i < split.length - 1) {\n regexp += '|';\n }\n }\n else {\n excludes = excludes.concat(r.excludes);\n }\n }\n }\n else {\n if (str.startsWith('!')) {\n excludes.push(`^((?!${this.globStringToRegex(str.substring(1)).regexp}).)*$`);\n }\n else {\n if (str.startsWith('.')) {\n str = `*${str}`;\n }\n regexp = `^${str.replace(new RegExp('[.\\\\\\\\+*?\\\\[\\\\^\\\\]$(){}=!<>|:\\\\-]', 'g'), '\\\\$&')}$`;\n regexp = regexp.replace(/\\\\\\*/g, '.*').replace(/\\\\\\?/g, '.');\n }\n }\n }\n return { regexp, excludes };\n }\n /* eslint-enable max-depth */\n translateScalars(str) {\n if (typeof str === 'string') {\n if (str.search(/kb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024);\n }\n if (str.search(/mb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024 * 1024);\n }\n if (str.search(/gb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024 * 1024 * 1024);\n }\n if (str.search(/b/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1));\n }\n if (str.search(/s/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1));\n }\n if (str.search(/m/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1) * 60);\n }\n if (str.search(/h/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1) * 3600);\n }\n }\n return str;\n }\n validatePattern(file, val) {\n if (!val) {\n return true;\n }\n const pattern = this.globStringToRegex(val);\n let valid = true;\n if (pattern.regexp && pattern.regexp.length) {\n const regexp = new RegExp(pattern.regexp, 'i');\n valid = (!lodash_1.default.isNil(file.type) && regexp.test(file.type)) ||\n (!lodash_1.default.isNil(file.name) && regexp.test(file.name));\n }\n valid = pattern.excludes.reduce((result, excludePattern) => {\n const exclude = new RegExp(excludePattern, 'i');\n return result && (lodash_1.default.isNil(file.type) || exclude.test(file.type)) &&\n (lodash_1.default.isNil(file.name) || exclude.test(file.name));\n }, valid);\n return valid;\n }\n validateMinSize(file, val) {\n return file.size + 0.1 >= this.translateScalars(val);\n }\n validateMaxSize(file, val) {\n return file.size - 0.1 <= this.translateScalars(val);\n }\n abortRequest(id) {\n const abortUpload = this.abortUploads.find(abortUpload => abortUpload.id === id);\n if (abortUpload) {\n abortUpload.abort();\n }\n }\n handleAction(event) {\n const target = event.target;\n if (!target.id) {\n return;\n }\n const [action, id] = target.id.split('-');\n if (!action || !id || !this.actions[action]) {\n return;\n }\n this.actions[action](id);\n }\n getFileName(file) {\n return (0, utils_1.uniqueName)(file.name, this.component.fileNameTemplate, this.evalContext());\n }\n getInitFileToSync(file) {\n const escapedFileName = file.name ? file.name.replaceAll('<', '&lt;').replaceAll('>', '&gt;') : file.name;\n return {\n id: createRandomString(),\n // Get a unique name for this file to keep file collisions from occurring.\n dir: this.interpolate(this.component.dir || ''),\n name: this.getFileName(file),\n originalName: escapedFileName,\n fileKey: this.component.fileKey || 'file',\n storage: this.component.storage,\n options: this.component.options,\n file,\n size: file.size,\n status: 'info',\n message: this.t('Processing file. Please wait...'),\n hash: '',\n };\n }\n handleSubmissionRevisions(file) {\n return __awaiter(this, void 0, void 0, function* () {\n if (this.root.form.submissionRevisions !== 'true') {\n return '';\n }\n const bmf = new browser_md5_file_1.default();\n const hash = yield new Promise((resolve, reject) => {\n this.emit('fileUploadingStart');\n bmf.md5(file, (err, md5) => {\n if (err) {\n return reject(err);\n }\n return resolve(md5);\n });\n });\n this.emit('fileUploadingEnd');\n return hash;\n });\n }\n validateFileName(file) {\n // Check if file with the same name is being uploaded\n const fileWithSameNameUploading = this.filesToSync.filesToUpload\n .some(fileToSync => { var _a; return ((_a = fileToSync.file) === null || _a === void 0 ? void 0 : _a.name) === file.name; });\n const fileWithSameNameUploaded = this.dataValue && this.dataValue\n .some(fileStatus => fileStatus.originalName === file.name);\n return fileWithSameNameUploaded || fileWithSameNameUploading\n ? {\n status: 'error',\n message: this.t(`File with the same name is already ${fileWithSameNameUploading ? 'being ' : ''}uploaded`),\n }\n : {};\n }\n validateFileSettings(file) {\n // Check file pattern\n if (this.component.filePattern && !this.validatePattern(file, this.component.filePattern)) {\n return {\n status: 'error',\n message: this.t('File is the wrong type; it must be {{ pattern }}', {\n pattern: this.component.filePattern,\n }),\n };\n }\n // Check file minimum size\n if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) {\n return {\n status: 'error',\n message: this.t('File is too small; it must be at least {{ size }}', {\n size: this.component.fileMinSize,\n }),\n };\n }\n // Check file maximum size\n if (this.component.fileMaxSize && !this.validateMaxSize(file, this.component.fileMaxSize)) {\n return {\n status: 'error',\n message: this.t('File is too big; it must be at most {{ size }}', {\n size: this.component.fileMaxSize,\n }),\n };\n }\n return {};\n }\n validateFileService() {\n const { fileService } = this;\n return !fileService\n ? {\n status: 'error',\n message: this.t('File Service not provided.'),\n }\n : {};\n }\n validateFile(file) {\n const fileServiceValidation = this.validateFileService();\n if (fileServiceValidation.status === 'error') {\n return fileServiceValidation;\n }\n const fileNameValidation = this.validateFileName(file);\n if (fileNameValidation.status === 'error') {\n return fileNameValidation;\n }\n return this.validateFileSettings(file);\n }\n getGroupPermissions() {\n let groupKey = null;\n let groupPermissions = null;\n //Iterate through form components to find group resource if one exists\n this.root.everyComponent((element) => {\n var _a, _b;\n if (((_a = element.component) === null || _a === void 0 ? void 0 : _a.submissionAccess) || ((_b = element.component) === null || _b === void 0 ? void 0 : _b.defaultPermission)) {\n groupPermissions = !element.component.submissionAccess ? [\n {\n type: element.component.defaultPermission,\n roles: [],\n },\n ] : element.component.submissionAccess;\n groupPermissions.forEach((permission) => {\n groupKey = ['admin', 'write', 'create'].includes(permission.type) ? element.component.key : null;\n });\n }\n });\n return { groupKey, groupPermissions };\n }\n triggerFileProcessor(file) {\n return __awaiter(this, void 0, void 0, function* () {\n let processedFile = null;\n if (this.root.options.fileProcessor) {\n try {\n if (this.refs.fileProcessingLoader) {\n this.refs.fileProcessingLoader.style.display = 'block';\n }\n const fileProcessorHandler = (0, fileProcessor_1.default)(this.fileService, this.root.options.fileProcessor);\n processedFile = yield fileProcessorHandler(file, this.component.properties);\n }\n catch (err) {\n this.fileDropHidden = false;\n return {\n status: 'error',\n message: this.t('File processing has been failed.'),\n };\n }\n finally {\n if (this.refs.fileProcessingLoader) {\n this.refs.fileProcessingLoader.style.display = 'none';\n }\n }\n }\n return {\n file: processedFile,\n };\n });\n }\n prepareFileToUpload(file) {\n return __awaiter(this, void 0, void 0, function* () {\n const fileToSync = this.getInitFileToSync(file);\n fileToSync.hash = yield this.handleSubmissionRevisions(file);\n const { status, message } = this.validateFile(file);\n if (status === 'error') {\n fileToSync.isValidationError = true;\n fileToSync.status = status;\n fileToSync.message = message;\n return this.filesToSync.filesToUpload.push(fileToSync);\n }\n if (this.component.privateDownload) {\n file.private = true;\n }\n const { groupKey, groupPermissions } = this.getGroupPermissions();\n const processedFile = yield this.triggerFileProcessor(file);\n if (processedFile.status === 'error') {\n fileToSync.status === 'error';\n fileToSync.message = processedFile.message;\n return this.filesToSync.filesToUpload.push(fileToSync);\n }\n if (this.autoSync) {\n fileToSync.message = this.t('Ready to be uploaded into storage');\n }\n this.filesToSync.filesToUpload.push(Object.assign(Object.assign({}, fileToSync), { message: fileToSync.message, file: processedFile.file || file, url: this.interpolate(this.component.url, { file: fileToSync }), groupPermissions, groupResourceId: groupKey ? this.currentForm.submission.data[groupKey]._id : null }));\n });\n }\n prepareFilesToUpload(files) {\n return __awaiter(this, void 0, void 0, function* () {\n // Only allow one upload if not multiple.\n if (!this.component.multiple) {\n files = Array.prototype.slice.call(files, 0, 1);\n }\n if (this.component.storage && files && files.length) {\n this.fileDropHidden = true;\n return Promise.all([...files].map((file) => __awaiter(this, void 0, void 0, function* () {\n yield this.prepareFileToUpload(file);\n this.redraw();\n })));\n }\n else {\n return Promise.resolve();\n }\n });\n }\n handleFilesToUpload(files) {\n return __awaiter(this, void 0, void 0, function* () {\n yield this.prepareFilesToUpload(files);\n if (!this.autoSync) {\n yield this.syncFiles();\n }\n });\n }\n prepareFileToDelete(fileInfo) {\n this.filesToSync.filesToDelete.push(Object.assign(Object.assign({}, fileInfo), { status: 'info', message: this.autoSync\n ? this.t('Ready to be removed from storage')\n : this.t('Preparing file to remove') }));\n const index = this.dataValue.findIndex(file => file.name === fileInfo.name);\n this.splice(index);\n this.redraw();\n }\n handleFileToRemove(fileInfo) {\n this.prepareFileToDelete(fileInfo);\n if (!this.autoSync) {\n this.syncFiles();\n }\n }\n deleteFile(fileInfo) {\n return __awaiter(this, void 0, void 0, function* () {\n const { options = {} } = this.component;\n if (fileInfo && (['url', 'indexeddb', 's3', 'azure', 'googledrive'].includes(this.component.storage))) {\n const { fileService } = this;\n if (fileService && typeof fileService.deleteFile === 'function') {\n return yield fileService.deleteFile(fileInfo, options);\n }\n else {\n const formio = this.options.formio || (this.root && this.root.formio);\n if (formio) {\n return yield formio.makeRequest('', fileInfo.url, 'delete');\n }\n }\n }\n });\n }\n delete() {\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.filesToSync.filesToDelete.length) {\n return Promise.resolve();\n }\n return yield Promise.all(this.filesToSync.filesToDelete.map((fileToSync) => __awaiter(this, void 0, void 0, function* () {\n try {\n if (fileToSync.isValidationError) {\n return { fileToSync };\n }\n yield this.deleteFile(fileToSync);\n fileToSync.status = 'success';\n fileToSync.message = this.t('Succefully removed');\n }\n catch (response) {\n fileToSync.status = 'error';\n fileToSync.message = typeof response === 'string' ? response : response.toString();\n }\n finally {\n this.redraw();\n }\n return { fileToSync };\n })));\n });\n }\n updateProgress(fileInfo, progressEvent) {\n fileInfo.progress = parseInt(100.0 * progressEvent.loaded / progressEvent.total);\n if (fileInfo.status !== 'progress') {\n fileInfo.status = 'progress';\n delete fileInfo.message;\n this.redraw();\n }\n else {\n const progress = Array.prototype.find.call(this.refs.progress, progressElement => progressElement.id === fileInfo.id);\n progress.innerHTML = `<span class=\"visually-hidden\">${fileInfo.progress}% ${this.t('Complete')}</span>`;\n progress.style.width = `${fileInfo.progress}%`;\n progress.ariaValueNow = fileInfo.progress.toString();\n }\n }\n getMultipartOptions(fileToSync) {\n let count = 0;\n return this.component.useMultipartUpload && this.component.multipart ? Object.assign(Object.assign({}, this.component.multipart), { progressCallback: (total) => {\n count++;\n fileToSync.status = 'progress';\n fileToSync.progress = parseInt(100 * count / total);\n delete fileToSync.message;\n this.redraw();\n }, changeMessage: (message) => {\n fileToSync.message = message;\n this.redraw();\n } }) : false;\n }\n uploadFile(fileToSync) {\n return __awaiter(this, void 0, void 0, function* () {\n return yield this.fileService.uploadFile(fileToSync.storage, fileToSync.file, fileToSync.name, fileToSync.dir, \n // Progress callback\n this.updateProgress.bind(this, fileToSync), fileToSync.url, fileToSync.options, fileToSync.fileKey, fileToSync.groupPermissions, fileToSync.groupResourceId, () => { }, \n // Abort upload callback\n (abort) => this.abortUploads.push({\n id: fileToSync.id,\n abort,\n }), this.getMultipartOptions(fileToSync));\n });\n }\n upload() {\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.filesToSync.filesToUpload.length) {\n return Promise.resolve();\n }\n return yield Promise.all(this.filesToSync.filesToUpload.map((fileToSync) => __awaiter(this, void 0, void 0, function* () {\n let fileInfo = null;\n try {\n if (fileToSync.isValidationError) {\n return {\n fileToSync,\n fileInfo,\n };\n }\n fileInfo = yield this.uploadFile(fileToSync);\n fileToSync.status = 'success';\n fileToSync.message = this.t('Succefully uploaded');\n fileInfo.originalName = fileToSync.originalName;\n fileInfo.hash = fileToSync.hash;\n }\n catch (response) {\n fileToSync.status = 'error';\n delete fileToSync.progress;\n fileToSync.message = typeof response === 'string'\n ? response\n : response.type === 'abort'\n ? this.t('Request was aborted')\n : response.toString();\n }\n finally {\n delete fileToSync.progress;\n this.redraw();\n }\n return {\n fileToSync,\n fileInfo,\n };\n })));\n });\n }\n syncFiles() {\n return __awaiter(this, void 0, void 0, function* () {\n this.isSyncing = true;\n this.fileDropHidden = true;\n this.redraw();\n try {\n const [filesToDelete = [], filesToUpload = []] = yield Promise.all([this.delete(), this.upload()]);\n this.filesToSync.filesToDelete = filesToDelete\n .filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'error'; })\n .map(file => file.fileToSync);\n this.filesToSync.filesToUpload = filesToUpload\n .filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'error'; })\n .map(file => file.fileToSync);\n if (!this.hasValue()) {\n this.dataValue = [];\n }\n const data = filesToUpload\n .filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'success'; })\n .map(file => file.fileInfo);\n this.dataValue.push(...data);\n this.triggerChange();\n return Promise.resolve();\n }\n catch (err) {\n return Promise.reject();\n }\n finally {\n this.isSyncing = false;\n this.fileDropHidden = false;\n this.abortUploads = [];\n this.redraw();\n }\n });\n }\n getFile(fileInfo) {\n const { options = {} } = this.component;\n const { fileService } = this;\n if (!fileService) {\n return alert('File Service not provided');\n }\n if (this.component.privateDownload) {\n fileInfo.private = true;\n }\n fileService.downloadFile(fileInfo, options).then((file) => {\n if (file) {\n if (['base64', 'indexeddb'].includes(file.storage)) {\n (0, downloadjs_1.default)(file.url, file.originalName || file.name, file.type);\n }\n else {\n window.open(file.url, '_blank');\n }\n }\n })\n .catch((response) => {\n // Is alert the best way to do this?\n // User is expecting an immediate notification due to attempting to download a file.\n alert(response);\n });\n }\n focus() {\n if ('beforeFocus' in this.parent) {\n this.parent.beforeFocus(this);\n }\n if (this.refs.fileBrowse) {\n this.refs.fileBrowse.focus();\n }\n }\n beforeSubmit() {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n if (!this.autoSync) {\n return Promise.resolve();\n }\n yield this.syncFiles();\n return this.shouldSyncFiles\n ? Promise.reject('Synchronization is failed')\n : Promise.resolve();\n }\n catch (error) {\n return Promise.reject(error.message);\n }\n });\n }\n destroy(all) {\n this.stopVideo();\n super.destroy(all);\n }\n}\nexports[\"default\"] = FileComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/file/File.js?");
5692
+ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst Field_1 = __importDefault(__webpack_require__(/*! ../_classes/field/Field */ \"./lib/cjs/components/_classes/field/Field.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst downloadjs_1 = __importDefault(__webpack_require__(/*! downloadjs */ \"./node_modules/downloadjs/download.js\"));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst fileProcessor_1 = __importDefault(__webpack_require__(/*! ../../providers/processor/fileProcessor */ \"./lib/cjs/providers/processor/fileProcessor.js\"));\nconst browser_md5_file_1 = __importDefault(__webpack_require__(/*! browser-md5-file */ \"./node_modules/browser-md5-file/dist/index.umd.js\"));\nlet Camera;\nlet webViewCamera = 'undefined' !== typeof window ? navigator.camera : Camera;\n// canvas.toBlob polyfill.\nlet htmlCanvasElement;\nif (typeof window !== 'undefined') {\n htmlCanvasElement = window.HTMLCanvasElement;\n}\nelse if (typeof __webpack_require__.g !== 'undefined') {\n htmlCanvasElement = __webpack_require__.g.HTMLCanvasElement;\n}\nif (htmlCanvasElement && !htmlCanvasElement.prototype.toBlob) {\n Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {\n value: function (callback, type, quality) {\n var canvas = this;\n setTimeout(function () {\n var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]), len = binStr.length, arr = new Uint8Array(len);\n for (var i = 0; i < len; i++) {\n arr[i] = binStr.charCodeAt(i);\n }\n callback(new Blob([arr], { type: type || 'image/png' }));\n });\n }\n });\n}\nconst createRandomString = () => Math.random().toString(36).substring(2, 15);\nclass FileComponent extends Field_1.default {\n static schema(...extend) {\n return Field_1.default.schema({\n type: 'file',\n label: 'Upload',\n key: 'file',\n image: false,\n privateDownload: false,\n imageSize: '200',\n filePattern: '*',\n fileMinSize: '0KB',\n fileMaxSize: '1GB',\n uploadOnly: false,\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'File',\n group: 'premium',\n icon: 'file',\n documentation: '/userguide/form-building/premium-components#file',\n weight: 100,\n schema: FileComponent.schema(),\n };\n }\n static get serverConditionSettings() {\n return FileComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { operators: ['isEmpty', 'isNotEmpty'] });\n }\n static savedValueTypes(schema) {\n schema = schema || {};\n return (0, utils_1.getComponentSavedTypes)(schema) || [utils_1.componentValueTypes.object];\n }\n init() {\n super.init();\n webViewCamera = navigator.camera || Camera;\n const fileReaderSupported = (typeof FileReader !== 'undefined');\n const formDataSupported = typeof window !== 'undefined' ? Boolean(window.FormData) : false;\n const progressSupported = (typeof window !== 'undefined' && window.XMLHttpRequest) ? ('upload' in new XMLHttpRequest) : false;\n this.support = {\n filereader: fileReaderSupported,\n formdata: formDataSupported,\n hasWarning: !fileReaderSupported || !formDataSupported || !progressSupported,\n progress: progressSupported,\n };\n this.cameraMode = false;\n this.fileDropHidden = false;\n this.filesToSync = {\n filesToUpload: [],\n filesToDelete: [],\n };\n this.isSyncing = false;\n this.abortUploads = [];\n }\n get dataReady() {\n return this.filesReady || Promise.resolve();\n }\n get defaultSchema() {\n return FileComponent.schema();\n }\n loadImage(fileInfo) {\n if (this.component.privateDownload) {\n fileInfo.private = true;\n }\n return this.fileService.downloadFile(fileInfo).then((result) => result.url);\n }\n get emptyValue() {\n return [];\n }\n getValueAsString(value) {\n if (lodash_1.default.isArray(value)) {\n return lodash_1.default.map(value, 'originalName').join(', ');\n }\n return lodash_1.default.get(value, 'originalName', '');\n }\n getValue() {\n return this.dataValue;\n }\n get defaultValue() {\n const value = super.defaultValue;\n return Array.isArray(value) ? value : [];\n }\n get hasTypes() {\n return this.component.fileTypes &&\n Array.isArray(this.component.fileTypes) &&\n this.component.fileTypes.length !== 0 &&\n (this.component.fileTypes[0].label !== '' || this.component.fileTypes[0].value !== '');\n }\n get fileDropHidden() {\n return this._fileBrowseHidden;\n }\n set fileDropHidden(value) {\n if (typeof value !== 'boolean' || this.component.multiple) {\n return;\n }\n this._fileBrowseHidden = value;\n }\n get shouldSyncFiles() {\n return Boolean(this.filesToSync.filesToDelete.length || this.filesToSync.filesToUpload.length);\n }\n get autoSync() {\n return lodash_1.default.get(this, 'component.autoSync', false);\n }\n get columnsSize() {\n const actionsColumn = this.disabled ? 0 : this.autoSync ? 2 : 1;\n const typeColumn = this.hasTypes ? 2 : 0;\n const sizeColumn = 2;\n const nameColumn = 12 - actionsColumn - typeColumn - sizeColumn;\n return {\n name: nameColumn,\n size: sizeColumn,\n type: typeColumn,\n actions: actionsColumn,\n };\n }\n render() {\n const { filesToDelete, filesToUpload } = this.filesToSync;\n return super.render(this.renderTemplate('file', {\n fileSize: this.fileSize,\n files: this.dataValue || [],\n filesToDelete,\n filesToUpload,\n disabled: this.disabled,\n support: this.support,\n fileDropHidden: this.fileDropHidden,\n showSyncButton: this.autoSync && (filesToDelete.length || filesToUpload.length),\n isSyncing: this.isSyncing,\n columns: this.columnsSize,\n }));\n }\n getVideoStream(constraints) {\n return navigator.mediaDevices.getUserMedia({\n video: Object.assign({ width: { min: 640, ideal: 1920 }, height: { min: 360, ideal: 1080 }, aspectRatio: { ideal: 16 / 9 } }, constraints),\n audio: false,\n });\n }\n stopVideoStream(videoStream) {\n videoStream.getVideoTracks().forEach((track) => track.stop());\n }\n getFrame(videoPlayer) {\n return new Promise((resolve) => {\n const canvas = document.createElement('canvas');\n canvas.height = videoPlayer.videoHeight;\n canvas.width = videoPlayer.videoWidth;\n const context = canvas.getContext('2d');\n context.drawImage(videoPlayer, 0, 0);\n canvas.toBlob(resolve);\n });\n }\n startVideo() {\n this.getVideoStream()\n .then((stream) => {\n this.videoStream = stream;\n const { videoPlayer } = this.refs;\n if (!videoPlayer) {\n console.warn('Video player not found in template.');\n this.cameraMode = false;\n this.redraw();\n return;\n }\n videoPlayer.srcObject = stream;\n const width = parseInt(this.component.webcamSize) || 320;\n videoPlayer.setAttribute('width', width);\n videoPlayer.play();\n })\n .catch((err) => {\n console.error(err);\n this.cameraMode = false;\n this.redraw();\n });\n }\n stopVideo() {\n if (this.videoStream) {\n this.stopVideoStream(this.videoStream);\n this.videoStream = null;\n }\n }\n takePicture() {\n const { videoPlayer } = this.refs;\n if (!videoPlayer) {\n console.warn('Video player not found in template.');\n this.cameraMode = false;\n this.redraw();\n return;\n }\n this.getFrame(videoPlayer)\n .then((frame) => {\n frame.name = `photo-${Date.now()}.png`;\n this.handleFilesToUpload([frame]);\n this.cameraMode = false;\n this.redraw();\n });\n }\n browseFiles(attrs = {}) {\n return new Promise((resolve) => {\n const fileInput = this.ce('input', Object.assign({ type: 'file', style: 'height: 0; width: 0; visibility: hidden;', tabindex: '-1' }, attrs));\n document.body.appendChild(fileInput);\n fileInput.addEventListener('change', () => {\n resolve(fileInput.files);\n document.body.removeChild(fileInput);\n }, true);\n // There is no direct way to trigger a file dialog. To work around this, create an input of type file and trigger\n // a click event on it.\n if (typeof fileInput.trigger === 'function') {\n fileInput.trigger('click');\n }\n else {\n fileInput.click();\n }\n });\n }\n set cameraMode(value) {\n this._cameraMode = value;\n if (value) {\n this.startVideo();\n }\n else {\n this.stopVideo();\n }\n }\n get cameraMode() {\n return this._cameraMode;\n }\n get useWebViewCamera() {\n return this.imageUpload && webViewCamera;\n }\n get imageUpload() {\n return Boolean(this.component.image);\n }\n get browseOptions() {\n const options = {};\n if (this.component.multiple) {\n options.multiple = true;\n }\n if (this.component.capture) {\n options.capture = this.component.capture;\n }\n //use \"accept\" attribute only for desktop devices because of its limited support by mobile browsers\n const filePattern = this.component.filePattern.trim() || '';\n if (!this.isMobile.any) {\n const imagesPattern = 'image/*';\n if (this.imageUpload && (!filePattern || filePattern === '*')) {\n options.accept = imagesPattern;\n }\n else if (this.imageUpload && !filePattern.includes(imagesPattern)) {\n options.accept = `${imagesPattern},${filePattern}`;\n }\n else {\n options.accept = filePattern;\n }\n }\n // if input capture is set, we need the \"accept\" attribute to determine which device to launch\n else if (this.component.capture) {\n if (filePattern.includes('video')) {\n options.accept = 'video/*';\n }\n else if (filePattern.includes('audio')) {\n options.accept = 'audio/*';\n }\n else {\n options.accept = 'image/*';\n }\n }\n return options;\n }\n get actions() {\n return {\n abort: this.abortRequest.bind(this),\n };\n }\n attach(element) {\n this.loadRefs(element, {\n fileDrop: 'single',\n fileBrowse: 'single',\n galleryButton: 'single',\n cameraButton: 'single',\n takePictureButton: 'single',\n toggleCameraMode: 'single',\n videoPlayer: 'single',\n fileLink: 'multiple',\n removeLink: 'multiple',\n fileToSyncRemove: 'multiple',\n fileImage: 'multiple',\n fileType: 'multiple',\n fileProcessingLoader: 'single',\n syncNow: 'single',\n restoreFile: 'multiple',\n progress: 'multiple',\n });\n // Ensure we have an empty input refs. We need this for the setValue method to redraw the control when it is set.\n this.refs.input = [];\n const superAttach = super.attach(element);\n if (this.refs.fileDrop) {\n // if (!this.statuses.length) {\n // this.refs.fileDrop.removeAttribute('hidden');\n // }\n const _this = this;\n this.addEventListener(this.refs.fileDrop, 'dragover', function (event) {\n this.className = 'fileSelector fileDragOver';\n event.preventDefault();\n });\n this.addEventListener(this.refs.fileDrop, 'dragleave', function (event) {\n this.className = 'fileSelector';\n event.preventDefault();\n });\n this.addEventListener(this.refs.fileDrop, 'drop', function (event) {\n this.className = 'fileSelector';\n event.preventDefault();\n _this.handleFilesToUpload(event.dataTransfer.files);\n });\n }\n this.addEventListener(element, 'click', (event) => {\n this.handleAction(event);\n });\n if (this.refs.fileBrowse) {\n this.addEventListener(this.refs.fileBrowse, 'click', (event) => {\n event.preventDefault();\n this.browseFiles(this.browseOptions)\n .then((files) => {\n this.handleFilesToUpload(files);\n });\n });\n }\n this.refs.fileLink.forEach((fileLink, index) => {\n this.addEventListener(fileLink, 'click', (event) => {\n event.preventDefault();\n this.getFile(this.dataValue[index]);\n });\n });\n this.refs.removeLink.forEach((removeLink, index) => {\n this.addEventListener(removeLink, 'click', (event) => {\n event.preventDefault();\n const fileInfo = this.dataValue[index];\n this.handleFileToRemove(fileInfo);\n });\n });\n this.refs.fileToSyncRemove.forEach((fileToSyncRemove, index) => {\n this.addEventListener(fileToSyncRemove, 'click', (event) => {\n event.preventDefault();\n this.filesToSync.filesToUpload.splice(index, 1);\n this.redraw();\n });\n });\n this.refs.restoreFile.forEach((fileToRestore, index) => {\n this.addEventListener(fileToRestore, 'click', (event) => {\n event.preventDefault();\n const fileInfo = this.filesToSync.filesToDelete[index];\n delete fileInfo.status;\n delete fileInfo.message;\n this.filesToSync.filesToDelete.splice(index, 1);\n this.dataValue.push(fileInfo);\n this.triggerChange();\n this.redraw();\n });\n });\n if (this.refs.galleryButton && webViewCamera) {\n this.addEventListener(this.refs.galleryButton, 'click', (event) => {\n event.preventDefault();\n webViewCamera.getPicture((success) => {\n window.resolveLocalFileSystemURL(success, (fileEntry) => {\n fileEntry.file((file) => {\n const reader = new FileReader();\n reader.onloadend = (evt) => {\n const blob = new Blob([new Uint8Array(evt.target.result)], { type: file.type });\n blob.name = file.name;\n this.handleFilesToUpload([blob]);\n };\n reader.readAsArrayBuffer(file);\n });\n });\n }, (err) => {\n console.error(err);\n }, {\n sourceType: webViewCamera.PictureSourceType.PHOTOLIBRARY,\n });\n });\n }\n if (this.refs.cameraButton && webViewCamera) {\n this.addEventListener(this.refs.cameraButton, 'click', (event) => {\n event.preventDefault();\n webViewCamera.getPicture((success) => {\n window.resolveLocalFileSystemURL(success, (fileEntry) => {\n fileEntry.file((file) => {\n const reader = new FileReader();\n reader.onloadend = (evt) => {\n const blob = new Blob([new Uint8Array(evt.target.result)], { type: file.type });\n blob.name = file.name;\n this.handleFilesToUpload([blob]);\n };\n reader.readAsArrayBuffer(file);\n });\n });\n }, (err) => {\n console.error(err);\n }, {\n sourceType: webViewCamera.PictureSourceType.CAMERA,\n encodingType: webViewCamera.EncodingType.PNG,\n mediaType: webViewCamera.MediaType.PICTURE,\n saveToPhotoAlbum: true,\n correctOrientation: false,\n });\n });\n }\n if (this.refs.takePictureButton) {\n this.addEventListener(this.refs.takePictureButton, 'click', (event) => {\n event.preventDefault();\n this.takePicture();\n });\n }\n if (this.refs.toggleCameraMode) {\n this.addEventListener(this.refs.toggleCameraMode, 'click', (event) => {\n event.preventDefault();\n this.cameraMode = !this.cameraMode;\n this.redraw();\n });\n }\n this.refs.fileType.forEach((fileType, index) => {\n if (!this.dataValue[index]) {\n return;\n }\n this.dataValue[index].fileType = this.dataValue[index].fileType || this.component.fileTypes[0].label;\n this.addEventListener(fileType, 'change', (event) => {\n event.preventDefault();\n const fileType = this.component.fileTypes.find((typeObj) => typeObj.value === event.target.value);\n this.dataValue[index].fileType = fileType.label;\n });\n });\n this.addEventListener(this.refs.syncNow, 'click', (event) => {\n event.preventDefault();\n this.syncFiles();\n });\n const fileService = this.fileService;\n if (fileService) {\n const loadingImages = [];\n this.filesReady = new Promise((resolve, reject) => {\n this.filesReadyResolve = resolve;\n this.filesReadyReject = reject;\n });\n this.refs.fileImage.forEach((image, index) => {\n loadingImages.push(this.loadImage(this.dataValue[index]).then((url) => (image.src = url)));\n });\n if (loadingImages.length) {\n Promise.all(loadingImages).then(() => {\n this.filesReadyResolve();\n }).catch(() => this.filesReadyReject());\n }\n else {\n this.filesReadyResolve();\n }\n }\n return superAttach;\n }\n /* eslint-disable max-len */\n fileSize(a, b, c, d, e) {\n return `${(b = Math, c = b.log, d = 1024, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(2)} ${e ? `${'kMGTPEZY'[--e]}B` : 'Bytes'}`;\n }\n /* eslint-enable max-len */\n /* eslint-disable max-depth */\n globStringToRegex(str) {\n str = str.replace(/\\s/g, '');\n let regexp = '', excludes = [];\n if (str.length > 2 && str[0] === '/' && str[str.length - 1] === '/') {\n regexp = str.substring(1, str.length - 1);\n }\n else {\n const split = str.split(',');\n if (split.length > 1) {\n for (let i = 0; i < split.length; i++) {\n const r = this.globStringToRegex(split[i]);\n if (r.regexp) {\n regexp += `(${r.regexp})`;\n if (i < split.length - 1) {\n regexp += '|';\n }\n }\n else {\n excludes = excludes.concat(r.excludes);\n }\n }\n }\n else {\n if (str.startsWith('!')) {\n excludes.push(`^((?!${this.globStringToRegex(str.substring(1)).regexp}).)*$`);\n }\n else {\n if (str.startsWith('.')) {\n str = `*${str}`;\n }\n regexp = `^${str.replace(new RegExp('[.\\\\\\\\+*?\\\\[\\\\^\\\\]$(){}=!<>|:\\\\-]', 'g'), '\\\\$&')}$`;\n regexp = regexp.replace(/\\\\\\*/g, '.*').replace(/\\\\\\?/g, '.');\n }\n }\n }\n return { regexp, excludes };\n }\n /* eslint-enable max-depth */\n translateScalars(str) {\n if (typeof str === 'string') {\n if (str.search(/kb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024);\n }\n if (str.search(/mb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024 * 1024);\n }\n if (str.search(/gb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024 * 1024 * 1024);\n }\n if (str.search(/b/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1));\n }\n if (str.search(/s/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1));\n }\n if (str.search(/m/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1) * 60);\n }\n if (str.search(/h/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1) * 3600);\n }\n }\n return str;\n }\n validatePattern(file, val) {\n if (!val) {\n return true;\n }\n const pattern = this.globStringToRegex(val);\n let valid = true;\n if (pattern.regexp && pattern.regexp.length) {\n const regexp = new RegExp(pattern.regexp, 'i');\n valid = (!lodash_1.default.isNil(file.type) && regexp.test(file.type)) ||\n (!lodash_1.default.isNil(file.name) && regexp.test(file.name));\n }\n valid = pattern.excludes.reduce((result, excludePattern) => {\n const exclude = new RegExp(excludePattern, 'i');\n return result && (lodash_1.default.isNil(file.type) || exclude.test(file.type)) &&\n (lodash_1.default.isNil(file.name) || exclude.test(file.name));\n }, valid);\n return valid;\n }\n validateMinSize(file, val) {\n return file.size + 0.1 >= this.translateScalars(val);\n }\n validateMaxSize(file, val) {\n return file.size - 0.1 <= this.translateScalars(val);\n }\n abortRequest(id) {\n const abortUpload = this.abortUploads.find(abortUpload => abortUpload.id === id);\n if (abortUpload) {\n abortUpload.abort();\n }\n }\n handleAction(event) {\n const target = event.target;\n if (!target.id) {\n return;\n }\n const [action, id] = target.id.split('-');\n if (!action || !id || !this.actions[action]) {\n return;\n }\n this.actions[action](id);\n }\n getFileName(file) {\n return (0, utils_1.uniqueName)(file.name, this.component.fileNameTemplate, this.evalContext());\n }\n getInitFileToSync(file) {\n const escapedFileName = file.name ? file.name.replaceAll('<', '&lt;').replaceAll('>', '&gt;') : file.name;\n return {\n id: createRandomString(),\n // Get a unique name for this file to keep file collisions from occurring.\n dir: this.interpolate(this.component.dir || ''),\n name: this.getFileName(file),\n originalName: escapedFileName,\n fileKey: this.component.fileKey || 'file',\n storage: this.component.storage,\n options: this.component.options,\n file,\n size: file.size,\n status: 'info',\n message: this.t('Processing file. Please wait...'),\n hash: '',\n };\n }\n handleSubmissionRevisions(file) {\n return __awaiter(this, void 0, void 0, function* () {\n if (this.root.form.submissionRevisions !== 'true') {\n return '';\n }\n const bmf = new browser_md5_file_1.default();\n const hash = yield new Promise((resolve, reject) => {\n this.emit('fileUploadingStart');\n bmf.md5(file, (err, md5) => {\n if (err) {\n return reject(err);\n }\n return resolve(md5);\n });\n });\n this.emit('fileUploadingEnd');\n return hash;\n });\n }\n validateFileName(file) {\n // Check if file with the same name is being uploaded\n const fileWithSameNameUploading = this.filesToSync.filesToUpload\n .some(fileToSync => { var _a; return ((_a = fileToSync.file) === null || _a === void 0 ? void 0 : _a.name) === file.name; });\n const fileWithSameNameUploaded = this.dataValue\n .some(fileStatus => fileStatus.originalName === file.name);\n return fileWithSameNameUploaded || fileWithSameNameUploading\n ? {\n status: 'error',\n message: this.t(`File with the same name is already ${fileWithSameNameUploading ? 'being ' : ''}uploaded`),\n }\n : {};\n }\n validateFileSettings(file) {\n // Check file pattern\n if (this.component.filePattern && !this.validatePattern(file, this.component.filePattern)) {\n return {\n status: 'error',\n message: this.t('File is the wrong type; it must be {{ pattern }}', {\n pattern: this.component.filePattern,\n }),\n };\n }\n // Check file minimum size\n if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) {\n return {\n status: 'error',\n message: this.t('File is too small; it must be at least {{ size }}', {\n size: this.component.fileMinSize,\n }),\n };\n }\n // Check file maximum size\n if (this.component.fileMaxSize && !this.validateMaxSize(file, this.component.fileMaxSize)) {\n return {\n status: 'error',\n message: this.t('File is too big; it must be at most {{ size }}', {\n size: this.component.fileMaxSize,\n }),\n };\n }\n return {};\n }\n validateFileService() {\n const { fileService } = this;\n return !fileService\n ? {\n status: 'error',\n message: this.t('File Service not provided.'),\n }\n : {};\n }\n validateFile(file) {\n const fileServiceValidation = this.validateFileService();\n if (fileServiceValidation.status === 'error') {\n return fileServiceValidation;\n }\n const fileNameValidation = this.validateFileName(file);\n if (fileNameValidation.status === 'error') {\n return fileNameValidation;\n }\n return this.validateFileSettings(file);\n }\n getGroupPermissions() {\n let groupKey = null;\n let groupPermissions = null;\n //Iterate through form components to find group resource if one exists\n this.root.everyComponent((element) => {\n var _a, _b;\n if (((_a = element.component) === null || _a === void 0 ? void 0 : _a.submissionAccess) || ((_b = element.component) === null || _b === void 0 ? void 0 : _b.defaultPermission)) {\n groupPermissions = !element.component.submissionAccess ? [\n {\n type: element.component.defaultPermission,\n roles: [],\n },\n ] : element.component.submissionAccess;\n groupPermissions.forEach((permission) => {\n groupKey = ['admin', 'write', 'create'].includes(permission.type) ? element.component.key : null;\n });\n }\n });\n return { groupKey, groupPermissions };\n }\n triggerFileProcessor(file) {\n return __awaiter(this, void 0, void 0, function* () {\n let processedFile = null;\n if (this.root.options.fileProcessor) {\n try {\n if (this.refs.fileProcessingLoader) {\n this.refs.fileProcessingLoader.style.display = 'block';\n }\n const fileProcessorHandler = (0, fileProcessor_1.default)(this.fileService, this.root.options.fileProcessor);\n processedFile = yield fileProcessorHandler(file, this.component.properties);\n }\n catch (err) {\n this.fileDropHidden = false;\n return {\n status: 'error',\n message: this.t('File processing has been failed.'),\n };\n }\n finally {\n if (this.refs.fileProcessingLoader) {\n this.refs.fileProcessingLoader.style.display = 'none';\n }\n }\n }\n return {\n file: processedFile,\n };\n });\n }\n prepareFileToUpload(file) {\n return __awaiter(this, void 0, void 0, function* () {\n const fileToSync = this.getInitFileToSync(file);\n fileToSync.hash = yield this.handleSubmissionRevisions(file);\n const { status, message } = this.validateFile(file);\n if (status === 'error') {\n fileToSync.isValidationError = true;\n fileToSync.status = status;\n fileToSync.message = message;\n return this.filesToSync.filesToUpload.push(fileToSync);\n }\n if (this.component.privateDownload) {\n file.private = true;\n }\n const { groupKey, groupPermissions } = this.getGroupPermissions();\n const processedFile = yield this.triggerFileProcessor(file);\n if (processedFile.status === 'error') {\n fileToSync.status === 'error';\n fileToSync.message = processedFile.message;\n return this.filesToSync.filesToUpload.push(fileToSync);\n }\n if (this.autoSync) {\n fileToSync.message = this.t('Ready to be uploaded into storage');\n }\n this.filesToSync.filesToUpload.push(Object.assign(Object.assign({}, fileToSync), { message: fileToSync.message, file: processedFile.file || file, url: this.interpolate(this.component.url, { file: fileToSync }), groupPermissions, groupResourceId: groupKey ? this.currentForm.submission.data[groupKey]._id : null }));\n });\n }\n prepareFilesToUpload(files) {\n return __awaiter(this, void 0, void 0, function* () {\n // Only allow one upload if not multiple.\n if (!this.component.multiple) {\n files = Array.prototype.slice.call(files, 0, 1);\n }\n if (this.component.storage && files && files.length) {\n this.fileDropHidden = true;\n return Promise.all([...files].map((file) => __awaiter(this, void 0, void 0, function* () {\n yield this.prepareFileToUpload(file);\n this.redraw();\n })));\n }\n else {\n return Promise.resolve();\n }\n });\n }\n handleFilesToUpload(files) {\n return __awaiter(this, void 0, void 0, function* () {\n yield this.prepareFilesToUpload(files);\n if (!this.autoSync) {\n yield this.syncFiles();\n }\n });\n }\n prepareFileToDelete(fileInfo) {\n this.filesToSync.filesToDelete.push(Object.assign(Object.assign({}, fileInfo), { status: 'info', message: this.autoSync\n ? this.t('Ready to be removed from storage')\n : this.t('Preparing file to remove') }));\n const index = this.dataValue.findIndex(file => file.name === fileInfo.name);\n this.splice(index);\n this.redraw();\n }\n handleFileToRemove(fileInfo) {\n this.prepareFileToDelete(fileInfo);\n if (!this.autoSync) {\n this.syncFiles();\n }\n }\n deleteFile(fileInfo) {\n return __awaiter(this, void 0, void 0, function* () {\n const { options = {} } = this.component;\n if (fileInfo && (['url', 'indexeddb', 's3', 'azure', 'googledrive'].includes(this.component.storage))) {\n const { fileService } = this;\n if (fileService && typeof fileService.deleteFile === 'function') {\n return yield fileService.deleteFile(fileInfo, options);\n }\n else {\n const formio = this.options.formio || (this.root && this.root.formio);\n if (formio) {\n return yield formio.makeRequest('', fileInfo.url, 'delete');\n }\n }\n }\n });\n }\n delete() {\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.filesToSync.filesToDelete.length) {\n return Promise.resolve();\n }\n return yield Promise.all(this.filesToSync.filesToDelete.map((fileToSync) => __awaiter(this, void 0, void 0, function* () {\n try {\n if (fileToSync.isValidationError) {\n return { fileToSync };\n }\n yield this.deleteFile(fileToSync);\n fileToSync.status = 'success';\n fileToSync.message = this.t('Succefully removed');\n }\n catch (response) {\n fileToSync.status = 'error';\n fileToSync.message = typeof response === 'string' ? response : response.toString();\n }\n finally {\n this.redraw();\n }\n return { fileToSync };\n })));\n });\n }\n updateProgress(fileInfo, progressEvent) {\n fileInfo.progress = parseInt(100.0 * progressEvent.loaded / progressEvent.total);\n if (fileInfo.status !== 'progress') {\n fileInfo.status = 'progress';\n delete fileInfo.message;\n this.redraw();\n }\n else {\n const progress = Array.prototype.find.call(this.refs.progress, progressElement => progressElement.id === fileInfo.id);\n progress.innerHTML = `<span class=\"visually-hidden\">${fileInfo.progress}% ${this.t('Complete')}</span>`;\n progress.style.width = `${fileInfo.progress}%`;\n progress.ariaValueNow = fileInfo.progress.toString();\n }\n }\n getMultipartOptions(fileToSync) {\n let count = 0;\n return this.component.useMultipartUpload && this.component.multipart ? Object.assign(Object.assign({}, this.component.multipart), { progressCallback: (total) => {\n count++;\n fileToSync.status = 'progress';\n fileToSync.progress = parseInt(100 * count / total);\n delete fileToSync.message;\n this.redraw();\n }, changeMessage: (message) => {\n fileToSync.message = message;\n this.redraw();\n } }) : false;\n }\n uploadFile(fileToSync) {\n return __awaiter(this, void 0, void 0, function* () {\n return yield this.fileService.uploadFile(fileToSync.storage, fileToSync.file, fileToSync.name, fileToSync.dir, \n // Progress callback\n this.updateProgress.bind(this, fileToSync), fileToSync.url, fileToSync.options, fileToSync.fileKey, fileToSync.groupPermissions, fileToSync.groupResourceId, () => { }, \n // Abort upload callback\n (abort) => this.abortUploads.push({\n id: fileToSync.id,\n abort,\n }), this.getMultipartOptions(fileToSync));\n });\n }\n upload() {\n return __awaiter(this, void 0, void 0, function* () {\n if (!this.filesToSync.filesToUpload.length) {\n return Promise.resolve();\n }\n return yield Promise.all(this.filesToSync.filesToUpload.map((fileToSync) => __awaiter(this, void 0, void 0, function* () {\n let fileInfo = null;\n try {\n if (fileToSync.isValidationError) {\n return {\n fileToSync,\n fileInfo,\n };\n }\n fileInfo = yield this.uploadFile(fileToSync);\n fileToSync.status = 'success';\n fileToSync.message = this.t('Succefully uploaded');\n fileInfo.originalName = fileToSync.originalName;\n fileInfo.hash = fileToSync.hash;\n }\n catch (response) {\n fileToSync.status = 'error';\n delete fileToSync.progress;\n fileToSync.message = typeof response === 'string'\n ? response\n : response.type === 'abort'\n ? this.t('Request was aborted')\n : response.toString();\n }\n finally {\n delete fileToSync.progress;\n this.redraw();\n }\n return {\n fileToSync,\n fileInfo,\n };\n })));\n });\n }\n syncFiles() {\n return __awaiter(this, void 0, void 0, function* () {\n this.isSyncing = true;\n this.fileDropHidden = true;\n this.redraw();\n try {\n const [filesToDelete = [], filesToUpload = []] = yield Promise.all([this.delete(), this.upload()]);\n this.filesToSync.filesToDelete = filesToDelete\n .filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'error'; })\n .map(file => file.fileToSync);\n this.filesToSync.filesToUpload = filesToUpload\n .filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'error'; })\n .map(file => file.fileToSync);\n if (!this.hasValue()) {\n this.dataValue = [];\n }\n const data = filesToUpload\n .filter(file => { var _a; return ((_a = file.fileToSync) === null || _a === void 0 ? void 0 : _a.status) === 'success'; })\n .map(file => file.fileInfo);\n this.dataValue.push(...data);\n this.triggerChange();\n return Promise.resolve();\n }\n catch (err) {\n return Promise.reject();\n }\n finally {\n this.isSyncing = false;\n this.fileDropHidden = false;\n this.abortUploads = [];\n this.redraw();\n }\n });\n }\n getFile(fileInfo) {\n const { options = {} } = this.component;\n const { fileService } = this;\n if (!fileService) {\n return alert('File Service not provided');\n }\n if (this.component.privateDownload) {\n fileInfo.private = true;\n }\n fileService.downloadFile(fileInfo, options).then((file) => {\n if (file) {\n if (['base64', 'indexeddb'].includes(file.storage)) {\n (0, downloadjs_1.default)(file.url, file.originalName || file.name, file.type);\n }\n else {\n window.open(file.url, '_blank');\n }\n }\n })\n .catch((response) => {\n // Is alert the best way to do this?\n // User is expecting an immediate notification due to attempting to download a file.\n alert(response);\n });\n }\n focus() {\n if ('beforeFocus' in this.parent) {\n this.parent.beforeFocus(this);\n }\n if (this.refs.fileBrowse) {\n this.refs.fileBrowse.focus();\n }\n }\n beforeSubmit() {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n if (!this.autoSync) {\n return Promise.resolve();\n }\n yield this.syncFiles();\n return this.shouldSyncFiles\n ? Promise.reject('Synchronization is failed')\n : Promise.resolve();\n }\n catch (error) {\n return Promise.reject(error.message);\n }\n });\n }\n destroy(all) {\n this.stopVideo();\n super.destroy(all);\n }\n}\nexports[\"default\"] = FileComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/file/File.js?");
5693
5693
 
5694
5694
  /***/ }),
5695
5695
 
@@ -5788,7 +5788,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
5788
5788
  /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
5789
5789
 
5790
5790
  "use strict";
5791
- eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst ListComponent_1 = __importDefault(__webpack_require__(/*! ../_classes/list/ListComponent */ \"./lib/cjs/components/_classes/list/ListComponent.js\"));\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nclass RadioComponent extends ListComponent_1.default {\n static schema(...extend) {\n return ListComponent_1.default.schema({\n type: 'radio',\n inputType: 'radio',\n label: 'Radio',\n key: 'radio',\n values: [{ label: '', value: '' }],\n data: {\n url: '',\n },\n fieldSet: false\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Radio',\n group: 'basic',\n icon: 'dot-circle-o',\n weight: 80,\n documentation: '/userguide/form-building/form-components#radio',\n schema: RadioComponent.schema()\n };\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom() {\n return classComp.values;\n }\n },\n };\n } });\n }\n static get serverConditionSettings() {\n return Object.assign(Object.assign({}, super.serverConditionSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom: `values = ${classComp && classComp.values ? JSON.stringify(classComp.values) : []}`,\n },\n };\n } });\n }\n static savedValueTypes(schema) {\n const { boolean, string, number, object, array } = utils_1.componentValueTypes;\n const { dataType } = schema;\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (types) {\n return types;\n }\n if (dataType === 'object') {\n return [object, array];\n }\n if (utils_1.componentValueTypes[dataType]) {\n return [utils_1.componentValueTypes[dataType]];\n }\n return [boolean, string, number, object, array];\n }\n constructor(component, options, data) {\n super(component, options, data);\n this.previousValue = this.dataValue || null;\n }\n get defaultSchema() {\n return RadioComponent.schema();\n }\n get defaultValue() {\n let defaultValue = super.defaultValue;\n if (!defaultValue && this.component.defaultValue === false) {\n defaultValue = this.component.defaultValue;\n }\n return defaultValue;\n }\n get inputInfo() {\n var _a;\n const info = super.elementInfo();\n info.type = 'input';\n info.changeEvent = 'click';\n info.attr.class = 'form-check-input';\n info.attr.name = info.attr.name += `[${(_a = this.root) === null || _a === void 0 ? void 0 : _a.id}-${this.id}]`;\n return info;\n }\n get emptyValue() {\n return '';\n }\n get isRadio() {\n return this.component.inputType === 'radio';\n }\n get optionSelectedClass() {\n return 'radio-selected';\n }\n get listData() {\n const listData = lodash_1.default.get(this.root, 'submission.metadata.listData', {});\n return lodash_1.default.get(listData, this.path);\n }\n init() {\n super.init();\n this.templateData = {};\n // Trigger an update.//\n let updateArgs = [];\n const triggerUpdate = lodash_1.default.debounce((...args) => {\n updateArgs = [];\n return this.updateItems.apply(this, args);\n }, 100);\n this.triggerUpdate = (...args) => {\n // Make sure we always resolve the previous promise before reassign it\n if (typeof this.itemsLoadedResolve === 'function') {\n this.itemsLoadedResolve();\n }\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n if (args.length) {\n updateArgs = args;\n }\n return triggerUpdate(...updateArgs);\n };\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n this.optionsLoaded = false;\n this.loadedOptions = [];\n // Get the template keys for this radio component.\n this.getTemplateKeys();\n }\n render() {\n return super.render(this.renderTemplate('radio', {\n input: this.inputInfo,\n inline: this.component.inline,\n values: this.component.dataSrc === 'values' ? this.component.values : this.loadedOptions,\n value: this.dataValue,\n row: this.row,\n }));\n }\n attach(element) {\n this.loadRefs(element, { input: 'multiple', wrapper: 'multiple' });\n this.refs.input.forEach((input, index) => {\n this.addEventListener(input, this.inputInfo.changeEvent, () => {\n this.updateValue(null, {\n modified: true,\n });\n });\n if (this.component.values[index]) {\n this.addShortcut(input, this.component.values[index].shortcut);\n }\n if (this.isRadio) {\n let dataValue = this.dataValue;\n if (!lodash_1.default.isString(this.dataValue)) {\n dataValue = lodash_1.default.toString(this.dataValue);\n }\n if (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) {\n const optionValue = this.component.dataType === 'string' ? JSON.stringify(this.loadedOptions[index].value) : this.loadedOptions[index].value;\n input.checked = lodash_1.default.isEqual(optionValue, this.dataValue);\n }\n else {\n input.checked = (dataValue === input.value && (input.value || this.component.dataSrc !== 'url'));\n }\n this.addEventListener(input, 'keyup', (event) => {\n if (event.key === ' ' && dataValue === input.value) {\n event.preventDefault();\n this.updateValue(null, {\n modified: true,\n });\n }\n });\n }\n });\n this.triggerUpdate();\n this.setSelectedClasses();\n return super.attach(element);\n }\n detach(element) {\n if (element && this.refs.input) {\n this.refs.input.forEach((input, index) => {\n if (this.component.values[index]) {\n this.removeShortcut(input, this.component.values[index].shortcut);\n }\n });\n }\n super.detach();\n }\n getValue() {\n if (this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n let value = this.dataValue;\n this.refs.input.forEach((input, index) => {\n if (input.checked) {\n value = (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) ?\n this.loadedOptions[index].value :\n input.value;\n }\n });\n return value;\n }\n validateValueProperty() {\n if (this.component.dataSrc === 'values') {\n return true;\n }\n return !lodash_1.default.some(this.refs.wrapper, (wrapper, index) => this.refs.input[index].checked && this.loadedOptions[index].invalid);\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.component.values;\n if (values) {\n return values.findIndex(({ value: optionValue }) => this.normalizeValue(optionValue) === value) !== -1;\n }\n return false;\n }\n getValueAsString(value, options = {}) {\n if (lodash_1.default.isObject(value)) {\n value = JSON.stringify(value);\n }\n else if (!lodash_1.default.isString(value)) {\n value = lodash_1.default.toString(value);\n }\n const isModalPreviewWithUrlDataSource = options.modalPreview && this.component.dataSrc === 'url';\n if (this.component.dataSrc !== 'values' && !isModalPreviewWithUrlDataSource) {\n return value;\n }\n const values = isModalPreviewWithUrlDataSource ? this.loadedOptions : this.component.values;\n const option = lodash_1.default.find(values, (v) => v.value === value);\n if (!value) {\n return lodash_1.default.get(option, 'label', '');\n }\n return lodash_1.default.get(option, 'label', '');\n }\n setValueAt(index, value) {\n if (this.refs.input && this.refs.input[index] && value !== null && value !== undefined) {\n const inputValue = this.refs.input[index].value;\n this.refs.input[index].checked = (inputValue === value.toString());\n }\n }\n loadItems(url, search, headers, options, method, body) {\n if (this.optionsLoaded) {\n return;\n }\n if (!this.shouldLoad && this.listData) {\n this.loadItemsFromMetadata();\n return;\n }\n // Ensure we have a method and remove any body if method is get\n method = method || 'GET';\n if (method.toUpperCase() === 'GET') {\n body = null;\n }\n // Set ignoreCache if it is\n options.ignoreCache = this.component.ignoreCache;\n // Make the request.\n options.header = headers;\n this.loading = true;\n Formio_1.Formio.makeRequest(this.options.formio, 'select', url, method, body, options)\n .then((response) => {\n this.loading = false;\n this.setItems(response);\n this.optionsLoaded = true;\n this.redraw();\n })\n .catch((err) => {\n this.handleLoadingError(err);\n });\n }\n loadItemsFromMetadata() {\n this.listData.forEach((item, i) => {\n this.loadedOptions[i] = {\n label: this.itemTemplate(item)\n };\n if (lodash_1.default.isEqual(item, this.selectData || lodash_1.default.pick(this.dataValue, lodash_1.default.keys(item)))) {\n this.loadedOptions[i].value = this.dataValue;\n }\n });\n this.optionsLoaded = true;\n this.redraw();\n }\n setItems(items) {\n const listData = [];\n items === null || items === void 0 ? void 0 : items.forEach((item, i) => {\n this.loadedOptions[i] = {\n value: this.component.valueProperty ? item[this.component.valueProperty] : item,\n label: this.component.valueProperty ? this.itemTemplate(item, item[this.component.valueProperty]) : this.itemTemplate(item, item, i)\n };\n listData.push(this.templateData[this.component.valueProperty ? item[this.component.valueProperty] : i]);\n if ((this.component.valueProperty || !this.isRadio) && (lodash_1.default.isUndefined(item[this.component.valueProperty]) ||\n (!this.isRadio && lodash_1.default.isObject(item[this.component.valueProperty])) ||\n (!this.isRadio && lodash_1.default.isBoolean(item[this.component.valueProperty])))) {\n this.loadedOptions[i].invalid = true;\n }\n });\n if (this.isSelectURL) {\n const submission = this.root.submission;\n if (!submission.metadata) {\n submission.metadata = {};\n }\n if (!submission.metadata.listData) {\n submission.metadata.listData = {};\n }\n lodash_1.default.set(submission.metadata.listData, this.path, listData);\n }\n }\n setSelectedClasses() {\n if (this.refs.wrapper) {\n //add/remove selected option class\n const value = this.dataValue;\n this.refs.wrapper.forEach((wrapper, index) => {\n const input = this.refs.input[index];\n const checked = (input.type === 'checkbox') ? value[input.value] : (input.value.toString() === value.toString());\n if (checked) {\n //add class to container when selected\n this.addClass(wrapper, this.optionSelectedClass);\n //change \"checked\" attribute\n input.setAttribute('checked', 'true');\n }\n else {\n this.removeClass(wrapper, this.optionSelectedClass);\n input.removeAttribute('checked');\n }\n });\n }\n }\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n if (changed) {\n this.setSelectedClasses();\n }\n if (!flags || !flags.modified || !this.isRadio) {\n if (changed) {\n this.previousValue = this.dataValue;\n }\n return changed;\n }\n // If they clicked on the radio that is currently selected, it needs to reset the value.\n this.currentValue = this.dataValue;\n const shouldResetValue = flags && flags.modified && !flags.noUpdateEvent && this.previousValue === this.currentValue;\n if (shouldResetValue) {\n this.resetValue();\n this.triggerChange(flags);\n this.setSelectedClasses();\n }\n this.previousValue = this.dataValue;\n return changed;\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n const dataType = this.component.dataType || 'auto';\n if (value === this.emptyValue) {\n return value;\n }\n switch (dataType) {\n case 'auto':\n if (!isNaN(parseFloat(value)) && isFinite(value) && lodash_1.default.toString(value) === Number(value).toString()) {\n value = +value;\n }\n if (value === 'true') {\n value = true;\n }\n if (value === 'false') {\n value = false;\n }\n break;\n case 'number':\n value = +value;\n break;\n case 'string':\n if (typeof value === 'object') {\n value = JSON.stringify(value);\n }\n else {\n value = String(value);\n }\n break;\n case 'boolean':\n value = !(!value || value.toString() === 'false');\n break;\n }\n if (this.isSelectURL && this.templateData && this.templateData[value]) {\n const submission = this.root.submission;\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n lodash_1.default.set(submission.metadata.selectData, this.path, this.templateData[value]);\n }\n return super.normalizeValue(value);\n }\n}\nexports[\"default\"] = RadioComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/radio/Radio.js?");
5791
+ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst ListComponent_1 = __importDefault(__webpack_require__(/*! ../_classes/list/ListComponent */ \"./lib/cjs/components/_classes/list/ListComponent.js\"));\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nclass RadioComponent extends ListComponent_1.default {\n static schema(...extend) {\n return ListComponent_1.default.schema({\n type: 'radio',\n inputType: 'radio',\n label: 'Radio',\n key: 'radio',\n values: [{ label: '', value: '' }],\n data: {\n url: '',\n },\n fieldSet: false\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Radio',\n group: 'basic',\n icon: 'dot-circle-o',\n weight: 80,\n documentation: '/userguide/form-building/form-components#radio',\n schema: RadioComponent.schema()\n };\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom() {\n return classComp.values;\n }\n },\n };\n } });\n }\n static get serverConditionSettings() {\n return Object.assign(Object.assign({}, super.serverConditionSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom: `values = ${classComp && classComp.values ? JSON.stringify(classComp.values) : []}`,\n },\n };\n } });\n }\n static savedValueTypes(schema) {\n const { boolean, string, number, object, array } = utils_1.componentValueTypes;\n const { dataType } = schema;\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (types) {\n return types;\n }\n if (dataType === 'object') {\n return [object, array];\n }\n if (utils_1.componentValueTypes[dataType]) {\n return [utils_1.componentValueTypes[dataType]];\n }\n return [boolean, string, number, object, array];\n }\n constructor(component, options, data) {\n super(component, options, data);\n this.previousValue = this.dataValue || null;\n }\n get defaultSchema() {\n return RadioComponent.schema();\n }\n get defaultValue() {\n let defaultValue = super.defaultValue;\n if (!defaultValue && this.component.defaultValue === false) {\n defaultValue = this.component.defaultValue;\n }\n return defaultValue;\n }\n get inputInfo() {\n var _a;\n const info = super.elementInfo();\n info.type = 'input';\n info.changeEvent = 'click';\n info.attr.class = 'form-check-input';\n info.attr.name = info.attr.name += `[${(_a = this.root) === null || _a === void 0 ? void 0 : _a.id}-${this.id}]`;\n return info;\n }\n get emptyValue() {\n return '';\n }\n get isRadio() {\n return this.component.inputType === 'radio';\n }\n get optionSelectedClass() {\n return 'radio-selected';\n }\n get listData() {\n const listData = lodash_1.default.get(this.root, 'submission.metadata.listData', {});\n return lodash_1.default.get(listData, this.path);\n }\n init() {\n super.init();\n this.templateData = {};\n // Trigger an update.//\n let updateArgs = [];\n const triggerUpdate = lodash_1.default.debounce((...args) => {\n updateArgs = [];\n return this.updateItems.apply(this, args);\n }, 100);\n this.triggerUpdate = (...args) => {\n // Make sure we always resolve the previous promise before reassign it\n if (typeof this.itemsLoadedResolve === 'function') {\n this.itemsLoadedResolve();\n }\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n if (args.length) {\n updateArgs = args;\n }\n return triggerUpdate(...updateArgs);\n };\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n this.optionsLoaded = false;\n this.loadedOptions = [];\n // Get the template keys for this radio component.\n this.getTemplateKeys();\n }\n render() {\n return super.render(this.renderTemplate('radio', {\n input: this.inputInfo,\n inline: this.component.inline,\n values: this.component.dataSrc === 'values' ? this.component.values : this.loadedOptions,\n value: this.dataValue,\n row: this.row,\n }));\n }\n attach(element) {\n this.loadRefs(element, { input: 'multiple', wrapper: 'multiple' });\n this.refs.input.forEach((input, index) => {\n this.addEventListener(input, this.inputInfo.changeEvent, () => {\n this.updateValue(null, {\n modified: true,\n });\n });\n if (this.component.values[index]) {\n this.addShortcut(input, this.component.values[index].shortcut);\n }\n if (this.isRadio) {\n let dataValue = this.dataValue;\n if (!lodash_1.default.isString(this.dataValue)) {\n dataValue = lodash_1.default.toString(this.dataValue);\n }\n if (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) {\n const optionValue = this.component.dataType === 'string' ? JSON.stringify(this.loadedOptions[index].value) : this.loadedOptions[index].value;\n input.checked = lodash_1.default.isEqual(optionValue, this.dataValue);\n }\n else {\n input.checked = (dataValue === input.value && (input.value || this.component.dataSrc !== 'url'));\n }\n this.addEventListener(input, 'keyup', (event) => {\n if (event.key === ' ' && dataValue === input.value) {\n event.preventDefault();\n this.updateValue(null, {\n modified: true,\n });\n }\n });\n }\n });\n this.triggerUpdate();\n this.setSelectedClasses();\n return super.attach(element);\n }\n detach(element) {\n if (element && this.refs.input) {\n this.refs.input.forEach((input, index) => {\n if (this.component.values[index]) {\n this.removeShortcut(input, this.component.values[index].shortcut);\n }\n });\n }\n super.detach();\n }\n getValue() {\n if (this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n let value = this.dataValue;\n this.refs.input.forEach((input, index) => {\n if (input.checked) {\n value = (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) ?\n this.loadedOptions[index].value :\n input.value;\n }\n });\n return value;\n }\n validateValueProperty() {\n if (this.component.dataSrc === 'values') {\n return true;\n }\n return !lodash_1.default.some(this.refs.wrapper, (wrapper, index) => this.refs.input[index].checked && this.loadedOptions[index].invalid);\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.component.values;\n if (values) {\n return values.findIndex(({ value: optionValue }) => this.normalizeValue(optionValue) === value) !== -1;\n }\n return false;\n }\n getValueAsString(value, options = {}) {\n if (lodash_1.default.isObject(value)) {\n value = JSON.stringify(value);\n }\n else if (!lodash_1.default.isString(value)) {\n value = lodash_1.default.toString(value);\n }\n const isModalPreviewWithUrlDataSource = options.modalPreview && this.component.dataSrc === 'url';\n if (this.component.dataSrc !== 'values' && !isModalPreviewWithUrlDataSource) {\n return value;\n }\n const values = isModalPreviewWithUrlDataSource ? this.loadedOptions : this.component.values;\n const option = lodash_1.default.find(values, (v) => v.value === value);\n if (!value) {\n return lodash_1.default.get(option, 'label', '');\n }\n return lodash_1.default.get(option, 'label', '');\n }\n setValueAt(index, value) {\n if (this.refs.input && this.refs.input[index] && value !== null && value !== undefined) {\n const inputValue = this.refs.input[index].value;\n this.refs.input[index].checked = (inputValue === value.toString());\n }\n }\n loadItems(url, search, headers, options, method, body) {\n if (this.optionsLoaded) {\n return;\n }\n if (!this.shouldLoad && this.listData) {\n this.loadItemsFromMetadata();\n return;\n }\n // Ensure we have a method and remove any body if method is get\n method = method || 'GET';\n if (method.toUpperCase() === 'GET') {\n body = null;\n }\n // Set ignoreCache if it is\n options.ignoreCache = this.component.ignoreCache;\n // Make the request.\n options.header = headers;\n this.loading = true;\n Formio_1.Formio.makeRequest(this.options.formio, 'select', url, method, body, options)\n .then((response) => {\n this.loading = false;\n this.setItems(response);\n this.optionsLoaded = true;\n this.redraw();\n })\n .catch((err) => {\n this.handleLoadingError(err);\n });\n }\n loadItemsFromMetadata() {\n this.listData.forEach((item, i) => {\n this.loadedOptions[i] = {\n label: this.itemTemplate(item)\n };\n if (lodash_1.default.isEqual(item, this.selectData || lodash_1.default.pick(this.dataValue, lodash_1.default.keys(item)))) {\n this.loadedOptions[i].value = this.dataValue;\n }\n });\n this.optionsLoaded = true;\n this.redraw();\n }\n setItems(items) {\n const listData = [];\n items === null || items === void 0 ? void 0 : items.forEach((item, i) => {\n this.loadedOptions[i] = {\n value: this.component.valueProperty ? item[this.component.valueProperty] : item,\n label: this.component.valueProperty ? this.itemTemplate(item, item[this.component.valueProperty]) : this.itemTemplate(item, item, i)\n };\n listData.push(this.templateData[this.component.valueProperty ? item[this.component.valueProperty] : i]);\n if ((this.component.valueProperty || !this.isRadio) && (lodash_1.default.isUndefined(item[this.component.valueProperty]) ||\n (!this.isRadio && lodash_1.default.isObject(item[this.component.valueProperty])) ||\n (!this.isRadio && lodash_1.default.isBoolean(item[this.component.valueProperty])))) {\n this.loadedOptions[i].invalid = true;\n }\n });\n if (this.isSelectURL) {\n const submission = this.root.submission;\n if (!submission.metadata) {\n submission.metadata = {};\n }\n if (!submission.metadata.listData) {\n submission.metadata.listData = {};\n }\n lodash_1.default.set(submission.metadata.listData, this.path, listData);\n }\n }\n setSelectedClasses() {\n if (this.refs.wrapper) {\n //add/remove selected option class\n const value = this.dataValue;\n this.refs.wrapper.forEach((wrapper, index) => {\n var _a;\n const input = this.refs.input[index];\n const checked = (input.type === 'checkbox') ? value[input.value] || ((_a = this.element) === null || _a === void 0 ? void 0 : _a.querySelector('input').checked) : (input.value.toString() === value.toString());\n if (checked) {\n //add class to container when selected\n this.addClass(wrapper, this.optionSelectedClass);\n //change \"checked\" attribute\n input.setAttribute('checked', 'true');\n }\n else {\n this.removeClass(wrapper, this.optionSelectedClass);\n input.removeAttribute('checked');\n }\n });\n }\n }\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n if (changed) {\n this.setSelectedClasses();\n }\n if (!flags || !flags.modified || !this.isRadio) {\n if (changed) {\n this.previousValue = this.dataValue;\n }\n return changed;\n }\n // If they clicked on the radio that is currently selected, it needs to reset the value.\n this.currentValue = this.dataValue;\n const shouldResetValue = flags && flags.modified && !flags.noUpdateEvent && this.previousValue === this.currentValue;\n if (shouldResetValue) {\n this.resetValue();\n this.triggerChange(flags);\n this.setSelectedClasses();\n }\n this.previousValue = this.dataValue;\n return changed;\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n const dataType = this.component.dataType || 'auto';\n if (value === this.emptyValue) {\n return value;\n }\n switch (dataType) {\n case 'auto':\n if (!isNaN(parseFloat(value)) && isFinite(value) && lodash_1.default.toString(value) === Number(value).toString()) {\n value = +value;\n }\n if (value === 'true') {\n value = true;\n }\n if (value === 'false') {\n value = false;\n }\n break;\n case 'number':\n value = +value;\n break;\n case 'string':\n if (typeof value === 'object') {\n value = JSON.stringify(value);\n }\n else {\n value = String(value);\n }\n break;\n case 'boolean':\n value = !(!value || value.toString() === 'false');\n break;\n }\n if (this.isSelectURL && this.templateData && this.templateData[value]) {\n const submission = this.root.submission;\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n lodash_1.default.set(submission.metadata.selectData, this.path, this.templateData[value]);\n }\n return super.normalizeValue(value);\n }\n}\nexports[\"default\"] = RadioComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/radio/Radio.js?");
5792
5792
 
5793
5793
  /***/ }),
5794
5794