Removing sorting of search uris in favor of source selection dropdown

This commit is contained in:
James Barnsley
2018-05-04 09:08:01 +12:00
parent 2cfb7afed5
commit 75099b732b
10 changed files with 192 additions and 111 deletions

View File

@ -718,12 +718,8 @@ var getFromUri = exports.getFromUri = function getFromUri(element) {
case 'searchcontext': case 'searchcontext':
if (exploded[0] == "search") { if (exploded[0] == "search") {
var available_views = ["all", "artist", "album", "playlist", "track"];
var view = available_views.indexOf(exploded[1]);
if (view > -1) {
return exploded[1]; return exploded[1];
} }
}
break; break;
case 'searchterm': case 'searchterm':
@ -20944,6 +20940,7 @@ var DropdownField = function (_React$Component) {
_this.state = { _this.state = {
expanded: false expanded: false
}; };
_this.handleClick = _this.handleClick.bind(_this); _this.handleClick = _this.handleClick.bind(_this);
return _this; return _this;
} }
@ -20963,19 +20960,40 @@ var DropdownField = function (_React$Component) {
value: function handleClick(e) { value: function handleClick(e) {
// TODO: remove dependency on jQuery and explore the performance of this functionality // 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) { if ($(e.target).closest('.dropdown-field').data('key') != this.props.name.replace(' ', '_').toLowerCase() && this.state.expanded) {
this.setState({ expanded: false }); this.setState({
expanded: false
});
} }
} }
}, { }, {
key: 'handleChange', key: 'handleChange',
value: function handleChange(value) { value: function handleChange(value, is_selected) {
this.setState({ expanded: !this.state.expanded }); this.setState({
return this.props.handleChange(value); expanded: !this.state.expanded
});
var current_value = this.props.value;
if (current_value instanceof Array) {
if (is_selected) {
var index = current_value.indexOf(value);
current_value.splice(index, 1);
var new_value = current_value;
} else {
current_value.push(value);
var new_value = current_value;
}
} else {
var new_value = value;
}
return this.props.handleChange(new_value);
} }
}, { }, {
key: 'handleToggle', key: 'handleToggle',
value: function handleToggle() { value: function handleToggle() {
this.setState({ expanded: !this.state.expanded }); this.setState({
expanded: !this.state.expanded
});
} }
}, { }, {
key: 'render', key: 'render',
@ -21002,9 +21020,11 @@ var DropdownField = function (_React$Component) {
if (this.props.className) { if (this.props.className) {
className += ' ' + this.props.className; className += ' ' + this.props.className;
} }
var current_value = this.props.options[0].value; var current_value = null;
if (this.props.value) { if (this.props.value) {
current_value = this.props.value; current_value = this.props.value;
} else if (this.props.options.length > 0) {
current_value = this.props.options[0].value;
} }
var icon = _react2.default.createElement(_reactFontawesome2.default, { name: 'check' }); var icon = _react2.default.createElement(_reactFontawesome2.default, { name: 'check' });
@ -21040,12 +21060,17 @@ var DropdownField = function (_React$Component) {
'div', 'div',
{ className: 'options' }, { className: 'options' },
this.props.options.map(function (option) { this.props.options.map(function (option) {
if (current_value instanceof Array) {
var is_selected = current_value.indexOf(option.value) > -1;
} else {
var is_selected = current_value == option.value;
}
return _react2.default.createElement( return _react2.default.createElement(
'div', 'div',
{ className: 'option', key: option.value, onClick: function onClick(e) { { className: 'option', key: option.value, onClick: function onClick(e) {
return _this2.handleChange(option.value); return _this2.handleChange(option.value, is_selected);
} }, } },
!_this2.props.no_status_icon && option.value == current_value ? icon : null, !_this2.props.no_status_icon && is_selected ? icon : null,
option.label option.label
); );
}) })
@ -70283,11 +70308,19 @@ var Search = function (_React$Component) {
}, { }, {
value: 'duration', value: 'duration',
label: 'Duration' label: 'Duration'
}, {
value: 'uri',
label: 'Source'
}]; }];
var provider_options = [{
value: 'all',
label: 'All'
}];
for (var i = 0; i < this.props.uri_schemes.length; i++) {
provider_options.push({
value: this.props.uri_schemes[i],
label: helpers.titleCase(this.props.uri_schemes[i].replace(':', '').replace('+', ' '))
});
}
var options = _react2.default.createElement( var options = _react2.default.createElement(
'span', 'span',
null, null,
@ -70297,17 +70330,20 @@ var Search = function (_React$Component) {
value: this.props.sort, value: this.props.sort,
options: sort_options, options: sort_options,
reverse: this.props.sort_reverse, reverse: this.props.sort_reverse,
handleChange: function handleChange(val) { handleChange: function handleChange(value) {
_this3.setSort(val);_this3.props.uiActions.hideContextMenu(); _this3.setSort(value);_this3.props.uiActions.hideContextMenu();
} }), }
_react2.default.createElement( }),
'button', _react2.default.createElement(_DropdownField2.default, {
{ className: 'no-hover', onClick: function onClick(e) { icon: 'database',
return _this3.props.uiActions.openModal('search_uri_schemes', { query: _this3.props.params.query }); name: 'Source',
} }, value: this.props.search_uri_schemes,
_react2.default.createElement(_reactFontawesome2.default, { name: 'wrench' }), options: provider_options,
'\xA0 Sources' reverse: this.props.sort_reverse,
) handleChange: function handleChange(value) {
_this3.props.uiActions.set({ search_uri_schemes: value });_this3.props.uiActions.hideContextMenu();
}
})
); );
return _react2.default.createElement( return _react2.default.createElement(
@ -70320,7 +70356,8 @@ var Search = function (_React$Component) {
}), }),
_react2.default.createElement(_SearchForm2.default, { _react2.default.createElement(_SearchForm2.default, {
query: this.props.params.query ? this.props.params.query : '', query: this.props.params.query ? this.props.params.query : '',
view: this.props.params.view ? this.props.params.view : 'all' }), view: this.props.params.view ? this.props.params.view : 'all'
}),
_react2.default.createElement( _react2.default.createElement(
'div', 'div',
{ className: 'content-wrapper' }, { className: 'content-wrapper' },
@ -70341,6 +70378,7 @@ var mapStateToProps = function mapStateToProps(state, ownProps) {
playlists: state.core.playlists ? state.core.playlists : [], playlists: state.core.playlists ? state.core.playlists : [],
tracks: state.core.tracks ? state.core.tracks : [], tracks: state.core.tracks ? state.core.tracks : [],
search_uri_schemes: state.ui.search_uri_schemes ? state.ui.search_uri_schemes : [], search_uri_schemes: state.ui.search_uri_schemes ? state.ui.search_uri_schemes : [],
uri_schemes: state.mopidy.uri_schemes ? state.mopidy.uri_schemes : [],
mopidy_search_results: state.mopidy.search_results ? state.mopidy.search_results : {}, mopidy_search_results: state.mopidy.search_results ? state.mopidy.search_results : {},
spotify_search_results: state.spotify.search_results ? state.spotify.search_results : {}, spotify_search_results: state.spotify.search_results ? state.spotify.search_results : {},
sort: state.ui.search_results_sort ? state.ui.search_results_sort : 'name', sort: state.ui.search_results_sort ? state.ui.search_results_sort : 'name',
@ -70455,6 +70493,10 @@ var SearchForm = function (_React$Component) {
_reactRouter.hashHistory.push(global.baseURL + 'playlist/' + encodeURIComponent(this.state.query)); _reactRouter.hashHistory.push(global.baseURL + 'playlist/' + encodeURIComponent(this.state.query));
break; break;
case 'track':
_reactRouter.hashHistory.push(global.baseURL + 'track/' + encodeURIComponent(this.state.query));
break;
default: default:
var available_views = ["artist", "album", "playlist", "track"]; var available_views = ["artist", "album", "playlist", "track"];
var view_defined = false; var view_defined = false;
@ -77665,15 +77707,34 @@ var LibraryAlbums = function (_React$Component) {
_react2.default.createElement(_FilterField2.default, { handleChange: function handleChange(value) { _react2.default.createElement(_FilterField2.default, { handleChange: function handleChange(value) {
return _this3.setState({ filter: value, limit: _this3.state.per_page }); return _this3.setState({ filter: value, limit: _this3.state.per_page });
} }), } }),
_react2.default.createElement(_DropdownField2.default, { icon: 'sort', name: 'Sort', value: this.props.sort, options: sort_options, reverse: this.props.sort_reverse, handleChange: function handleChange(val) { _react2.default.createElement(_DropdownField2.default, {
icon: 'sort',
name: 'Sort',
value: this.props.sort,
options: sort_options,
reverse: this.props.sort_reverse,
handleChange: function handleChange(val) {
_this3.setSort(val);_this3.props.uiActions.hideContextMenu(); _this3.setSort(val);_this3.props.uiActions.hideContextMenu();
} }), }
_react2.default.createElement(_DropdownField2.default, { icon: 'eye', name: 'View', value: this.props.view, options: view_options, handleChange: function handleChange(val) { }),
_react2.default.createElement(_DropdownField2.default, {
icon: 'eye',
name: 'View',
value: this.props.view,
options: view_options,
handleChange: function handleChange(val) {
_this3.props.uiActions.set({ library_albums_view: val });_this3.props.uiActions.hideContextMenu(); _this3.props.uiActions.set({ library_albums_view: val });_this3.props.uiActions.hideContextMenu();
} }), }
_react2.default.createElement(_DropdownField2.default, { icon: 'database', name: 'Source', value: this.props.source, options: source_options, handleChange: function handleChange(val) { }),
_react2.default.createElement(_DropdownField2.default, {
icon: 'database',
name: 'Source',
value: this.props.source,
options: source_options,
handleChange: function handleChange(val) {
_this3.props.uiActions.set({ library_albums_source: val });_this3.props.uiActions.hideContextMenu(); _this3.props.uiActions.set({ library_albums_source: val });_this3.props.uiActions.hideContextMenu();
} }) }
})
); );
return _react2.default.createElement( return _react2.default.createElement(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -77,7 +77,7 @@
// Release details // Release details
// These are automatically injected to built HTML // These are automatically injected to built HTML
var build = "1525309512"; var build = "1525381100";
var version = "3.18.0"; var version = "3.18.0";
// Construct the script tag // Construct the script tag

View File

@ -12,31 +12,53 @@ export default class DropdownField extends React.Component{
this.state = { this.state = {
expanded: false expanded: false
} }
this.handleClick = this.handleClick.bind(this)
this.handleClick = this.handleClick.bind(this);
} }
componentDidMount(){ componentDidMount(){
window.addEventListener("click", this.handleClick, false) window.addEventListener("click", this.handleClick, false);
} }
componentWillUnmount(){ componentWillUnmount(){
window.removeEventListener("click", this.handleClick, false) window.removeEventListener("click", this.handleClick, false);
} }
handleClick(e){ handleClick(e){
// TODO: remove dependency on jQuery and explore the performance of this functionality // 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){ if ($(e.target).closest('.dropdown-field').data('key') != this.props.name.replace(' ','_').toLowerCase() && this.state.expanded){
this.setState({ expanded: false }) this.setState({
expanded: false
});
} }
} }
handleChange(value){ handleChange(value, is_selected){
this.setState({ expanded: !this.state.expanded }) this.setState({
return this.props.handleChange(value ) expanded: !this.state.expanded
});
var current_value = this.props.value;
if (current_value instanceof Array){
if (is_selected){
var index = current_value.indexOf(value);
current_value.splice(index, 1);
var new_value = current_value;
} else {
current_value.push(value);
var new_value = current_value;
}
} else {
var new_value = value;
}
return this.props.handleChange(new_value);
} }
handleToggle(){ handleToggle(){
this.setState({ expanded: !this.state.expanded }) this.setState({
expanded: !this.state.expanded
});
} }
render(){ render(){
@ -60,9 +82,11 @@ export default class DropdownField extends React.Component{
if (this.props.className){ if (this.props.className){
className += ' '+this.props.className; className += ' '+this.props.className;
} }
var current_value = this.props.options[0].value var current_value = null;
if (this.props.value){ if (this.props.value){
current_value = this.props.value; current_value = this.props.value;
} else if (this.props.options.length > 0){
current_value = this.props.options[0].value;
} }
var icon = <FontAwesome name="check" /> var icon = <FontAwesome name="check" />
@ -83,9 +107,14 @@ export default class DropdownField extends React.Component{
<div className="options"> <div className="options">
{ {
this.props.options.map(option => { this.props.options.map(option => {
if (current_value instanceof Array){
var is_selected = current_value.indexOf(option.value) > -1;
} else {
var is_selected = current_value == option.value;
}
return ( return (
<div className="option" key={ option.value } onClick={ e => this.handleChange(option.value) }> <div className="option" key={option.value} onClick={e => this.handleChange(option.value, is_selected)}>
{!this.props.no_status_icon && (option.value == current_value) ? icon : null} {!this.props.no_status_icon && is_selected ? icon : null}
{option.label} {option.label}
</div> </div>
) )

View File

@ -50,6 +50,10 @@ class SearchForm extends React.Component{
hashHistory.push(global.baseURL+'playlist/'+encodeURIComponent(this.state.query)) hashHistory.push(global.baseURL+'playlist/'+encodeURIComponent(this.state.query))
break break
case 'track':
hashHistory.push(global.baseURL+'track/'+encodeURIComponent(this.state.query))
break
default: default:
var available_views = ["artist","album","playlist","track"]; var available_views = ["artist","album","playlist","track"];
var view_defined = false; var view_defined = false;

View File

@ -451,12 +451,8 @@ export let getFromUri = function(element, uri = ""){
case 'searchcontext': case 'searchcontext':
if (exploded[0] == "search"){ if (exploded[0] == "search"){
var available_views = ["all","artist","album","playlist","track"];
var view = available_views.indexOf(exploded[1]);
if (view > -1){
return exploded[1]; return exploded[1];
} }
}
break break
case 'searchterm': case 'searchterm':

View File

@ -319,13 +319,20 @@ class Search extends React.Component{
{ {
value: 'duration', value: 'duration',
label: 'Duration' label: 'Duration'
},
{
value: 'uri',
label: 'Source'
} }
]; ];
var provider_options = [{
value: 'all',
label: 'All'
}];
for (var i = 0; i < this.props.uri_schemes.length; i++){
provider_options.push({
value: this.props.uri_schemes[i],
label: helpers.titleCase(this.props.uri_schemes[i].replace(':','').replace('+',' '))
});
}
var options = ( var options = (
<span> <span>
<DropdownField <DropdownField
@ -334,13 +341,16 @@ class Search extends React.Component{
value={this.props.sort} value={this.props.sort}
options={sort_options} options={sort_options}
reverse={this.props.sort_reverse} reverse={this.props.sort_reverse}
handleChange={val => {this.setSort(val); this.props.uiActions.hideContextMenu() }} /> handleChange={value => {this.setSort(value); this.props.uiActions.hideContextMenu()}}
/>
<button className="no-hover" onClick={e => this.props.uiActions.openModal('search_uri_schemes', {query: this.props.params.query})}> <DropdownField
<FontAwesome name="wrench" />&nbsp; icon="database"
Sources name="Source"
</button> value={this.props.search_uri_schemes}
options={provider_options}
reverse={this.props.sort_reverse}
handleChange={value => {this.props.uiActions.set({search_uri_schemes: value}); this.props.uiActions.hideContextMenu()}}
/>
</span> </span>
) )
@ -354,7 +364,8 @@ class Search extends React.Component{
<SearchForm <SearchForm
query={(this.props.params.query ? this.props.params.query : '')} query={(this.props.params.query ? this.props.params.query : '')}
view={(this.props.params.view ? this.props.params.view : 'all')} /> view={(this.props.params.view ? this.props.params.view : 'all')}
/>
<div className="content-wrapper"> <div className="content-wrapper">
{ this.renderResults() } { this.renderResults() }
@ -372,6 +383,7 @@ const mapStateToProps = (state, ownProps) => {
playlists: (state.core.playlists ? state.core.playlists : []), playlists: (state.core.playlists ? state.core.playlists : []),
tracks: (state.core.tracks ? state.core.tracks : []), tracks: (state.core.tracks ? state.core.tracks : []),
search_uri_schemes: (state.ui.search_uri_schemes ? state.ui.search_uri_schemes : []), search_uri_schemes: (state.ui.search_uri_schemes ? state.ui.search_uri_schemes : []),
uri_schemes: (state.mopidy.uri_schemes ? state.mopidy.uri_schemes : []),
mopidy_search_results: (state.mopidy.search_results ? state.mopidy.search_results : {}), mopidy_search_results: (state.mopidy.search_results ? state.mopidy.search_results : {}),
spotify_search_results: (state.spotify.search_results ? state.spotify.search_results : {}), spotify_search_results: (state.spotify.search_results ? state.spotify.search_results : {}),
sort: (state.ui.search_results_sort ? state.ui.search_results_sort : 'name'), sort: (state.ui.search_results_sort ? state.ui.search_results_sort : 'name'),

View File

@ -249,9 +249,28 @@ class LibraryAlbums extends React.Component{
var options = ( var options = (
<span> <span>
<FilterField handleChange={value => this.setState({filter: value, limit: this.state.per_page})} /> <FilterField handleChange={value => this.setState({filter: value, limit: this.state.per_page})} />
<DropdownField icon="sort" name="Sort" value={this.props.sort} options={sort_options} reverse={this.props.sort_reverse} handleChange={val => {this.setSort(val); this.props.uiActions.hideContextMenu() }} /> <DropdownField
<DropdownField icon="eye" name="View" value={this.props.view} options={view_options} handleChange={val => {this.props.uiActions.set({ library_albums_view: val }); this.props.uiActions.hideContextMenu() }} /> icon="sort"
<DropdownField icon="database" name="Source" value={this.props.source} options={source_options} handleChange={val => {this.props.uiActions.set({ library_albums_source: val}); this.props.uiActions.hideContextMenu() }} /> name="Sort"
value={this.props.sort}
options={sort_options}
reverse={this.props.sort_reverse}
handleChange={val => {this.setSort(val); this.props.uiActions.hideContextMenu() }}
/>
<DropdownField
icon="eye"
name="View"
value={this.props.view}
options={view_options}
handleChange={val => {this.props.uiActions.set({ library_albums_view: val }); this.props.uiActions.hideContextMenu() }}
/>
<DropdownField
icon="database"
name="Source"
value={this.props.source}
options={source_options}
handleChange={val => {this.props.uiActions.set({ library_albums_source: val}); this.props.uiActions.hideContextMenu() }}
/>
</span> </span>
) )