mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-17 15:53:28 +00:00
Change tag list UI (#5637)
* 01 change file tags list * 02 change select tags UI * change edit icons
This commit is contained in:
22
frontend/src/components/common/common-add-tool.js
Normal file
22
frontend/src/components/common/common-add-tool.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import '../../css/common-add-tool.css';
|
||||
|
||||
function CommonAddTool(props) {
|
||||
const { callBack, footerName, className, addIconClassName } = props;
|
||||
return (
|
||||
<div className={`add-item-btn ${className ? className : ''}`} onClick={(e) => {callBack(e);}}>
|
||||
<span className={`fas fa-plus mr-2 ${addIconClassName || ''}`}></span>
|
||||
<span className='add-new-option' title={footerName}>{footerName}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
CommonAddTool.propTypes = {
|
||||
className: PropTypes.string,
|
||||
addIconClassName: PropTypes.string,
|
||||
footerName: PropTypes.string.isRequired,
|
||||
callBack: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default CommonAddTool;
|
101
frontend/src/components/common/seahub-popover.js
Normal file
101
frontend/src/components/common/seahub-popover.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import React from 'react';
|
||||
import { Popover } from 'reactstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import { KeyCodes } from '../../constants';
|
||||
|
||||
const propTypes = {
|
||||
target: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
boundariesElement: PropTypes.object,
|
||||
innerClassName: PropTypes.string,
|
||||
popoverClassName: PropTypes.string,
|
||||
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
hideSeahubPopover: PropTypes.func.isRequired,
|
||||
hideSeahubPopoverWithEsc: PropTypes.func,
|
||||
hideArrow: PropTypes.bool,
|
||||
canHideSeahubPopover: PropTypes.bool,
|
||||
placement: PropTypes.string,
|
||||
modifiers: PropTypes.object
|
||||
};
|
||||
|
||||
class SeahubPopover extends React.Component {
|
||||
|
||||
SeahubPopoverRef = null;
|
||||
isSelectOpen = false;
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('mousedown', this.onMouseDown, true);
|
||||
document.addEventListener('keydown', this.onKeyDown);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('mousedown', this.onMouseDown, true);
|
||||
document.removeEventListener('keydown', this.onKeyDown);
|
||||
}
|
||||
|
||||
getEventClassName = (e) => {
|
||||
// svg mouseEvent event.target.className is an object
|
||||
if (!e || !e.target) return '';
|
||||
return e.target.getAttribute('class') || '';
|
||||
};
|
||||
|
||||
onKeyDown = (e) => {
|
||||
const { canHideSeahubPopover, hideSeahubPopoverWithEsc } = this.props;
|
||||
if (e.keyCode === KeyCodes.Escape && typeof hideSeahubPopoverWithEsc === 'function' && !this.isSelectOpen) {
|
||||
e.preventDefault();
|
||||
hideSeahubPopoverWithEsc();
|
||||
} else if (e.keyCode === KeyCodes.Enter) {
|
||||
// Resolve the default behavior of the enter key when entering formulas is blocked
|
||||
if (canHideSeahubPopover) return;
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
};
|
||||
|
||||
onMouseDown = (e) => {
|
||||
if (!this.props.canHideSeahubPopover) return;
|
||||
if (this.SeahubPopoverRef && e && this.getEventClassName(e).indexOf('popover') === -1 && !this.SeahubPopoverRef.contains(e.target)) {
|
||||
this.props.hideSeahubPopover(e);
|
||||
}
|
||||
};
|
||||
|
||||
onPopoverInsideClick = (e) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
target, boundariesElement, innerClassName, popoverClassName, hideArrow, modifiers,
|
||||
placement,
|
||||
} = this.props;
|
||||
let additionalProps = {};
|
||||
if (boundariesElement) {
|
||||
additionalProps.boundariesElement = boundariesElement;
|
||||
}
|
||||
return (
|
||||
<Popover
|
||||
placement={placement}
|
||||
isOpen={true}
|
||||
target={target}
|
||||
fade={false}
|
||||
hideArrow={hideArrow}
|
||||
innerClassName={innerClassName}
|
||||
className={popoverClassName}
|
||||
modifiers={modifiers}
|
||||
{...additionalProps}
|
||||
>
|
||||
<div ref={ref => this.SeahubPopoverRef = ref} onClick={this.onPopoverInsideClick}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SeahubPopover.defaultProps = {
|
||||
placement: 'bottom-start',
|
||||
hideArrow: true,
|
||||
canHideSeahubPopover: true
|
||||
};
|
||||
|
||||
SeahubPopover.propTypes = propTypes;
|
||||
|
||||
export default SeahubPopover;
|
144
frontend/src/components/common/search-input.js
Normal file
144
frontend/src/components/common/search-input.js
Normal file
@@ -0,0 +1,144 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const propTypes = {
|
||||
placeholder: PropTypes.string,
|
||||
autoFocus: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onKeyDown: PropTypes.func,
|
||||
wait: PropTypes.number,
|
||||
disabled: PropTypes.bool,
|
||||
style: PropTypes.object,
|
||||
isClearable: PropTypes.bool,
|
||||
clearValue: PropTypes.func,
|
||||
clearClassName: PropTypes.string,
|
||||
components: PropTypes.object,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
class SearchInput extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
searchValue: props.value,
|
||||
};
|
||||
this.isInputtingChinese = false;
|
||||
this.timer = null;
|
||||
this.inputRef = null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.autoFocus && this.inputRef && this.inputRef !== document.activeElement) {
|
||||
setTimeout(() => {
|
||||
this.inputRef.focus();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.value !== this.props.value) {
|
||||
this.setState({searchValue: nextProps.value});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.timer && clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
this.inputRef = null;
|
||||
}
|
||||
|
||||
onCompositionStart = () => {
|
||||
this.isInputtingChinese = true;
|
||||
};
|
||||
|
||||
onChange = (e) => {
|
||||
this.timer && clearTimeout(this.timer);
|
||||
const { onChange, wait } = this.props;
|
||||
let text = e.target.value;
|
||||
this.setState({searchValue: text || ''}, () => {
|
||||
if (this.isInputtingChinese) return;
|
||||
this.timer = setTimeout(() => {
|
||||
onChange && onChange(this.state.searchValue.trim());
|
||||
}, wait);
|
||||
});
|
||||
};
|
||||
|
||||
onCompositionEnd = (e) => {
|
||||
this.isInputtingChinese = false;
|
||||
this.onChange(e);
|
||||
};
|
||||
|
||||
clearSearch = () => {
|
||||
const { clearValue } = this.props;
|
||||
this.setState({searchValue: ''}, () => {
|
||||
clearValue && clearValue();
|
||||
});
|
||||
};
|
||||
|
||||
setFocus = (isSelectAllText) => {
|
||||
if (this.inputRef === document.activeElement) return;
|
||||
this.inputRef.focus();
|
||||
if (isSelectAllText) {
|
||||
const txtLength = this.state.searchValue.length;
|
||||
this.inputRef.setSelectionRange(0, txtLength);
|
||||
}
|
||||
};
|
||||
|
||||
isFunction = (functionToCheck) => {
|
||||
const getType = {};
|
||||
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
||||
};
|
||||
|
||||
renderClear = () => {
|
||||
const { isClearable, clearClassName, components = {} } = this.props;
|
||||
const { searchValue } = this.state;
|
||||
if (!isClearable || !searchValue) return null;
|
||||
const { ClearIndicator } = components;
|
||||
if (React.isValidElement(ClearIndicator)) {
|
||||
return React.cloneElement(ClearIndicator, {clearValue: this.clearSearch});
|
||||
} else if (this.isFunction(ClearIndicator)) {
|
||||
return <ClearIndicator clearValue={this.clearSearch} />;
|
||||
}
|
||||
return (
|
||||
<i className={classnames('search-text-clear input-icon-addon', clearClassName)} onClick={this.clearSearch}>×</i>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { placeholder, autoFocus, className, onKeyDown, disabled, style } = this.props;
|
||||
const { searchValue } = this.state;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<input
|
||||
type="text"
|
||||
value={searchValue}
|
||||
className={classnames('form-control', className)}
|
||||
onChange={this.onChange}
|
||||
autoFocus={autoFocus}
|
||||
placeholder={placeholder}
|
||||
onCompositionStart={this.onCompositionStart}
|
||||
onCompositionEnd={this.onCompositionEnd}
|
||||
onKeyDown={onKeyDown}
|
||||
disabled={disabled}
|
||||
style={style}
|
||||
ref={ref => this.inputRef = ref}
|
||||
/>
|
||||
{this.renderClear()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchInput.propTypes = propTypes;
|
||||
|
||||
SearchInput.defaultProps = {
|
||||
wait: 100,
|
||||
disabled: false,
|
||||
value: '',
|
||||
};
|
||||
|
||||
export default SearchInput;
|
Reference in New Issue
Block a user