diff --git a/test/core/workflow/workflow-upload/action-binder.test.js b/test/core/workflow/workflow-upload/action-binder.test.js index 28b5b6c18..ecf27b0e8 100644 --- a/test/core/workflow/workflow-upload/action-binder.test.js +++ b/test/core/workflow/workflow-upload/action-binder.test.js @@ -1920,5 +1920,28 @@ describe('Unity Upload Block', () => { testDiv.dispatchEvent(clickEvent); expect(testDiv).to.not.be.null; }); + + it('should prevent double file picker while lock is active', async () => { + const actionBinder = new ActionBinder(unityEl, workflowCfg, unityEl, [unityEl]); + const container = document.createElement('div'); + const fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.id = 'file-upload'; + fileInput.className = 'file-upload'; + container.appendChild(fileInput); + + await actionBinder.initActionListeners(container, { '#file-upload': 'upload' }); + + let openCount = 0; + fileInput.addEventListener('click', (e) => { + if (e.defaultPrevented) return; + openCount += 1; + }); + + fileInput.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); + fileInput.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); + + expect(openCount).to.equal(1); + }); }); }); diff --git a/unitylibs/core/workflow/workflow-upload/action-binder.js b/unitylibs/core/workflow/workflow-upload/action-binder.js index 641fc8b8e..7c1693c2e 100644 --- a/unitylibs/core/workflow/workflow-upload/action-binder.js +++ b/unitylibs/core/workflow/workflow-upload/action-binder.js @@ -548,7 +548,18 @@ export default class ActionBinder { if (this.limits.allowedFileTypes?.length) { el.setAttribute('accept', this.limits.allowedFileTypes.join(',')); } - el.addEventListener('click', () => { + let isFilePickerOpen = false; + el.addEventListener('click', (e) => { + if (isFilePickerOpen) { + e.preventDefault(); + return; + } + isFilePickerOpen = true; + const releaseFilePickerLock = () => { isFilePickerOpen = false; }; + window.addEventListener('focus', releaseFilePickerLock, { once: true }); + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') releaseFilePickerLock(); + }, { once: true }); this.canvasArea.forEach((element) => { const errHolder = element.querySelector('.alert-holder'); if (errHolder?.classList.contains('show')) { @@ -558,6 +569,7 @@ export default class ActionBinder { }); }); el.addEventListener('change', async (e) => { + isFilePickerOpen = false; const files = this.extractFiles(e); this.filesData = { count: files.length, size: files[0].size, type: files[0].type }; this.logAnalyticsinSplunk('Click Drag and drop|UnityWidget', { assetId: this.assetId, fileMetaData: this.filesData });