mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
194 lines
4.9 KiB
JavaScript
194 lines
4.9 KiB
JavaScript
const React = require('react');
|
|
const { connect } = require('react-redux');
|
|
const { themeStyle } = require('@joplin/lib/theme');
|
|
const { _ } = require('@joplin/lib/locale');
|
|
|
|
class NoteSearchBarComponent extends React.Component {
|
|
constructor() {
|
|
super();
|
|
|
|
this.searchInput_change = this.searchInput_change.bind(this);
|
|
this.searchInput_keyDown = this.searchInput_keyDown.bind(this);
|
|
this.previousButton_click = this.previousButton_click.bind(this);
|
|
this.nextButton_click = this.nextButton_click.bind(this);
|
|
this.closeButton_click = this.closeButton_click.bind(this);
|
|
|
|
this.backgroundColor = undefined;
|
|
}
|
|
|
|
style() {
|
|
const theme = themeStyle(this.props.themeId);
|
|
|
|
const style = {
|
|
root: Object.assign({}, theme.textStyle, {
|
|
backgroundColor: theme.backgroundColor,
|
|
color: theme.colorFaded,
|
|
}),
|
|
};
|
|
|
|
return style;
|
|
}
|
|
|
|
buttonIconComponent(iconName, clickHandler, isEnabled) {
|
|
const theme = themeStyle(this.props.themeId);
|
|
|
|
const searchButton = {
|
|
paddingLeft: 4,
|
|
paddingRight: 4,
|
|
paddingTop: 2,
|
|
paddingBottom: 2,
|
|
textDecoration: 'none',
|
|
marginRight: 5,
|
|
};
|
|
|
|
const iconStyle = {
|
|
display: 'flex',
|
|
fontSize: Math.round(theme.fontSize) * 1.2,
|
|
color: theme.color,
|
|
opacity: isEnabled ? 1.0 : theme.disabledOpacity,
|
|
};
|
|
|
|
const icon = <i style={iconStyle} className={`fas ${iconName}`}></i>;
|
|
|
|
return (
|
|
<a href="#" style={searchButton} onClick={clickHandler}>
|
|
{icon}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
searchInput_change(event) {
|
|
const query = event.currentTarget.value;
|
|
this.triggerOnChange(query);
|
|
}
|
|
|
|
searchInput_keyDown(event) {
|
|
if (event.keyCode === 13) {
|
|
// ENTER
|
|
event.preventDefault();
|
|
|
|
if (!event.shiftKey) {
|
|
if (this.props.onNext) this.props.onNext();
|
|
} else {
|
|
if (this.props.onPrevious) this.props.onPrevious();
|
|
}
|
|
}
|
|
|
|
if (event.keyCode === 27) {
|
|
// ESCAPE
|
|
event.preventDefault();
|
|
|
|
if (this.props.onClose) this.props.onClose();
|
|
}
|
|
|
|
if (event.keyCode === 70) {
|
|
// F key
|
|
if (event.ctrlKey) {
|
|
event.target.select();
|
|
}
|
|
}
|
|
}
|
|
|
|
previousButton_click() {
|
|
if (this.props.onPrevious) this.props.onPrevious();
|
|
}
|
|
|
|
nextButton_click() {
|
|
if (this.props.onNext) this.props.onNext();
|
|
}
|
|
|
|
closeButton_click() {
|
|
if (this.props.onClose) this.props.onClose();
|
|
}
|
|
|
|
triggerOnChange(query) {
|
|
if (this.props.onChange) this.props.onChange(query);
|
|
}
|
|
|
|
focus() {
|
|
this.refs.searchInput.focus();
|
|
this.refs.searchInput.select();
|
|
}
|
|
|
|
render() {
|
|
const query = this.props.query ? this.props.query : '';
|
|
|
|
// backgroundColor needs to cached to a local variable to prevent the
|
|
// colour from blinking.
|
|
// For more info: https://github.com/laurent22/joplin/pull/2329#issuecomment-578376835
|
|
const theme = themeStyle(this.props.themeId);
|
|
if (!this.props.searching) {
|
|
if (this.props.resultCount === 0 && query.length > 0) {
|
|
this.backgroundColor = theme.warningBackgroundColor;
|
|
} else {
|
|
this.backgroundColor = theme.backgroundColor;
|
|
}
|
|
}
|
|
if (this.backgroundColor === undefined) {
|
|
this.backgroundColor = theme.backgroundColor;
|
|
}
|
|
const buttonEnabled = (this.backgroundColor === theme.backgroundColor);
|
|
|
|
const closeButton = this.buttonIconComponent('fa-times', this.closeButton_click, true);
|
|
const previousButton = this.buttonIconComponent('fa-chevron-up', this.previousButton_click, buttonEnabled);
|
|
const nextButton = this.buttonIconComponent('fa-chevron-down', this.nextButton_click, buttonEnabled);
|
|
|
|
const textStyle = Object.assign({
|
|
fontSize: theme.fontSize,
|
|
fontFamily: theme.fontFamily,
|
|
color: theme.colorFaded,
|
|
backgroundColor: theme.backgroundColor,
|
|
});
|
|
|
|
const matchesFoundString = (query.length > 0) ? (
|
|
<div style={textStyle}>
|
|
{`${this.props.resultCount === 0 ? 0 : this.props.selectedIndex + 1} / ${this.props.resultCount}`}
|
|
</div>
|
|
) : null;
|
|
|
|
const allowScrolling = this.props.visiblePanes.indexOf('editor') >= 0;
|
|
|
|
const viewerWarning = (
|
|
<div style={textStyle}>
|
|
{'Jumping between matches is not available in the viewer, please toggle the editor'}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="note-search-bar" style={this.props.style}>
|
|
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
|
{closeButton}
|
|
<input
|
|
placeholder={_('Search...')}
|
|
value={query}
|
|
onChange={this.searchInput_change}
|
|
onKeyDown={this.searchInput_keyDown}
|
|
ref="searchInput"
|
|
type="text"
|
|
style={{ width: 200, marginRight: 5, backgroundColor: this.backgroundColor, color: theme.color }}
|
|
/>
|
|
{allowScrolling ? previousButton : null}
|
|
{allowScrolling ? nextButton : null}
|
|
{allowScrolling ? matchesFoundString : null}
|
|
{!allowScrolling ? viewerWarning : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
const mapStateToProps = state => {
|
|
return {
|
|
themeId: state.settings.theme,
|
|
};
|
|
};
|
|
|
|
const NoteSearchBar = connect(
|
|
mapStateToProps,
|
|
null,
|
|
null,
|
|
{ withRef: true }
|
|
)(NoteSearchBarComponent);
|
|
|
|
module.exports = NoteSearchBar;
|