mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-13 18:27:08 -07:00
New: Custom Formats
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
This commit is contained in:
parent
86e44731bb
commit
9fe13a2d14
187 changed files with 6957 additions and 902 deletions
|
@ -27,6 +27,7 @@ import RootFolderSelectInputConnector from './RootFolderSelectInputConnector';
|
|||
import SeriesTypeSelectInput from './SeriesTypeSelectInput';
|
||||
import TagInputConnector from './TagInputConnector';
|
||||
import TagSelectInputConnector from './TagSelectInputConnector';
|
||||
import TextArea from './TextArea';
|
||||
import TextInput from './TextInput';
|
||||
import TextTagInputConnector from './TextTagInputConnector';
|
||||
import UMaskInput from './UMaskInput';
|
||||
|
@ -100,6 +101,9 @@ function getComponent(type) {
|
|||
case inputTypes.TAG:
|
||||
return TagInputConnector;
|
||||
|
||||
case inputTypes.TEXT_AREA:
|
||||
return TextArea;
|
||||
|
||||
case inputTypes.TEXT_TAG:
|
||||
return TextTagInputConnector;
|
||||
|
||||
|
|
19
frontend/src/Components/Form/TextArea.css
Normal file
19
frontend/src/Components/Form/TextArea.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
.input {
|
||||
composes: input from '~Components/Form/Input.css';
|
||||
|
||||
flex-grow: 1;
|
||||
min-height: 200px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.readOnly {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.hasError {
|
||||
composes: hasError from '~Components/Form/Input.css';
|
||||
}
|
||||
|
||||
.hasWarning {
|
||||
composes: hasWarning from '~Components/Form/Input.css';
|
||||
}
|
172
frontend/src/Components/Form/TextArea.js
Normal file
172
frontend/src/Components/Form/TextArea.js
Normal file
|
@ -0,0 +1,172 @@
|
|||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import styles from './TextArea.css';
|
||||
|
||||
class TextArea extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this._input = null;
|
||||
this._selectionStart = null;
|
||||
this._selectionEnd = null;
|
||||
this._selectionTimeout = null;
|
||||
this._isMouseTarget = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('mouseup', this.onDocumentMouseUp);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('mouseup', this.onDocumentMouseUp);
|
||||
|
||||
if (this._selectionTimeout) {
|
||||
this._selectionTimeout = clearTimeout(this._selectionTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
setInputRef = (ref) => {
|
||||
this._input = ref;
|
||||
};
|
||||
|
||||
selectionChange() {
|
||||
if (this._selectionTimeout) {
|
||||
this._selectionTimeout = clearTimeout(this._selectionTimeout);
|
||||
}
|
||||
|
||||
this._selectionTimeout = setTimeout(() => {
|
||||
const selectionStart = this._input.selectionStart;
|
||||
const selectionEnd = this._input.selectionEnd;
|
||||
|
||||
const selectionChanged = (
|
||||
this._selectionStart !== selectionStart ||
|
||||
this._selectionEnd !== selectionEnd
|
||||
);
|
||||
|
||||
this._selectionStart = selectionStart;
|
||||
this._selectionEnd = selectionEnd;
|
||||
|
||||
if (this.props.onSelectionChange && selectionChanged) {
|
||||
this.props.onSelectionChange(selectionStart, selectionEnd);
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onChange = (event) => {
|
||||
const {
|
||||
name,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const payload = {
|
||||
name,
|
||||
value: event.target.value
|
||||
};
|
||||
|
||||
onChange(payload);
|
||||
};
|
||||
|
||||
onFocus = (event) => {
|
||||
if (this.props.onFocus) {
|
||||
this.props.onFocus(event);
|
||||
}
|
||||
|
||||
this.selectionChange();
|
||||
};
|
||||
|
||||
onKeyUp = () => {
|
||||
this.selectionChange();
|
||||
};
|
||||
|
||||
onMouseDown = () => {
|
||||
this._isMouseTarget = true;
|
||||
};
|
||||
|
||||
onMouseUp = () => {
|
||||
this.selectionChange();
|
||||
};
|
||||
|
||||
onDocumentMouseUp = () => {
|
||||
if (this._isMouseTarget) {
|
||||
this.selectionChange();
|
||||
}
|
||||
|
||||
this._isMouseTarget = false;
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
readOnly,
|
||||
autoFocus,
|
||||
placeholder,
|
||||
name,
|
||||
value,
|
||||
hasError,
|
||||
hasWarning,
|
||||
onBlur
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<textarea
|
||||
ref={this.setInputRef}
|
||||
readOnly={readOnly}
|
||||
autoFocus={autoFocus}
|
||||
placeholder={placeholder}
|
||||
className={classNames(
|
||||
className,
|
||||
readOnly && styles.readOnly,
|
||||
hasError && styles.hasError,
|
||||
hasWarning && styles.hasWarning
|
||||
)}
|
||||
name={name}
|
||||
value={value}
|
||||
onChange={this.onChange}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={onBlur}
|
||||
onKeyUp={this.onKeyUp}
|
||||
onMouseDown={this.onMouseDown}
|
||||
onMouseUp={this.onMouseUp}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TextArea.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
readOnly: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
placeholder: PropTypes.string,
|
||||
name: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]).isRequired,
|
||||
hasError: PropTypes.bool,
|
||||
hasWarning: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onFocus: PropTypes.func,
|
||||
onBlur: PropTypes.func,
|
||||
onSelectionChange: PropTypes.func
|
||||
};
|
||||
|
||||
TextArea.defaultProps = {
|
||||
className: styles.input,
|
||||
type: 'text',
|
||||
readOnly: false,
|
||||
autoFocus: false,
|
||||
value: ''
|
||||
};
|
||||
|
||||
export default TextArea;
|
|
@ -46,13 +46,13 @@ class TextTagInputConnector extends Component {
|
|||
// to oddities with restrictions (as an example).
|
||||
|
||||
const newValue = [...valueArray];
|
||||
const newTags = split(tag.name);
|
||||
const newTags = tag.name.startsWith('/') ? [tag.name] : split(tag.name);
|
||||
|
||||
newTags.forEach((newTag) => {
|
||||
newValue.push(newTag.trim());
|
||||
});
|
||||
|
||||
onChange({ name, value: newValue.join(',') });
|
||||
onChange({ name, value: newValue });
|
||||
};
|
||||
|
||||
onTagDelete = ({ index }) => {
|
||||
|
@ -67,7 +67,7 @@ class TextTagInputConnector extends Component {
|
|||
|
||||
onChange({
|
||||
name,
|
||||
value: newValue.join(',')
|
||||
value: newValue
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ class ClipboardButton extends Component {
|
|||
|
||||
this._id = getUniqueElememtId();
|
||||
this._successTimeout = null;
|
||||
this._testResultTimeout = null;
|
||||
|
||||
this.state = {
|
||||
showSuccess: false,
|
||||
|
@ -26,7 +27,8 @@ class ClipboardButton extends Component {
|
|||
|
||||
componentDidMount() {
|
||||
this._clipboard = new Clipboard(`#${this._id}`, {
|
||||
text: () => this.props.value
|
||||
text: () => this.props.value,
|
||||
container: document.getElementById(this._id)
|
||||
});
|
||||
|
||||
this._clipboard.on('success', this.onSuccess);
|
||||
|
@ -47,6 +49,10 @@ class ClipboardButton extends Component {
|
|||
if (this._clipboard) {
|
||||
this._clipboard.destroy();
|
||||
}
|
||||
|
||||
if (this._testResultTimeout) {
|
||||
clearTimeout(this._testResultTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -80,6 +86,7 @@ class ClipboardButton extends Component {
|
|||
render() {
|
||||
const {
|
||||
value,
|
||||
className,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
|
@ -95,7 +102,7 @@ class ClipboardButton extends Component {
|
|||
return (
|
||||
<FormInputButton
|
||||
id={this._id}
|
||||
className={styles.button}
|
||||
className={className}
|
||||
{...otherProps}
|
||||
>
|
||||
<span className={showStateIcon ? styles.showStateIcon : undefined}>
|
||||
|
@ -121,7 +128,12 @@ class ClipboardButton extends Component {
|
|||
}
|
||||
|
||||
ClipboardButton.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
value: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
ClipboardButton.defaultProps = {
|
||||
className: styles.button
|
||||
};
|
||||
|
||||
export default ClipboardButton;
|
||||
|
|
|
@ -104,6 +104,10 @@ const links = [
|
|||
title: translate('Quality'),
|
||||
to: '/settings/quality'
|
||||
},
|
||||
{
|
||||
title: translate('CustomFormats'),
|
||||
to: '/settings/customformats'
|
||||
},
|
||||
{
|
||||
title: translate('Indexers'),
|
||||
to: '/settings/indexers'
|
||||
|
|
|
@ -196,7 +196,7 @@ class TableOptionsModal extends Component {
|
|||
<TableOptionsColumnDragSource
|
||||
key={name}
|
||||
name={name}
|
||||
label={label || columnLabel}
|
||||
label={columnLabel || label}
|
||||
isVisible={isVisible}
|
||||
isModifiable={true}
|
||||
index={index}
|
||||
|
@ -214,7 +214,7 @@ class TableOptionsModal extends Component {
|
|||
<TableOptionsColumn
|
||||
key={name}
|
||||
name={name}
|
||||
label={label || columnLabel}
|
||||
label={columnLabel || label}
|
||||
isVisible={isVisible}
|
||||
index={index}
|
||||
isModifiable={false}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue