Skip to content
Snippets Groups Projects
Unverified Commit da65b413 authored by Paul Kaplan's avatar Paul Kaplan Committed by GitHub
Browse files

Merge pull request #4499 from LLK/multi-upload

Multiple file upload for costumes, sounds, backdrops and sprites
parents 65f9f7f1 65756fcc
No related branches found
No related tags found
No related merge requests found
......@@ -142,7 +142,7 @@ class ActionMenu extends React.Component {
<div className={styles.moreButtonsOuter}>
<div className={styles.moreButtons}>
{(moreButtons || []).map(({img, title, onClick: handleClick,
fileAccept, fileChange, fileInput}, keyId) => {
fileAccept, fileChange, fileInput, fileMultiple}, keyId) => {
const isComingSoon = !handleClick;
const hasFileInput = fileInput;
const tooltipId = `${this.mainTooltipId}-${title}`;
......@@ -166,6 +166,7 @@ class ActionMenu extends React.Component {
<input
accept={fileAccept}
className={styles.fileInput}
multiple={fileMultiple}
ref={fileInput}
type="file"
onChange={fileChange}
......@@ -198,7 +199,8 @@ ActionMenu.propTypes = {
onClick: PropTypes.func, // Optional, "coming soon" if no callback provided
fileAccept: PropTypes.string, // Optional, only for file upload
fileChange: PropTypes.func, // Optional, only for file upload
fileInput: PropTypes.func // Optional, only for file upload
fileInput: PropTypes.func, // Optional, only for file upload
fileMultiple: PropTypes.bool // Optional, only for file upload
})),
onClick: PropTypes.func.isRequired,
title: PropTypes.node.isRequired,
......
......@@ -122,7 +122,8 @@ const SpriteSelectorComponent = function (props) {
onClick: onFileUploadClick,
fileAccept: '.svg, .png, .jpg, .jpeg, .sprite2, .sprite3',
fileChange: onSpriteUpload,
fileInput: spriteFileInput
fileInput: spriteFileInput,
fileMultiple: true
}, {
title: intl.formatMessage(messages.addSpriteFromSurprise),
img: surpriseIcon,
......
......@@ -104,7 +104,8 @@ const StageSelector = props => {
onClick: onBackdropFileUploadClick,
fileAccept: '.svg, .png, .jpg, .jpeg', // Bitmap coming soon
fileChange: onBackdropFileUpload,
fileInput: fileInputRef
fileInput: fileInputRef,
fileMultiple: true
}, {
title: intl.formatMessage(messages.addBackdropFromSurprise),
img: surpriseIcon,
......
......@@ -293,7 +293,8 @@ class CostumeTab extends React.Component {
onClick: this.handleFileUploadClick,
fileAccept: '.svg, .png, .jpg, .jpeg',
fileChange: this.handleCostumeUpload,
fileInput: this.setFileInput
fileInput: this.setFileInput,
fileMultiple: true
},
{
title: intl.formatMessage(messages.addSurpriseCostumeMsg),
......
......@@ -223,7 +223,8 @@ class SoundTab extends React.Component {
onClick: this.handleFileUploadClick,
fileAccept: '.wav, .mp3',
fileChange: this.handleSoundUpload,
fileInput: this.setFileInput
fileInput: this.setFileInput,
fileMultiple: true
}, {
title: intl.formatMessage(messages.surpriseSound),
img: surpriseIcon,
......
......@@ -21,22 +21,25 @@ const extractFileName = function (nameExt) {
* @param {Function} onload The function that handles loading the file
*/
const handleFileUpload = function (fileInput, onload) {
let thisFile = null;
const reader = new FileReader();
reader.onload = () => {
// Reset the file input value now that we have everything we need
// so that the user can upload the same sound multiple times if
// they choose
fileInput.value = null;
const fileType = thisFile.type;
const fileName = extractFileName(thisFile.name);
onload(reader.result, fileType, fileName);
const readFile = (i, files) => {
if (i === files.length) {
// Reset the file input value now that we have everything we need
// so that the user can upload the same sound multiple times if
// they choose
fileInput.value = null;
return;
}
const file = files[i];
const reader = new FileReader();
reader.onload = () => {
const fileType = file.type;
const fileName = extractFileName(file.name);
onload(reader.result, fileType, fileName);
readFile(i + 1, files);
};
reader.readAsArrayBuffer(file);
};
if (fileInput.files) {
thisFile = fileInput.files[0];
reader.readAsArrayBuffer(thisFile);
}
readFile(0, fileInput.files);
};
/**
......
File added
File added
......@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
const {
clickText,
clickXpath,
findByText,
findByXpath,
getDriver,
getLogs,
......@@ -49,4 +50,30 @@ describe('Working with backdrops', () => {
const logs = await getLogs();
await expect(logs).toEqual([]);
});
test.only('Adding multiple backdrops at the same time', async () => {
const files = [
path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
path.resolve(__dirname, '../fixtures/100-100.svg')
];
await loadUri(uri);
await clickXpath('//button[@title="Try It"]');
const buttonXpath = '//button[@aria-label="Choose a Backdrop"]';
const fileXpath = `${buttonXpath}/following-sibling::div//input[@type="file"]`;
const el = await findByXpath(buttonXpath);
await driver.actions().mouseMove(el)
.perform();
await driver.sleep(500); // Wait for thermometer menu to come up
const input = await findByXpath(fileXpath);
await input.sendKeys(files.join('\n'));
await clickXpath('//span[text()="Stage"]');
await findByText('gh-3582-png', scope.costumesTab);
await findByText('100-100', scope.costumesTab);
const logs = await getLogs();
await expect(logs).toEqual([]);
});
});
......@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
const {
clickText,
clickXpath,
findByText,
findByXpath,
getDriver,
getLogs,
......@@ -181,4 +182,25 @@ describe('Working with costumes', () => {
await expect(logs).toEqual([]);
});
test.only('Adding multiple costumes at the same time', async () => {
const files = [
path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
path.resolve(__dirname, '../fixtures/100-100.svg')
];
await loadUri(uri);
await clickXpath('//button[@title="Try It"]');
await clickText('Costumes');
const el = await findByXpath('//button[@aria-label="Choose a Costume"]');
await driver.actions().mouseMove(el)
.perform();
await driver.sleep(500); // Wait for thermometer menu to come up
const input = await findByXpath('//input[@type="file"]');
await input.sendKeys(files.join('\n'));
await findByText('gh-3582-png', scope.costumesTab);
await findByText('100-100', scope.costumesTab);
const logs = await getLogs();
await expect(logs).toEqual([]);
});
});
......@@ -4,6 +4,7 @@ import SeleniumHelper from '../helpers/selenium-helper';
const {
clickText,
clickXpath,
findByText,
findByXpath,
getDriver,
getLogs,
......@@ -114,4 +115,26 @@ describe('Working with sounds', () => {
const logs = await getLogs();
await expect(logs).toEqual([]);
});
test.only('Adding multiple sounds at the same time', async () => {
const files = [
path.resolve(__dirname, '../fixtures/movie.wav'),
path.resolve(__dirname, '../fixtures/sneaker.wav')
];
await loadUri(uri);
await clickXpath('//button[@title="Try It"]');
await clickText('Sounds');
const el = await findByXpath('//button[@aria-label="Choose a Sound"]');
await driver.actions().mouseMove(el)
.perform();
await driver.sleep(500); // Wait for thermometer menu to come up
const input = await findByXpath('//input[@type="file"]');
await input.sendKeys(files.join('\n'));
await findByText('movie', scope.soundsTab);
await findByText('sneaker', scope.soundsTab);
const logs = await getLogs();
await expect(logs).toEqual([]);
});
});
......@@ -159,4 +159,25 @@ describe('Working with sprites', () => {
await expect(logs).toEqual([]);
});
test.only('Adding multiple sprites at the same time', async () => {
const files = [
path.resolve(__dirname, '../fixtures/gh-3582-png.png'),
path.resolve(__dirname, '../fixtures/100-100.svg')
];
await loadUri(uri);
await clickXpath('//button[@title="Try It"]');
const el = await findByXpath('//button[@aria-label="Choose a Sprite"]');
await driver.actions().mouseMove(el)
.perform();
await driver.sleep(500); // Wait for thermometer menu to come up
const input = await findByXpath('//input[@type="file"]');
await input.sendKeys(files.join('\n'));
await findByText('gh-3582-png', scope.spriteTile);
await findByText('100-100', scope.spriteTile);
const logs = await getLogs();
await expect(logs).toEqual([]);
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment