2018-03-26 23:32:43 +02:00
|
|
|
// @flow
|
2019-02-22 06:01:59 +01:00
|
|
|
import * as React from 'react';
|
2022-01-02 21:33:11 +01:00
|
|
|
import * as remote from '@electron/remote';
|
2022-09-02 18:43:35 +02:00
|
|
|
import { ipcRenderer } from 'electron';
|
2018-03-26 23:32:43 +02:00
|
|
|
import Button from 'component/button';
|
2019-02-13 17:27:20 +01:00
|
|
|
import { FormField } from 'component/common/form';
|
2018-10-13 17:49:47 +02:00
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
type Props = {
|
|
|
|
type: string,
|
2019-06-28 19:00:29 +02:00
|
|
|
currentPath?: ?string,
|
2022-09-02 18:43:35 +02:00
|
|
|
onFileChosen: (FileWithPath) => void,
|
2019-06-28 09:27:55 +02:00
|
|
|
label?: string,
|
|
|
|
placeholder?: string,
|
2019-10-07 22:02:32 +02:00
|
|
|
accept?: string,
|
2019-10-11 02:37:18 +02:00
|
|
|
error?: string,
|
|
|
|
disabled?: boolean,
|
2020-06-30 07:51:15 +02:00
|
|
|
autoFocus?: boolean,
|
2022-09-02 18:43:35 +02:00
|
|
|
filters?: Array<{ name: string, extension: string[] }>,
|
2022-09-19 22:42:16 +02:00
|
|
|
readFile?: boolean,
|
2018-03-26 23:32:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class FileSelector extends React.PureComponent<Props> {
|
2020-06-30 07:51:15 +02:00
|
|
|
static defaultProps = {
|
|
|
|
autoFocus: false,
|
2018-03-26 23:32:43 +02:00
|
|
|
type: 'file',
|
2022-09-19 22:42:16 +02:00
|
|
|
readFile: true,
|
2018-03-26 23:32:43 +02:00
|
|
|
};
|
|
|
|
|
2019-09-27 18:22:15 +02:00
|
|
|
fileInput: React.ElementRef<any>;
|
2019-02-22 06:01:59 +01:00
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
constructor() {
|
|
|
|
super();
|
2019-02-22 06:01:59 +01:00
|
|
|
this.fileInput = React.createRef();
|
2019-10-07 22:02:32 +02:00
|
|
|
this.handleFileInputSelection = this.handleFileInputSelection.bind(this);
|
2021-08-25 02:28:23 +02:00
|
|
|
this.handleDirectoryInputSelection = this.handleDirectoryInputSelection.bind(this);
|
2019-10-07 22:02:32 +02:00
|
|
|
this.fileInputButton = this.fileInputButton.bind(this);
|
2018-03-26 23:32:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-07 22:02:32 +02:00
|
|
|
handleFileInputSelection = () => {
|
2019-09-27 18:22:15 +02:00
|
|
|
const { files } = this.fileInput.current;
|
|
|
|
if (!files) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-07 22:02:32 +02:00
|
|
|
const file = files[0];
|
2020-10-16 01:06:05 +02:00
|
|
|
|
2019-09-27 18:22:15 +02:00
|
|
|
if (this.props.onFileChosen) {
|
2022-09-02 18:43:35 +02:00
|
|
|
this.props.onFileChosen({ file, path: file.path || file.name });
|
2019-09-27 18:22:15 +02:00
|
|
|
}
|
2021-08-25 02:28:23 +02:00
|
|
|
this.fileInput.current.value = null; // clear the file input
|
2019-10-07 22:02:32 +02:00
|
|
|
};
|
|
|
|
|
2020-10-16 01:06:05 +02:00
|
|
|
handleDirectoryInputSelection = () => {
|
2022-06-28 21:49:41 +02:00
|
|
|
let defaultPath;
|
|
|
|
let properties;
|
|
|
|
let isWin = process.platform === 'win32';
|
|
|
|
let type = this.props.type;
|
|
|
|
|
|
|
|
if (isWin === true) {
|
|
|
|
defaultPath = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'openFile') {
|
|
|
|
properties = ['openFile'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'openDirectory') {
|
|
|
|
properties = ['openDirectory'];
|
|
|
|
}
|
|
|
|
|
2022-09-02 18:43:35 +02:00
|
|
|
remote.dialog
|
|
|
|
.showOpenDialog({
|
|
|
|
properties,
|
|
|
|
defaultPath,
|
|
|
|
filters: this.props.filters,
|
|
|
|
})
|
|
|
|
.then((result) => {
|
|
|
|
const path = result && result.filePaths[0];
|
|
|
|
if (path) {
|
2022-09-19 22:42:16 +02:00
|
|
|
return ipcRenderer.invoke('get-file-from-path', path, this.props.readFile);
|
2022-09-02 18:43:35 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.then((result) => {
|
|
|
|
if (!result) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const file = new File([result.buffer], result.name, {
|
|
|
|
type: result.mime,
|
|
|
|
});
|
|
|
|
this.props.onFileChosen({ file, path: result.path });
|
|
|
|
});
|
2020-10-16 01:06:05 +02:00
|
|
|
};
|
|
|
|
|
2019-10-07 22:02:32 +02:00
|
|
|
fileInputButton = () => {
|
|
|
|
this.fileInput.current.click();
|
|
|
|
};
|
2019-02-22 06:01:59 +01:00
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
input: ?HTMLInputElement;
|
|
|
|
|
|
|
|
render() {
|
2020-07-23 19:02:07 +02:00
|
|
|
const { type, currentPath, label, placeholder, accept, error, disabled, autoFocus = false } = this.props;
|
2019-10-07 22:02:32 +02:00
|
|
|
const placeHolder = currentPath || placeholder;
|
2019-12-09 19:51:00 +01:00
|
|
|
|
2018-03-26 23:32:43 +02:00
|
|
|
return (
|
2019-02-22 06:01:59 +01:00
|
|
|
<React.Fragment>
|
|
|
|
<FormField
|
2019-06-28 09:27:55 +02:00
|
|
|
label={label}
|
2019-03-18 06:06:41 +01:00
|
|
|
webkitdirectory="true"
|
2022-04-17 19:04:56 +02:00
|
|
|
className="form-field--with-button"
|
2019-10-11 02:37:18 +02:00
|
|
|
error={error}
|
|
|
|
disabled={disabled}
|
2019-03-18 06:06:41 +01:00
|
|
|
type="text"
|
|
|
|
readOnly="readonly"
|
2019-10-07 22:02:32 +02:00
|
|
|
value={placeHolder || __('Choose a file')}
|
2019-10-11 02:37:18 +02:00
|
|
|
inputButton={
|
2020-06-30 07:51:15 +02:00
|
|
|
<Button
|
|
|
|
autoFocus={autoFocus}
|
2022-04-17 19:04:56 +02:00
|
|
|
button="primary"
|
2020-06-30 07:51:15 +02:00
|
|
|
disabled={disabled}
|
2022-06-28 21:49:41 +02:00
|
|
|
onClick={
|
|
|
|
type === 'openDirectory' || type === 'openFile'
|
|
|
|
? this.handleDirectoryInputSelection
|
|
|
|
: this.fileInputButton
|
|
|
|
}
|
2020-07-23 19:02:07 +02:00
|
|
|
label={__('Browse')}
|
2020-06-30 07:51:15 +02:00
|
|
|
/>
|
2019-10-11 02:37:18 +02:00
|
|
|
}
|
2019-10-07 22:02:32 +02:00
|
|
|
/>
|
|
|
|
<input
|
|
|
|
type={'file'}
|
|
|
|
style={{ display: 'none' }}
|
|
|
|
accept={accept}
|
|
|
|
ref={this.fileInput}
|
2020-10-16 01:06:05 +02:00
|
|
|
onChange={() => (type === 'openDirectory' ? () => {} : this.handleFileInputSelection())}
|
2019-10-07 22:02:32 +02:00
|
|
|
webkitdirectory={type === 'openDirectory' ? 'True' : null}
|
2019-02-22 06:01:59 +01:00
|
|
|
/>
|
|
|
|
</React.Fragment>
|
2018-03-26 23:32:43 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default FileSelector;
|