diff --git a/js/DropZone/DropZoneComponent.js b/js/DropZone/DropZoneComponent.js index faf19ab36f..7ffa915eb1 100644 --- a/js/DropZone/DropZoneComponent.js +++ b/js/DropZone/DropZoneComponent.js @@ -138,6 +138,20 @@ class DropZoneComponent { input.value = ''; input.type = ''; input.type = 'file'; + + let rawFiles = this.instanceManager.getFiles(id); + const dataTransfer = new DataTransfer(); + let wasFile = false; + for (let i = 0; i < rawFiles.length; i++) { + if (rawFiles[i].raw instanceof File){ + dataTransfer.items.add(rawFiles[i].raw); + wasFile = true; + } + } + if (wasFile){ + // this guard exists as some js tests do not provide a file type as the input value. + input.files = dataTransfer.files; + } }); // visually hide input - this should ideally be done in the CSS also to prevent a diff --git a/package.json b/package.json index 7cb89767e0..2452f57a3c 100644 --- a/package.json +++ b/package.json @@ -8,18 +8,12 @@ "publishConfig": { "registry": "https://npm.pkg.github.com/" }, - "workspaces": [ - "docs" - ], "scripts": { + "start": "docker compose up -d && grunt", "coverage": "mochify --transform [ babelify ] --plugin [ mochify-istanbul --exclude '**/+(tests|node_modules|libs)/**/*' --report lcov --dir ./coverage --instrumenter babel-istanbul] --reporter spec ./tests/harness/common './tests/js/web/**/*Test.js'", - "start": "docker-compose up -d && grunt", - "start:docs": "yarn workspace docs docusaurus start", - "build:docs": "yarn workspace docs docusaurus build", + "test": "npm run test:headless", "build:tests": "grunt javascript:tests", "build:tests:watch": "grunt javascript:tests:watch", - "deploy:docs": "yarn workspace docs docusaurus deploy", - "test": "npm run test:headless", "test:headless": "mochify --reporter spec --transform [ babelify ] ./tests/harness/common './tests/js/web/**/*Test.js'", "test:browser": "npm run build:tests && open ./tests/js/web/index.html", "test:browser:watch": "npm run build:tests:watch" @@ -37,11 +31,10 @@ "browser-sync": "^2.27.11", "browserify": "17.0.0", "browserify-istanbul": "^2.0.0", - "browserify-shim": "^3.8.9", + "browserify-shim": "^3.8.16", "chai": "^4.3.6", "chai-dom": "^1.11.0", "chai-hiff": "^1.0.0", - "dart-sass": "^1.25.0", "grunt": "^1.5.2", "grunt-asciify": "^0.2.2", "grunt-autoprefixer": "^3.0.4", @@ -73,6 +66,7 @@ "mochify": "^9.2.0", "mochify-istanbul": "^2.4.2", "require-globify": "^1.4.1", + "sass": "^1.75.0", "sinon": "^2.4.1", "sinon-chai": "^2.8.8", "sinon-jquery": "^1.0.3", @@ -84,26 +78,26 @@ "datatables.net": "^1.13.4", "datatables.net-buttons": "^1.7.1", "datatables.net-buttons-dt": "^1.7.1", - "datatables.net-dt": "^1.13.4", - "datatables.net-responsive": "^2.4.1", - "datatables.net-responsive-dt": "^2.4.1", - "datatables.net-select": "^1.6.2", - "datatables.net-select-dt": "^1.6.2", + "datatables.net-dt": "^1.13.6", + "datatables.net-responsive": "^2.5.0", + "datatables.net-responsive-dt": "^2.5.0", + "datatables.net-select-dt": "^1.7.1", + "datatables.net-select": "^1.7.1", "input-length": "^1.0.1", - "jquery": "^3.6.4", + "jquery": "^3.7.1", "jquery-countdown": "^2.2.0", "jquery-placeholder": "^2.3.1", "jquery-sticky": "^1.0.4", - "jquery-ui": "^1.13.1", - "jstree": "^3.3.15", + "jquery-ui": "^1.13.3", + "jstree": "^3.3.16", "lodash": "^4.17.21", - "moment": "^2.29.2", + "moment": "^2.30.1", "normalize.css": "^8.0.1", "pikaday": "^1.8.2", "pulsar-date-picker": "^1.0.0", "select2": "github:jadu/selectWoo#jadu-1.1.5", "spectrum-colorpicker": "^1.8.1", - "timepicker": "^1.13.18", + "timepicker": "^1.14.1", "tippy.js": "^5.2.1" } } diff --git a/tests/js/web/DropZone/DropZoneComponentTest.js b/tests/js/web/DropZone/DropZoneComponentTest.js index 790f127520..779799c0f9 100644 --- a/tests/js/web/DropZone/DropZoneComponentTest.js +++ b/tests/js/web/DropZone/DropZoneComponentTest.js @@ -148,6 +148,49 @@ describe('DropZoneComponent', () => { expect($fileInput.val()).to.equal(''); }); + it('should retain the input node files on change', () => { + // we need to explicitly set type="file" here. Originally it is configured as type="text" presumably to avoid the same security issue explained below + $fileInput = $(''); + const change = new Event('change'); + const getDTFileList = (fileInput, ...appendFiles) => { + const dataTransfer = new DataTransfer(); + if (fileInput.files && fileInput.files.length > 0) { + // add all our File objects to prepopulate the DataTransfer + for (let i = 0; i < fileInput.files.length; i++) { + dataTransfer.items.add(fileInput.files[i]); + } + } + appendFiles.forEach((appendFile)=>{ + dataTransfer.items.add(appendFile); + }); + return dataTransfer.files; + } + /** + * There is actually no way to programatically add a File object to Input.files other than to duplicate the DataTransfer process... + * This is due to strict browser security measures. Yes it is a bit of a hack, but there are simply no other options for initalising our input. + * Feel free to refactor this should a future version of ES add this functionality in some way. + */ + const file = new File(['Lorem ipsum dolor'], 'example.txt', { type: 'text/plain' }); + $fileInput[0].files = getDTFileList($fileInput[0], file); + + let rawFiles = []; + for (let i = 0; i < $fileInput[0].files.length; i++) { + $fileInput[0].files[i] + rawFiles.push({'raw': $fileInput[0].files[i]}) + } + + instanceManager.getFiles.returns(rawFiles); + dropZoneComponent.processInputNode($fileInput[0], 0, options.showInputNode); + $fileInput[0].dispatchEvent(change); + //debugger; + const dataTransferFile = getDTFileList($fileInput[0])[0]; + const inputFile = $fileInput[0].files[0]; + expect(inputFile.name).to.equal(dataTransferFile.name); + expect(inputFile.lastModified).to.equal(dataTransferFile.lastModified); + expect(inputFile.size).to.equal(dataTransferFile.size); + expect(inputFile.type).to.equal(dataTransferFile.type); + }); + it('should not hide the input if specified in options', () => { const options = { showInputNode: true, inputNodeId: 'fileInput' }; const display = $fileInput.css('display');