mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
style: update code style to please lint
This commit is contained in:
parent
1e001d2d82
commit
711d2d7413
@ -8,10 +8,10 @@ function getScroll(w, top) {
|
||||
let method = 'scroll' + (top ? 'Top' : 'Left');
|
||||
if (typeof ret !== 'number') {
|
||||
let d = w.document;
|
||||
//ie6,7,8 standard mode
|
||||
// ie6,7,8 standard mode
|
||||
ret = d.documentElement[method];
|
||||
if (typeof ret !== 'number') {
|
||||
//quirks mode
|
||||
// quirks mode
|
||||
ret = d.body[method];
|
||||
}
|
||||
}
|
||||
|
@ -44,20 +44,20 @@ export default React.createClass({
|
||||
|
||||
let iconType = '';
|
||||
switch (type) {
|
||||
case 'success':
|
||||
iconType = 'check-circle';
|
||||
break;
|
||||
case 'info':
|
||||
iconType = 'info-circle';
|
||||
break;
|
||||
case 'error':
|
||||
iconType = 'exclamation-circle';
|
||||
break;
|
||||
case 'warn':
|
||||
iconType = 'exclamation-circle';
|
||||
break;
|
||||
default:
|
||||
iconType = 'default';
|
||||
case 'success':
|
||||
iconType = 'check-circle';
|
||||
break;
|
||||
case 'info':
|
||||
iconType = 'info-circle';
|
||||
break;
|
||||
case 'error':
|
||||
iconType = 'exclamation-circle';
|
||||
break;
|
||||
case 'warn':
|
||||
iconType = 'exclamation-circle';
|
||||
break;
|
||||
default:
|
||||
iconType = 'default';
|
||||
}
|
||||
|
||||
// use outline icon in alert with description
|
||||
|
@ -26,16 +26,13 @@ class AntScrollNumber extends React.Component {
|
||||
if (this.state.count > this.lastCount) {
|
||||
if (currentDigit >= lastDigit) {
|
||||
return 10 + num;
|
||||
} else {
|
||||
return 20 + num;
|
||||
}
|
||||
} else {
|
||||
if (currentDigit <= lastDigit) {
|
||||
return 10 + num;
|
||||
} else {
|
||||
return num;
|
||||
}
|
||||
return 20 + num;
|
||||
}
|
||||
if (currentDigit <= lastDigit) {
|
||||
return 10 + num;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
@ -106,13 +103,12 @@ class AntScrollNumber extends React.Component {
|
||||
props,
|
||||
this.renderNumberElement()
|
||||
);
|
||||
} else {
|
||||
return createElement(
|
||||
this.props.component,
|
||||
props,
|
||||
props.count
|
||||
);
|
||||
}
|
||||
return createElement(
|
||||
this.props.component,
|
||||
props,
|
||||
props.count
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,12 @@ const BreadcrumbItem = React.createClass({
|
||||
if (typeof this.props.href === 'undefined') {
|
||||
link = <span className={prefixCls + '-link'} {...this.props}>{children}</span>;
|
||||
}
|
||||
return <span>
|
||||
{link}
|
||||
<span className={prefixCls + '-separator'}>{separator}</span>
|
||||
</span>;
|
||||
return (
|
||||
<span>
|
||||
{link}
|
||||
<span className={prefixCls + '-separator'}>{separator}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -52,9 +52,11 @@ export default class Button extends React.Component {
|
||||
|
||||
const kids = React.Children.map(children, insertSpace);
|
||||
|
||||
return <button {...others} type={htmlType || 'button'} className={classes} onClick={onClick}>
|
||||
{kids}
|
||||
</button>;
|
||||
return (
|
||||
<button {...others} type={htmlType || 'button'} className={classes} onClick={onClick}>
|
||||
{kids}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,25 +35,29 @@ class Calendar extends Component {
|
||||
monthCellRender(value, locale) {
|
||||
const prefixCls = this.props.prefixCls;
|
||||
const month = value.getMonth();
|
||||
return <div className={`${prefixCls}-month`}>
|
||||
<div className={`${prefixCls}-value`}>
|
||||
{locale.format.shortMonths[month]}
|
||||
return (
|
||||
<div className={`${prefixCls}-month`}>
|
||||
<div className={`${prefixCls}-value`}>
|
||||
{locale.format.shortMonths[month]}
|
||||
</div>
|
||||
<div className={`${prefixCls}-content`}>
|
||||
{this.props.monthCellRender(value)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${prefixCls}-content`}>
|
||||
{this.props.monthCellRender(value)}
|
||||
</div>
|
||||
</div>;
|
||||
);
|
||||
}
|
||||
dateCellRender(value) {
|
||||
const prefixCls = this.props.prefixCls;
|
||||
return <div className={`${prefixCls}-date`}>
|
||||
<div className={`${prefixCls}-value`}>
|
||||
{zerofixed(value.getDayOfMonth())}
|
||||
return (
|
||||
<div className={`${prefixCls}-date`}>
|
||||
<div className={`${prefixCls}-value`}>
|
||||
{zerofixed(value.getDayOfMonth())}
|
||||
</div>
|
||||
<div className={`${prefixCls}-content`}>
|
||||
{this.props.dateCellRender(value)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${prefixCls}-content`}>
|
||||
{this.props.dateCellRender(value)}
|
||||
</div>
|
||||
</div>;
|
||||
);
|
||||
}
|
||||
setValue(value) {
|
||||
if (!('value' in this.props) && this.state.value !== value) {
|
||||
|
@ -42,17 +42,19 @@ export default React.createClass({
|
||||
},
|
||||
render() {
|
||||
const options = this.props.options;
|
||||
return <div className="ant-checkbox-group">
|
||||
{
|
||||
options.map(option =>
|
||||
<label className="ant-checkbox-group-item" key={option}>
|
||||
<Checkbox disabled={this.props.disabled}
|
||||
checked={this.state.value.indexOf(option) !== -1}
|
||||
onChange={this.toggleOption.bind(this, option)} />
|
||||
{option}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
</div>;
|
||||
return (
|
||||
<div className="ant-checkbox-group">
|
||||
{
|
||||
options.map(option =>
|
||||
<label className="ant-checkbox-group-item" key={option}>
|
||||
<Checkbox disabled={this.props.disabled}
|
||||
checked={this.state.value.indexOf(option) !== -1}
|
||||
onChange={this.toggleOption.bind(this, option)} />
|
||||
{option}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
@ -76,14 +76,16 @@ export default React.createClass({
|
||||
['ant-calendar-time']: this.props.showTime,
|
||||
});
|
||||
|
||||
const calendar = <RangeCalendar prefixCls="ant-calendar"
|
||||
className={calendarClassName}
|
||||
timePicker={timePicker}
|
||||
disabledDate={disabledDate}
|
||||
dateInputPlaceholder={[startPlaceholder, endPlaceholder]}
|
||||
locale={locale.lang}
|
||||
defaultValue={defaultCalendarValue}
|
||||
showClear />;
|
||||
const calendar = (
|
||||
<RangeCalendar prefixCls="ant-calendar"
|
||||
className={calendarClassName}
|
||||
timePicker={timePicker}
|
||||
disabledDate={disabledDate}
|
||||
dateInputPlaceholder={[startPlaceholder, endPlaceholder]}
|
||||
locale={locale.lang}
|
||||
defaultValue={defaultCalendarValue}
|
||||
showClear />
|
||||
);
|
||||
|
||||
const pickerClass = classNames({
|
||||
'ant-calendar-picker': true,
|
||||
|
@ -91,35 +91,36 @@ function createPicker(TheCalendar, defaultFormat) {
|
||||
pickerClass += ' ant-calendar-picker-open';
|
||||
}
|
||||
|
||||
return <span className={pickerClass}>
|
||||
<DatePicker
|
||||
transitionName={this.props.transitionName}
|
||||
disabled={this.props.disabled}
|
||||
calendar={calendar}
|
||||
value={this.state.value}
|
||||
prefixCls="ant-calendar-picker-container"
|
||||
style={this.props.popupStyle}
|
||||
align={this.props.align}
|
||||
onOpen={this.toggleOpen}
|
||||
onClose={this.toggleOpen}
|
||||
onChange={this.handleChange}>
|
||||
{
|
||||
({ value }) => {
|
||||
return (
|
||||
<span>
|
||||
<input disabled={this.props.disabled}
|
||||
onChange={this.handleInputChange}
|
||||
value={value && this.getFormatter().format(value)}
|
||||
placeholder={placeholder}
|
||||
style={this.props.style}
|
||||
className={'ant-calendar-picker-input ant-input' + sizeClass}/>
|
||||
<span className="ant-calendar-picker-icon"/>
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<span className={pickerClass}>
|
||||
<DatePicker transitionName={this.props.transitionName}
|
||||
disabled={this.props.disabled}
|
||||
calendar={calendar}
|
||||
value={this.state.value}
|
||||
prefixCls="ant-calendar-picker-container"
|
||||
style={this.props.popupStyle}
|
||||
align={this.props.align}
|
||||
onOpen={this.toggleOpen}
|
||||
onClose={this.toggleOpen}
|
||||
onChange={this.handleChange}>
|
||||
{
|
||||
({ value }) => {
|
||||
return (
|
||||
<span>
|
||||
<input disabled={this.props.disabled}
|
||||
onChange={this.handleInputChange}
|
||||
value={value && this.getFormatter().format(value)}
|
||||
placeholder={placeholder}
|
||||
style={this.props.style}
|
||||
className={'ant-calendar-picker-input ant-input' + sizeClass}/>
|
||||
<span className="ant-calendar-picker-icon"/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
</DatePicker>
|
||||
</span>;
|
||||
</DatePicker>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -22,15 +22,17 @@ export default React.createClass({
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return <ButtonGroup className="ant-dropdown-button">
|
||||
<Button type={this.props.type}>
|
||||
{this.props.children}
|
||||
</Button>
|
||||
<Dropdown {...this.props}>
|
||||
return (
|
||||
<ButtonGroup className="ant-dropdown-button">
|
||||
<Button type={this.props.type}>
|
||||
<Icon type="down" />
|
||||
{this.props.children}
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</ButtonGroup>;
|
||||
<Dropdown {...this.props}>
|
||||
<Button type={this.props.type}>
|
||||
<Icon type="down" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -85,10 +85,8 @@ class FormItem extends React.Component {
|
||||
const compactControls = ['checkbox', 'radio', 'radio-group', 'static', 'file'];
|
||||
let isCompact = false;
|
||||
|
||||
if (!Array.isArray(children)) {
|
||||
children = [children];
|
||||
}
|
||||
children.map((child) => {
|
||||
const childrenArray = Array.isArray(children) ? children : [children];
|
||||
childrenArray.map((child) => {
|
||||
const type = child.props && child.props.type;
|
||||
let prefixCls = child.props && child.props.prefixCls;
|
||||
prefixCls = prefixCls ? prefixCls.substring(prefixCls.indexOf('-') + 1) : '';
|
||||
|
@ -72,12 +72,12 @@ class Input extends React.Component {
|
||||
}
|
||||
|
||||
switch (props.size) {
|
||||
case 'small': inputClassName = prefixClsFn(prefixCls, 'input', 'input-sm'); break;
|
||||
case 'large': inputClassName = prefixClsFn(prefixCls, 'input', 'input-lg'); break;
|
||||
default:
|
||||
case 'small': inputClassName = prefixClsFn(prefixCls, 'input', 'input-sm'); break;
|
||||
case 'large': inputClassName = prefixClsFn(prefixCls, 'input', 'input-lg'); break;
|
||||
default:
|
||||
}
|
||||
let placeholder = props.placeholder;
|
||||
if(placeholder && ieGT9()){
|
||||
if (placeholder && ieGT9()) {
|
||||
placeholder = null;
|
||||
}
|
||||
if ('value' in props) {
|
||||
|
@ -4,12 +4,11 @@ import Dialog from './index';
|
||||
import Icon from '../icon';
|
||||
import Button from '../button';
|
||||
|
||||
export default function (props) {
|
||||
export default function (props = {}) {
|
||||
let div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
|
||||
let d;
|
||||
props = props || {};
|
||||
props.iconClassName = props.iconClassName || 'question-circle';
|
||||
|
||||
let iconClassType = props.iconClassName;
|
||||
@ -72,28 +71,34 @@ export default function (props) {
|
||||
}
|
||||
}
|
||||
|
||||
let body = <div className="ant-confirm-body">
|
||||
<Icon type={iconClassType} />
|
||||
<span className="ant-confirm-title">{props.title}</span>
|
||||
<div className="ant-confirm-content">{props.content}</div>
|
||||
</div>;
|
||||
let body = (
|
||||
<div className="ant-confirm-body">
|
||||
<Icon type={iconClassType} />
|
||||
<span className="ant-confirm-title">{props.title}</span>
|
||||
<div className="ant-confirm-content">{props.content}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
let footer = null;
|
||||
if (props.okCancel) {
|
||||
footer = <div className="ant-confirm-btns">
|
||||
<Button type="ghost" size="large" onClick={onCancel}>
|
||||
{props.cancelText}
|
||||
</Button>
|
||||
<Button type="primary" size="large" onClick={onOk}>
|
||||
{props.okText}
|
||||
</Button>
|
||||
</div>;
|
||||
footer = (
|
||||
<div className="ant-confirm-btns">
|
||||
<Button type="ghost" size="large" onClick={onCancel}>
|
||||
{props.cancelText}
|
||||
</Button>
|
||||
<Button type="primary" size="large" onClick={onOk}>
|
||||
{props.okText}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
footer = <div className="ant-confirm-btns">
|
||||
<Button type="primary" size="large" onClick={onOk}>
|
||||
{props.okText}
|
||||
</Button>
|
||||
</div>;
|
||||
footer = (
|
||||
<div className="ant-confirm-btns">
|
||||
<Button type="primary" size="large" onClick={onOk}>
|
||||
{props.okText}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<Dialog
|
||||
|
@ -70,8 +70,10 @@ let AntModal = React.createClass({
|
||||
</Button>
|
||||
];
|
||||
let footer = props.footer || defaultFooter;
|
||||
return <Dialog onClose={this.handleCancel} footer={footer} {...props}
|
||||
visible={props.visible} mousePosition={mousePosition} />;
|
||||
return (
|
||||
<Dialog onClose={this.handleCancel} footer={footer} {...props}
|
||||
visible={props.visible} mousePosition={mousePosition} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -98,10 +98,10 @@ function notice(args) {
|
||||
}
|
||||
|
||||
let api = {
|
||||
open(args){
|
||||
open(args) {
|
||||
notice(args);
|
||||
},
|
||||
close(key){
|
||||
close(key) {
|
||||
if (notificationInstance) {
|
||||
notificationInstance.removeNotice(key);
|
||||
}
|
||||
|
@ -21,10 +21,12 @@ class AntPagination extends React.Component {
|
||||
selectComponentClass = MiniSelect;
|
||||
}
|
||||
|
||||
return <Pagination selectComponentClass={selectComponentClass}
|
||||
selectPrefixCls="ant-select"
|
||||
{...this.props}
|
||||
className={className} />;
|
||||
return (
|
||||
<Pagination selectComponentClass={selectComponentClass}
|
||||
selectPrefixCls="ant-select"
|
||||
{...this.props}
|
||||
className={className} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,18 +63,20 @@ export default React.createClass({
|
||||
},
|
||||
render() {
|
||||
const {title, okText, cancelText, placement, overlayStyle, trigger} = this.props;
|
||||
const overlay = <div>
|
||||
<div className={prefixCls + '-content'}>
|
||||
<p className={prefixCls + '-message'}>
|
||||
<Icon type="exclamation-circle" />
|
||||
{title}
|
||||
</p>
|
||||
<div className={prefixCls + '-buttons'}>
|
||||
<Button onClick={this.cancel} type="ghost" size="small">{cancelText}</Button>
|
||||
<Button onClick={this.confirm} type="primary" size="small">{okText}</Button>
|
||||
const overlay = (
|
||||
<div>
|
||||
<div className={prefixCls + '-content'}>
|
||||
<p className={prefixCls + '-message'}>
|
||||
<Icon type="exclamation-circle" />
|
||||
{title}
|
||||
</p>
|
||||
<div className={prefixCls + '-buttons'}>
|
||||
<Button onClick={this.cancel} type="ghost" size="small">{cancelText}</Button>
|
||||
<Button onClick={this.confirm} type="primary" size="small">{okText}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
);
|
||||
|
||||
const transitionName = transitionNames[placement];
|
||||
|
||||
|
@ -46,12 +46,14 @@ const Popover = React.createClass({
|
||||
},
|
||||
|
||||
getOverlay() {
|
||||
return <div>
|
||||
{this.props.title && <div className={prefixCls + '-title'}>{this.props.title}</div>}
|
||||
<div className={prefixCls + '-content'}>
|
||||
{this.props.overlay}
|
||||
return (
|
||||
<div>
|
||||
{this.props.title && <div className={prefixCls + '-title'}>{this.props.title}</div>}
|
||||
<div className={prefixCls + '-content'}>
|
||||
{this.props.overlay}
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -39,7 +39,7 @@ let Line = React.createClass({
|
||||
const text = (typeof props.format === 'string') ?
|
||||
props.format.replace('${percent}', props.percent) : props.format;
|
||||
|
||||
if(props.showInfo === true){
|
||||
if (props.showInfo === true) {
|
||||
if (props.status === 'exception') {
|
||||
progressInfo = (
|
||||
<span className={prefixCls + '-line-text'}>{text}</span>
|
||||
|
@ -37,13 +37,13 @@ export default React.createClass({
|
||||
let props = this.props;
|
||||
let children = React.Children.map(props.children, (radio) => {
|
||||
if (radio.props) {
|
||||
return <Radio
|
||||
key={radio.props.value}
|
||||
{...radio.props}
|
||||
onChange={this.onRadioChange}
|
||||
checked={this.state.value === radio.props.value}
|
||||
disabled={radio.props.disabled || this.props.disabled}
|
||||
/>;
|
||||
return (
|
||||
<Radio key={radio.props.value}
|
||||
{...radio.props}
|
||||
onChange={this.onRadioChange}
|
||||
checked={this.state.value === radio.props.value}
|
||||
disabled={radio.props.disabled || this.props.disabled}/>
|
||||
);
|
||||
}
|
||||
return radio;
|
||||
});
|
||||
|
@ -53,9 +53,8 @@ const AntSpin = React.createClass({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return spinElement;
|
||||
}
|
||||
return spinElement;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -13,7 +13,7 @@ let FilterMenu = React.createClass({
|
||||
visible: false,
|
||||
};
|
||||
},
|
||||
componentWillReceiveProps(nextProps){
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
selectedKeys: nextProps.selectedKeys
|
||||
});
|
||||
@ -95,6 +95,7 @@ let FilterMenu = React.createClass({
|
||||
if ('filterMultiple' in column) {
|
||||
multiple = column.filterMultiple;
|
||||
}
|
||||
<<<<<<< 1e001d2d82c5816b55d3953939fcaedbbacf1a3c
|
||||
let menus = <div className="ant-table-filter-dropdown">
|
||||
<Menu multiple={multiple} onClick={this.handleMenuItemClick}
|
||||
prefixCls="ant-dropdown-menu"
|
||||
@ -112,21 +113,44 @@ let FilterMenu = React.createClass({
|
||||
onClick={this.handleClearFilters}>
|
||||
{locale.filterReset}
|
||||
</a>
|
||||
=======
|
||||
let menus = (
|
||||
<div className="ant-table-filter-dropdown">
|
||||
<Menu multiple={multiple}
|
||||
prefixCls="ant-dropdown-menu"
|
||||
onSelect={this.setSelectedKeys}
|
||||
onDeselect={this.setSelectedKeys}
|
||||
selectedKeys={this.state.selectedKeys}>
|
||||
{this.renderMenus(column.filters)}
|
||||
</Menu>
|
||||
<div className="ant-table-filter-dropdown-btns">
|
||||
<a className="ant-table-filter-dropdown-link confirm"
|
||||
onClick={this.handleConfirm}>
|
||||
{locale.filterConfirm}
|
||||
</a>
|
||||
<a className="ant-table-filter-dropdown-link clear"
|
||||
onClick={this.handleClearFilters}>
|
||||
{locale.filterReset}
|
||||
</a>
|
||||
</div>
|
||||
>>>>>>> style: update code style to please lint
|
||||
</div>
|
||||
</div>;
|
||||
);
|
||||
|
||||
let dropdownSelectedClass = '';
|
||||
if (this.props.selectedKeys.length > 0) {
|
||||
dropdownSelectedClass = 'ant-table-filter-selected';
|
||||
}
|
||||
|
||||
return <Dropdown trigger={['click']}
|
||||
overlay={menus}
|
||||
visible={this.state.visible}
|
||||
onVisibleChange={this.onVisibleChange}
|
||||
closeOnSelect={false}>
|
||||
<Icon title={locale.filterTitle} type="filter" className={dropdownSelectedClass} />
|
||||
</Dropdown>;
|
||||
return (
|
||||
<Dropdown trigger={['click']}
|
||||
overlay={menus}
|
||||
visible={this.state.visible}
|
||||
onVisibleChange={this.onVisibleChange}
|
||||
closeOnSelect={false}>
|
||||
<Icon title={locale.filterTitle} type="filter" className={dropdownSelectedClass} />
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -147,9 +147,9 @@ let AntTable = React.createClass({
|
||||
this.props.onChange.apply(this, this.prepareParamsArguments(objectAssign({}, this.state, newState)));
|
||||
},
|
||||
|
||||
handleFilter(column, filters) {
|
||||
filters = objectAssign({}, this.state.filters, {
|
||||
[this.getColumnKey(column)]: filters
|
||||
handleFilter(column, nextFilters) {
|
||||
const filters = objectAssign({}, this.state.filters, {
|
||||
[this.getColumnKey(column)]: nextFilters
|
||||
});
|
||||
// Remove filters not in current columns
|
||||
const currentColumnKeys = this.props.columns.map(c => this.getColumnKey(c));
|
||||
@ -281,8 +281,10 @@ let AntTable = React.createClass({
|
||||
checked = (this.state.radioIndex === rowIndex ||
|
||||
this.getDefaultSelection().indexOf(rowIndex) >= 0);
|
||||
}
|
||||
return <Radio disabled={props.disabled} onChange={this.handleRadioSelect.bind(this, record, rowIndex)}
|
||||
value={rowIndex} checked={checked}/>;
|
||||
return (
|
||||
<Radio disabled={props.disabled} onChange={this.handleRadioSelect.bind(this, record, rowIndex)}
|
||||
value={rowIndex} checked={checked}/>
|
||||
);
|
||||
},
|
||||
|
||||
renderSelectionCheckBox(value, record, index) {
|
||||
@ -298,8 +300,10 @@ let AntTable = React.createClass({
|
||||
if (this.props.rowSelection.getCheckboxProps) {
|
||||
props = this.props.rowSelection.getCheckboxProps.call(this, record);
|
||||
}
|
||||
return <Checkbox checked={checked} disabled={props.disabled}
|
||||
onChange={this.handleSelect.bind(this, record, rowIndex)}/>;
|
||||
return (
|
||||
<Checkbox checked={checked} disabled={props.disabled}
|
||||
onChange={this.handleSelect.bind(this, record, rowIndex)}/>
|
||||
);
|
||||
},
|
||||
|
||||
getRecordKey(record, index) {
|
||||
@ -377,16 +381,18 @@ let AntTable = React.createClass({
|
||||
|
||||
renderColumnsDropdown(columns) {
|
||||
let locale = objectAssign({}, defaultLocale, this.props.locale);
|
||||
return columns.map((column, i) => {
|
||||
column = objectAssign({}, column);
|
||||
return columns.map((originColumn, i) => {
|
||||
let column = objectAssign({}, originColumn);
|
||||
let key = this.getColumnKey(column, i);
|
||||
let filterDropdown, sortButton;
|
||||
let filterDropdown;
|
||||
let sortButton;
|
||||
if (column.filters && column.filters.length > 0) {
|
||||
let colFilters = this.state.filters[key] || [];
|
||||
filterDropdown =
|
||||
filterDropdown = (
|
||||
<FilterDropdown locale={locale} column={column}
|
||||
selectedKeys={colFilters}
|
||||
confirmFilter={this.handleFilter}/>;
|
||||
confirmFilter={this.handleFilter}/>
|
||||
);
|
||||
}
|
||||
if (column.sorter) {
|
||||
let isSortColumn = this.isSortColumn(column);
|
||||
@ -397,26 +403,30 @@ let AntTable = React.createClass({
|
||||
}
|
||||
}
|
||||
|
||||
sortButton = <div className="ant-table-column-sorter">
|
||||
<span className={'ant-table-column-sorter-up ' +
|
||||
((isSortColumn && this.state.sortOrder === 'ascend') ? 'on' : 'off')}
|
||||
title="↑"
|
||||
onClick={this.toggleSortOrder.bind(this, 'ascend', column)}>
|
||||
<Icon type="caret-up"/>
|
||||
</span>
|
||||
<span className={'ant-table-column-sorter-down ' +
|
||||
((isSortColumn && this.state.sortOrder === 'descend') ? 'on' : 'off')}
|
||||
title="↓"
|
||||
onClick={this.toggleSortOrder.bind(this, 'descend', column)}>
|
||||
<Icon type="caret-down"/>
|
||||
</span>
|
||||
</div>;
|
||||
sortButton = (
|
||||
<div className="ant-table-column-sorter">
|
||||
<span className={'ant-table-column-sorter-up ' +
|
||||
((isSortColumn && this.state.sortOrder === 'ascend') ? 'on' : 'off')}
|
||||
title="↑"
|
||||
onClick={this.toggleSortOrder.bind(this, 'ascend', column)}>
|
||||
<Icon type="caret-up"/>
|
||||
</span>
|
||||
<span className={'ant-table-column-sorter-down ' +
|
||||
((isSortColumn && this.state.sortOrder === 'descend') ? 'on' : 'off')}
|
||||
title="↓"
|
||||
onClick={this.toggleSortOrder.bind(this, 'descend', column)}>
|
||||
<Icon type="caret-down"/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
column.title = <div>
|
||||
{column.title}
|
||||
{sortButton}
|
||||
{filterDropdown}
|
||||
</div>;
|
||||
column.title = (
|
||||
<div>
|
||||
{column.title}
|
||||
{sortButton}
|
||||
{filterDropdown}
|
||||
</div>
|
||||
);
|
||||
return column;
|
||||
});
|
||||
},
|
||||
@ -475,7 +485,8 @@ let AntTable = React.createClass({
|
||||
|
||||
getCurrentPageData(dataSource) {
|
||||
let data = this.getLocalData(dataSource);
|
||||
let current, pageSize;
|
||||
let current;
|
||||
let pageSize;
|
||||
let state = this.state;
|
||||
// 如果没有分页的话,默认全部展示
|
||||
if (!this.hasPagination()) {
|
||||
@ -546,20 +557,24 @@ let AntTable = React.createClass({
|
||||
let emptyText;
|
||||
let emptyClass = '';
|
||||
if (!data || data.length === 0) {
|
||||
emptyText = <div className="ant-table-placeholder">
|
||||
<Icon type="frown"/>{locale.emptyText}
|
||||
</div>;
|
||||
emptyText = (
|
||||
<div className="ant-table-placeholder">
|
||||
<Icon type="frown"/>{locale.emptyText}
|
||||
</div>
|
||||
);
|
||||
emptyClass = ' ant-table-empty';
|
||||
}
|
||||
|
||||
let table = <div>
|
||||
<Table {...this.props}
|
||||
data={data}
|
||||
columns={columns}
|
||||
className={classString}
|
||||
expandIconAsCell={expandIconAsCell} />
|
||||
{emptyText}
|
||||
</div>;
|
||||
let table = (
|
||||
<div>
|
||||
<Table {...this.props}
|
||||
data={data}
|
||||
columns={columns}
|
||||
className={classString}
|
||||
expandIconAsCell={expandIconAsCell} />
|
||||
{emptyText}
|
||||
</div>
|
||||
);
|
||||
if (this.props.loading) {
|
||||
// if there is no pagination or no data, the height of spin should decrease by half of pagination
|
||||
let paginationPatchClass = (this.hasPagination() && data && data.length !== 0)
|
||||
|
@ -51,20 +51,28 @@ class AntTabs extends React.Component {
|
||||
});
|
||||
}
|
||||
// Add new tab handler
|
||||
tabBarExtraContent = <span>
|
||||
<Icon type="plus" className={prefixCls + '-new-tab'} onClick={this.createNewTab} />
|
||||
{tabBarExtraContent}
|
||||
</span>;
|
||||
tabBarExtraContent = (
|
||||
<span>
|
||||
<Icon type="plus" className={prefixCls + '-new-tab'} onClick={this.createNewTab} />
|
||||
{tabBarExtraContent}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
// Wrap the extra content
|
||||
tabBarExtraContent = <div className={prefixCls + '-extra-content'}>
|
||||
{tabBarExtraContent}
|
||||
</div>;
|
||||
return <Tabs {...this.props}
|
||||
className={className}
|
||||
tabBarExtraContent={tabBarExtraContent}
|
||||
onChange={this.handleChange}
|
||||
animation={animation}>{children}</Tabs>;
|
||||
tabBarExtraContent = (
|
||||
<div className={prefixCls + '-extra-content'}>
|
||||
{tabBarExtraContent}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Tabs {...this.props}
|
||||
className={className}
|
||||
tabBarExtraContent={tabBarExtraContent}
|
||||
onChange={this.handleChange}
|
||||
animation={animation}>
|
||||
{children}
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ Timeline.Item = React.createClass({
|
||||
|
||||
return (
|
||||
<li className={prefixCls + '-item ' + endCls}>
|
||||
<div style={{display:lastTailShow}} className={prefixCls + '-item-tail'}></div>
|
||||
<div style={{display: lastTailShow}} className={prefixCls + '-item-tail'}></div>
|
||||
<div className={prefixCls + '-item-head ' + prefixCls + '-item-head-' + color}></div>
|
||||
<div className={prefixCls + '-item-content'}>{props.children}</div>
|
||||
{last}
|
||||
|
@ -29,7 +29,7 @@ class Transfer extends Component {
|
||||
if ( targetKeys.length > 0 ) {
|
||||
targetKeys.forEach((targetKey) => {
|
||||
rightDataSource.push(leftDataSource.find((data, index) => {
|
||||
if( data.key === targetKey ) {
|
||||
if ( data.key === targetKey ) {
|
||||
leftDataSource.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
@ -53,7 +53,7 @@ class Transfer extends Component {
|
||||
|
||||
// empty checked keys
|
||||
this.setState({
|
||||
[direction === 'right' ? 'leftCheckedKeys' : 'rightCheckedKeys']: [],
|
||||
[ direction === 'right' ? 'leftCheckedKeys' : 'rightCheckedKeys' ]: [],
|
||||
});
|
||||
|
||||
this.props.onChange(newTargetKeys);
|
||||
@ -162,52 +162,51 @@ class Transfer extends Component {
|
||||
prefixCls: true,
|
||||
});
|
||||
|
||||
return <div className={cls}>
|
||||
<List titleText={titles[0]}
|
||||
dataSource={leftDataSource}
|
||||
filter={leftFilter}
|
||||
style={listStyle}
|
||||
checkedKeys={leftCheckedKeys}
|
||||
checkStatus={leftCheckStatus}
|
||||
handleFilter={this.handleFilter.bind(this, 'left')}
|
||||
handleClear={this.handleClear.bind(this, 'left')}
|
||||
handleSelect={this.handleSelect.bind(this, 'left')}
|
||||
handleSelectAll={this.handleSelectAll.bind(this, 'left')}
|
||||
position="left"
|
||||
render={this.props.render}
|
||||
showSearch={showSearch}
|
||||
searchPlaceholder={searchPlaceholder}
|
||||
body={body}
|
||||
footer={footer}
|
||||
prefixCls={prefixCls + '-list'}
|
||||
/>
|
||||
<Operation rightActive={rightActive}
|
||||
rightArrowText={operations[0]}
|
||||
moveToRight={this.moveTo.bind(this, 'right')}
|
||||
leftActive={leftActive}
|
||||
leftArrowText={operations[1]}
|
||||
moveToLeft={this.moveTo.bind(this, 'left')}
|
||||
className={prefixCls + '-operation'}
|
||||
/>
|
||||
<List titleText={titles[1]}
|
||||
dataSource={rightDataSource}
|
||||
filter={rightFilter}
|
||||
style={listStyle}
|
||||
checkedKeys={rightCheckedKeys}
|
||||
checkStatus={rightCheckStatus}
|
||||
handleFilter={this.handleFilter.bind(this, 'right')}
|
||||
handleClear={this.handleClear.bind(this, 'right')}
|
||||
handleSelect={this.handleSelect.bind(this, 'right')}
|
||||
handleSelectAll={this.handleSelectAll.bind(this, 'right')}
|
||||
position="right"
|
||||
render={this.props.render}
|
||||
showSearch={showSearch}
|
||||
searchPlaceholder={searchPlaceholder}
|
||||
body={body}
|
||||
footer={footer}
|
||||
prefixCls={prefixCls + '-list'}
|
||||
/>
|
||||
</div>;
|
||||
return (
|
||||
<div className={cls}>
|
||||
<List titleText={titles[0]}
|
||||
dataSource={leftDataSource}
|
||||
filter={leftFilter}
|
||||
style={listStyle}
|
||||
checkedKeys={leftCheckedKeys}
|
||||
checkStatus={leftCheckStatus}
|
||||
handleFilter={this.handleFilter.bind(this, 'left')}
|
||||
handleClear={this.handleClear.bind(this, 'left')}
|
||||
handleSelect={this.handleSelect.bind(this, 'left')}
|
||||
handleSelectAll={this.handleSelectAll.bind(this, 'left')}
|
||||
position="left"
|
||||
render={this.props.render}
|
||||
showSearch={showSearch}
|
||||
searchPlaceholder={searchPlaceholder}
|
||||
body={body}
|
||||
footer={footer}
|
||||
prefixCls={prefixCls + '-list'}/>
|
||||
<Operation rightActive={rightActive}
|
||||
rightArrowText={operations[0]}
|
||||
moveToRight={this.moveTo.bind(this, 'right')}
|
||||
leftActive={leftActive}
|
||||
leftArrowText={operations[1]}
|
||||
moveToLeft={this.moveTo.bind(this, 'left')}
|
||||
className={prefixCls + '-operation'}/>
|
||||
<List titleText={titles[1]}
|
||||
dataSource={rightDataSource}
|
||||
filter={rightFilter}
|
||||
style={listStyle}
|
||||
checkedKeys={rightCheckedKeys}
|
||||
checkStatus={rightCheckStatus}
|
||||
handleFilter={this.handleFilter.bind(this, 'right')}
|
||||
handleClear={this.handleClear.bind(this, 'right')}
|
||||
handleSelect={this.handleSelect.bind(this, 'right')}
|
||||
handleSelectAll={this.handleSelectAll.bind(this, 'right')}
|
||||
position="right"
|
||||
render={this.props.render}
|
||||
showSearch={showSearch}
|
||||
searchPlaceholder={searchPlaceholder}
|
||||
body={body}
|
||||
footer={footer}
|
||||
prefixCls={prefixCls + '-list'}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,11 +54,13 @@ class TransferList extends Component {
|
||||
if (typeof props.checkable !== 'boolean') {
|
||||
customEle = props.checkable;
|
||||
}
|
||||
return <span ref="checkbox"
|
||||
className={checkboxCls}
|
||||
onClick={(!props.disabled) && this.handleSelectALl.bind(this)}>
|
||||
{customEle}
|
||||
</span>;
|
||||
return (
|
||||
<span ref="checkbox"
|
||||
className={checkboxCls}
|
||||
onClick={(!props.disabled) && this.handleSelectALl.bind(this)}>
|
||||
{customEle}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
matchFilter(text, filterText) {
|
||||
@ -78,48 +80,50 @@ class TransferList extends Component {
|
||||
[prefixCls + '-with-footer']: !!footerDom,
|
||||
});
|
||||
|
||||
return <div className={listCls} {...this.props}>
|
||||
<div className={`${prefixCls}-header`}>
|
||||
{this.renderCheckbox({
|
||||
prefixCls: 'ant-transfer',
|
||||
checked: checkStatus === 'all',
|
||||
checkPart: checkStatus === 'part',
|
||||
checkable: <span className={`ant-transfer-checkbox-inner`}></span>
|
||||
})}<span className={`${prefixCls}-header-selected`}><span>{(checkedKeys.length > 0 ? checkedKeys.length + '/' : '') + dataSource.length} 条</span>
|
||||
<span className={`${prefixCls}-header-title`}>{titleText}</span></span>
|
||||
</div>
|
||||
{ bodyDom ? bodyDom :
|
||||
<div className={ showSearch ? `${prefixCls}-body ${prefixCls}-body-with-search` : `${prefixCls}-body`}>
|
||||
{ showSearch ? <div className={`${prefixCls}-body-search-wrapper`}>
|
||||
<Search prefixCls={`${prefixCls}-search`} onChange={this.handleFilter.bind(this)} handleClear={this.handleClear.bind(this)} value={filter} />
|
||||
return (
|
||||
<div className={listCls} {...this.props}>
|
||||
<div className={`${prefixCls}-header`}>
|
||||
{this.renderCheckbox({
|
||||
prefixCls: 'ant-transfer',
|
||||
checked: checkStatus === 'all',
|
||||
checkPart: checkStatus === 'part',
|
||||
checkable: <span className={`ant-transfer-checkbox-inner`}></span>
|
||||
})}<span className={`${prefixCls}-header-selected`}><span>{(checkedKeys.length > 0 ? checkedKeys.length + '/' : '') + dataSource.length} 条</span>
|
||||
<span className={`${prefixCls}-header-title`}>{titleText}</span></span>
|
||||
</div>
|
||||
{ bodyDom ? bodyDom :
|
||||
<div className={ showSearch ? `${prefixCls}-body ${prefixCls}-body-with-search` : `${prefixCls}-body`}>
|
||||
{ showSearch ? <div className={`${prefixCls}-body-search-wrapper`}>
|
||||
<Search prefixCls={`${prefixCls}-search`} onChange={this.handleFilter.bind(this)} handleClear={this.handleClear.bind(this)} value={filter} />
|
||||
</div> : null }
|
||||
<Animate component="ul"
|
||||
transitionName={this.state.mounted ? `${prefixCls}-highlight` : ''}
|
||||
transitionLeave={false}>
|
||||
{dataSource.length > 0 ?
|
||||
dataSource.map((item) => {
|
||||
// apply filter
|
||||
const itemText = this.props.render(item);
|
||||
const filterResult = this.matchFilter(itemText, filter);
|
||||
|
||||
const renderedText = this.props.render(item);
|
||||
|
||||
if (filterResult) {
|
||||
return (
|
||||
<li onClick={this.handleSelect.bind(this, item)} key={item.key} title={renderedText}>
|
||||
<Checkbox checked={checkedKeys.some(key => key === item.key)} />
|
||||
{renderedText}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}) : <div className={`${prefixCls}-body-not-found`}>Not Found</div>
|
||||
}
|
||||
</Animate>
|
||||
</div>}
|
||||
{ footerDom ? <div className={`${prefixCls}-footer`}>
|
||||
{ footerDom }
|
||||
</div> : null }
|
||||
<Animate component="ul"
|
||||
transitionName={this.state.mounted ? `${prefixCls}-highlight` : ''}
|
||||
transitionLeave={false}>
|
||||
{dataSource.length > 0 ?
|
||||
dataSource.map((item) => {
|
||||
// apply filter
|
||||
const itemText = this.props.render(item);
|
||||
const filterResult = this.matchFilter(itemText, filter);
|
||||
|
||||
const renderedText = this.props.render(item);
|
||||
|
||||
if (filterResult) {
|
||||
return (
|
||||
<li onClick={this.handleSelect.bind(this, item)} key={item.key} title={renderedText}>
|
||||
<Checkbox checked={checkedKeys.some(key => key === item.key)} />
|
||||
{renderedText}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}) : <div className={`${prefixCls}-body-not-found`}>Not Found</div>
|
||||
}
|
||||
</Animate>
|
||||
</div>}
|
||||
{ footerDom ? <div className={`${prefixCls}-footer`}>
|
||||
{ footerDom }
|
||||
</div> : null }
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +136,7 @@ TransferList.defaultProps = {
|
||||
handleSelect: noop,
|
||||
handleSelectAll: noop,
|
||||
render: noop,
|
||||
//advanced
|
||||
// advanced
|
||||
body: noop,
|
||||
footer: noop,
|
||||
};
|
||||
|
@ -27,10 +27,12 @@ class TransferOperation extends Component {
|
||||
{<span>{rightArrowText}<Icon type="right" /></span>}
|
||||
</Button>
|
||||
);
|
||||
return <div className={className}>
|
||||
{moveToLeftButton}
|
||||
{moveToRightButton}
|
||||
</div>;
|
||||
return (
|
||||
<div className={className}>
|
||||
{moveToLeftButton}
|
||||
{moveToRightButton}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,16 +14,18 @@ class Search extends Component {
|
||||
|
||||
render() {
|
||||
const {placeholder, value, prefixCls} = this.props;
|
||||
return <div>
|
||||
<input placeholder={placeholder} className={ prefixCls + ' ant-input' } value={ value } ref="input"
|
||||
onChange={this.handleChange.bind(this)}/>
|
||||
{ value && value.length > 0 ?
|
||||
<a href="javascirpt:;" className={ prefixCls + '-action' } onClick={this.props.handleClear}>
|
||||
<Icon type="cross-circle" />
|
||||
</a>
|
||||
: <span className={ prefixCls + '-action' }><Icon type="search" /></span>
|
||||
}
|
||||
</div>;
|
||||
return (
|
||||
<div>
|
||||
<input placeholder={placeholder} className={ prefixCls + ' ant-input' } value={ value } ref="input"
|
||||
onChange={this.handleChange.bind(this)}/>
|
||||
{ value && value.length > 0 ?
|
||||
<a href="javascirpt:;" className={ prefixCls + '-action' } onClick={this.props.handleClear}>
|
||||
<Icon type="cross-circle" />
|
||||
</a>
|
||||
: <span className={ prefixCls + '-action' }><Icon type="search" /></span>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,11 @@ const AntTree = React.createClass({
|
||||
if (checkable) {
|
||||
checkable = <span className={`${props.prefixCls}-checkbox-inner`}></span>;
|
||||
}
|
||||
return <Tree {...props} checkable={checkable}>
|
||||
{this.props.children}
|
||||
</Tree>;
|
||||
return (
|
||||
<Tree {...props} checkable={checkable}>
|
||||
{this.props.children}
|
||||
</Tree>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3,9 +3,8 @@ export default function getFileItem(file, fileList) {
|
||||
let target = fileList.filter((item) => {
|
||||
if (matchWay === 'byName') {
|
||||
return item.name === file.name;
|
||||
} else {
|
||||
return item.uid === file.uid;
|
||||
}
|
||||
return item.uid === file.uid;
|
||||
})[0];
|
||||
return target;
|
||||
}
|
||||
|
@ -37,15 +37,16 @@ function genPercentAdd() {
|
||||
let k = 0.1;
|
||||
const i = 0.01;
|
||||
const end = 0.98;
|
||||
return function(start) {
|
||||
return function(s) {
|
||||
let start = s;
|
||||
if (start >= end) {
|
||||
return start;
|
||||
} else {
|
||||
start += k;
|
||||
k = k - i;
|
||||
if (k < 0.001) {
|
||||
k = 0.001;
|
||||
}
|
||||
}
|
||||
|
||||
start += k;
|
||||
k = k - i;
|
||||
if (k < 0.001) {
|
||||
k = 0.001;
|
||||
}
|
||||
return start * 100;
|
||||
};
|
||||
@ -65,9 +66,9 @@ const AntUpload = React.createClass({
|
||||
let nextFileList = this.state.fileList.concat();
|
||||
if (file.length > 0) {
|
||||
targetItem = file.map(function(f) {
|
||||
f = fileToObject(f);
|
||||
f.status = 'uploading';
|
||||
return f;
|
||||
const fileObject = fileToObject(f);
|
||||
fileObject.status = 'uploading';
|
||||
return fileObject;
|
||||
});
|
||||
nextFileList = nextFileList.concat(targetItem);
|
||||
} else {
|
||||
|
@ -60,9 +60,11 @@ export default React.createClass({
|
||||
target="_blank"><img src={file.thumbUrl || file.url} alt={file.name} /></a>;
|
||||
}
|
||||
if (file.status === 'uploading') {
|
||||
progress = <div className={prefixCls + '-list-item-progress'}>
|
||||
<Line {...this.props.progressAttr} percent={file.percent} />
|
||||
</div>;
|
||||
progress = (
|
||||
<div className={prefixCls + '-list-item-progress'}>
|
||||
<Line {...this.props.progressAttr} percent={file.percent} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const infoUploadingClass = classNames({
|
||||
[`${prefixCls}-list-item`]: true,
|
||||
@ -83,10 +85,12 @@ export default React.createClass({
|
||||
[`${prefixCls}-list`]: true,
|
||||
[`${prefixCls}-list-${this.props.listType}`]: true,
|
||||
});
|
||||
return <div className={listClassNames}>
|
||||
<Animate transitionName={prefixCls + '-margin-top'}>
|
||||
{list}
|
||||
</Animate>
|
||||
</div>;
|
||||
return (
|
||||
<div className={listClassNames}>
|
||||
<Animate transitionName={prefixCls + '-margin-top'}>
|
||||
{list}
|
||||
</Animate>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user