Dropdown click outside better handlers
This commit is contained in:
@ -9,6 +9,13 @@ export default class DropdownField extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
// Create a "unique" id. This is human-controlled to avoid requiring
|
||||
// other libraries for a very simple purpose: clicking outside
|
||||
this.uid = this.props.name.replace(' ','_').toLowerCase();
|
||||
if (this.props.uid){
|
||||
this.uid += "_"+this.props.uid;
|
||||
}
|
||||
|
||||
this.state = {
|
||||
expanded: false
|
||||
}
|
||||
@ -24,34 +31,33 @@ export default class DropdownField extends React.Component{
|
||||
window.removeEventListener("click", this.handleClick, false);
|
||||
}
|
||||
|
||||
setExpanded(expanded = !this.state.expanded){
|
||||
if (expanded){
|
||||
this.setState({expanded: expanded});
|
||||
window.addEventListener("click", this.handleClick, false);
|
||||
} else {
|
||||
this.setState({expanded: expanded});
|
||||
window.removeEventListener("click", this.handleClick, false);
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
// TODO: remove dependency on jQuery and explore the performance of this functionality
|
||||
if ($(e.target).closest('.dropdown-field').data('key') != this.props.name.replace(' ','_').toLowerCase() && this.state.expanded){
|
||||
this.setState({
|
||||
expanded: false
|
||||
});
|
||||
if ($(e.target).closest('.dropdown-field').attr('data-uid') != this.uid && this.state.expanded){
|
||||
this.setExpanded(false);
|
||||
}
|
||||
}
|
||||
|
||||
handleChange(value, is_selected){
|
||||
|
||||
var current_value = this.props.value;
|
||||
if (this.isMultiSelect()){
|
||||
if (value == 'select-all'){
|
||||
var new_value = [];
|
||||
for (var i = 0; i < this.props.options.length; i++){
|
||||
new_value.push(this.props.options[i].value);
|
||||
}
|
||||
return this.props.handleChange(new_value);
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
expanded: !this.state.expanded
|
||||
});
|
||||
}
|
||||
|
||||
var current_value = this.props.value;
|
||||
if (this.isMultiSelect()){
|
||||
if (is_selected){
|
||||
} else if (is_selected){
|
||||
var index = current_value.indexOf(value);
|
||||
current_value.splice(index, 1);
|
||||
var new_value = current_value;
|
||||
@ -61,17 +67,14 @@ export default class DropdownField extends React.Component{
|
||||
}
|
||||
} else {
|
||||
var new_value = value;
|
||||
|
||||
// Collapse our menu
|
||||
this.setExpanded(false);
|
||||
}
|
||||
|
||||
return this.props.handleChange(new_value);
|
||||
}
|
||||
|
||||
handleToggle(){
|
||||
this.setState({
|
||||
expanded: !this.state.expanded
|
||||
});
|
||||
}
|
||||
|
||||
isMultiSelect(){
|
||||
return this.props.value instanceof Array;
|
||||
}
|
||||
@ -119,8 +122,8 @@ export default class DropdownField extends React.Component{
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className} data-key={this.props.name.replace(' ','_').toLowerCase()}>
|
||||
<div className={"label"+(this.props.button ? " button "+this.props.button : "")} onClick={e => this.handleToggle()}>
|
||||
<div className={className} data-uid={this.uid}>
|
||||
<div className={"label"+(this.props.button ? " button "+this.props.button : "")} onClick={e => this.setExpanded()}>
|
||||
{this.props.icon ? <span><FontAwesome name={this.props.icon} /> </span> : null}
|
||||
<span className="text">
|
||||
{this.props.name}
|
||||
@ -128,21 +131,23 @@ export default class DropdownField extends React.Component{
|
||||
</span>
|
||||
</div>
|
||||
<div className="options">
|
||||
{
|
||||
options.map(option => {
|
||||
if (this.isMultiSelect()){
|
||||
var is_selected = current_value.indexOf(option.value) > -1;
|
||||
} else {
|
||||
var is_selected = current_value == option.value;
|
||||
}
|
||||
return (
|
||||
<div className={"option "+(option.className ? option.className : '')} key={option.value} onClick={e => this.handleChange(option.value, is_selected)}>
|
||||
{!this.props.no_status_icon && is_selected ? selected_icon : null}
|
||||
{option.label}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
<div className="liner">
|
||||
{
|
||||
options.map(option => {
|
||||
if (this.isMultiSelect()){
|
||||
var is_selected = current_value.indexOf(option.value) > -1;
|
||||
} else {
|
||||
var is_selected = current_value == option.value;
|
||||
}
|
||||
return (
|
||||
<div className={"option "+(option.className ? option.className : '')} key={option.value} onClick={e => this.handleChange(option.value, is_selected)}>
|
||||
{!this.props.no_status_icon && is_selected ? selected_icon : null}
|
||||
{option.label}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -55,12 +55,12 @@ class SearchForm extends React.Component{
|
||||
break
|
||||
|
||||
default:
|
||||
var available_views = ["artist","album","playlist","track"];
|
||||
var available_views = ["all:","artist:","album:","playlist:",":track"];
|
||||
var view_defined = false;
|
||||
var query = this.state.query;
|
||||
|
||||
for (var i = 0; i < available_views.length; i++){
|
||||
if (query.startsWith(available_views[i]+':')){
|
||||
if (query.startsWith(available_views[i])){
|
||||
view_defined = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +73,8 @@ class Snapcast extends React.Component{
|
||||
// the existing group and middleware handles the behavior shift)
|
||||
groups_dropdown.push({
|
||||
label: 'New group',
|
||||
value: group.id
|
||||
value: group.id,
|
||||
className: 'grey-text'
|
||||
});
|
||||
|
||||
return (
|
||||
@ -87,6 +88,7 @@ class Snapcast extends React.Component{
|
||||
no_status_icon
|
||||
value={group.id}
|
||||
options={groups_dropdown}
|
||||
uid={group.id+"_"+client.id}
|
||||
handleChange={value => {this.props.pusherActions.setSnapcastClientGroup(client.id, value); this.props.uiActions.hideContextMenu()}}
|
||||
/>
|
||||
<TextField
|
||||
|
||||
Reference in New Issue
Block a user