mirror of
https://github.com/SuperBFG7/ympd
synced 2025-04-13 06:13:15 +00:00
Feat: interface for advanced search
This commit is contained in:
parent
63039b15ec
commit
9c0d84d2ad
@ -321,3 +321,7 @@ div.key {
|
||||
heigth: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ol#searchCrumb {
|
||||
padding: .5rem;
|
||||
}
|
@ -142,7 +142,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="searchqueue">
|
||||
<form id="searchqueue" class="flex-grow-1">
|
||||
<div class="input-group mr-2">
|
||||
<input type="text" class="form-control" placeholder="Search Queue" id="searchqueuestr"/>
|
||||
<div class="input-group-append">
|
||||
@ -164,9 +164,9 @@
|
||||
</div>
|
||||
<button data-href='{"cmd": "gotoPage", "options": ["next"]}' id="QueueCurrentPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2 featTags">
|
||||
<div class="btn-group featTags">
|
||||
<button id="QueueCurrentColsBtn" class="btn btn-secondary dropdown-toggle material-icons" type="button" data-toggle="dropdown">settings</button>
|
||||
<div class="dropdown-menu bg-dark px-2" id="QueueCurrentColsDropdown"><form></form>
|
||||
<div class="dropdown-menu bg-dark px-2 dropdown-menu-right" id="QueueCurrentColsDropdown"><form></form>
|
||||
<button data-href='{"cmd": "saveCols", "options": ["QueueCurrent"]}' class="btn btn-success btn-block btn-sm mt-2">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -517,17 +517,26 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="btn-toolbar card-toolbar" id="SearchButtons">
|
||||
<form id="search">
|
||||
<form id="search" class="flex-grow-1">
|
||||
<div class="input-group mr-2">
|
||||
<input type="text" class="form-control" placeholder="Search" id="searchstr"/>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-prepend">
|
||||
<button title="Select tags to search" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
|
||||
<span class="material-icons">search</span>
|
||||
<span id="searchtagsdesc">Any Tag</span>
|
||||
</button>
|
||||
<div class="dropdown-menu bg-dark dropdown-menu-right px-2" id="searchtags">
|
||||
<div class="dropdown-menu bg-dark px-2" id="searchtags">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group-prepend featAdvsearch">
|
||||
<select class="form-control" id="searchMatch">
|
||||
<option value="contains">contains</option>
|
||||
<option value="==">==</option>
|
||||
<option value="=~">=~</option>
|
||||
<option value="!=">!=</option>
|
||||
<option value="!~">!~</option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="text" class="form-control" placeholder="Search" id="searchstr"/>
|
||||
</div>
|
||||
</form>
|
||||
<div class="input-group mr-2">
|
||||
@ -550,15 +559,17 @@
|
||||
</div>
|
||||
<button data-href='{"cmd": "gotoPage", "options": ["next"]}' id="SearchPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2 featTags">
|
||||
<div class="btn-group featTags">
|
||||
<button id="SearchColsBtn" class="btn btn-secondary dropdown-toggle material-icons" type="button" data-toggle="dropdown">settings</button>
|
||||
<div class="dropdown-menu bg-dark px-2" id="SearchColsDropdown"><form></form>
|
||||
<div class="dropdown-menu bg-dark px-2 dropdown-menu-right" id="SearchColsDropdown"><form></form>
|
||||
<button data-href='{"cmd": "saveCols", "options": ["Search"]}' class="btn btn-success btn-block btn-sm mt-2">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ol class="FeatAdvsearch breadcrumb" id="searchCrumb"></ol>
|
||||
|
||||
<div class="table-responsive-md">
|
||||
<table id="SearchList" class="table table-hover table-sm">
|
||||
<table id="SearchList" class="table table-hover table-sm" data-sort="">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
@ -276,8 +276,30 @@ function appRoute() {
|
||||
else if (app.current.app == 'Search') {
|
||||
var searchstrEl = document.getElementById('searchstr');
|
||||
searchstrEl.focus();
|
||||
if (searchstrEl.value == '' && app.current.search != '')
|
||||
searchstrEl.value = app.current.search;
|
||||
if (settings.featAdvsearch) {
|
||||
var crumbs = '';
|
||||
var elements = app.current.search.substring(1, app.current.search.length - 1).split(' AND ');
|
||||
for (var i = 0; i < elements.length - 1 ; i++) {
|
||||
var value = elements[i].substring(1, elements[i].length - 1);
|
||||
crumbs += '<button data-filter="' + encodeURI(value) + '" class="btn btn-light mr-2">' + value + '<span class="ml-2 badge badge-secondary">×</span></button>';
|
||||
}
|
||||
document.getElementById('searchCrumb').innerHTML = crumbs;
|
||||
if (searchstrEl.value == '' && elements.length >= 1) {
|
||||
var lastEl = elements[elements.length - 1].substring(1, elements[elements.length - 1].length - 1);
|
||||
var lastElValue = lastEl.substring(lastEl.indexOf('\'') + 1, lastEl.length - 1);
|
||||
if (searchstrEl.value != lastElValue)
|
||||
document.getElementById('searchCrumb').innerHTML += '<button data-filter="' + encodeURI(lastEl) +'" class="btn btn-light mr-2">' + lastEl + '<span href="#" class="ml-2 badge badge-secondary">×</span></button>';
|
||||
var match = lastEl.substring(lastEl.indexOf(' ') + 1);
|
||||
match = match.substring(0, match.indexOf(' '));
|
||||
if (match == '')
|
||||
match = 'contains';
|
||||
document.getElementById('searchMatch').value = match;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (searchstrEl.value == '' && app.current.search != '')
|
||||
searchstrEl.value = app.current.search;
|
||||
}
|
||||
if (app.last.app != app.current.app) {
|
||||
if (app.current.search != '') {
|
||||
var colspan = settings['cols' + app.current.app].length;
|
||||
@ -289,12 +311,33 @@ function appRoute() {
|
||||
}
|
||||
|
||||
if (app.current.search.length >= 2) {
|
||||
sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": { "plist": "", "offset": app.current.page, "filter": app.current.filter, "searchstr": app.current.search}}, parseSearch);
|
||||
if (settings.featAdvsearch) {
|
||||
var sort = document.getElementById('SearchList').getAttribute('data-sort');
|
||||
var sortdesc = false;
|
||||
if (sort == '') {
|
||||
if (settings.tags.includes('Title'))
|
||||
sort = 'Title';
|
||||
else
|
||||
sort = 'Filename';
|
||||
document.getElementById('SearchList').setAttribute('data-sort', sort);
|
||||
}
|
||||
else {
|
||||
if (sort.indexOf('-') == 0) {
|
||||
sortdesc = true;
|
||||
sort = sort.substring(1);
|
||||
}
|
||||
}
|
||||
sendAPI({"cmd": "MPD_API_DATABASE_SEARCH_ADV", "data": { "plist": "", "offset": app.current.page, "sort": sort, "sortdesc": sortdesc, "expression": app.current.search}}, parseSearch);
|
||||
}
|
||||
else {
|
||||
sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": { "plist": "", "offset": app.current.page, "filter": app.current.filter, "searchstr": app.current.search}}, parseSearch);
|
||||
}
|
||||
} else {
|
||||
document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML = '';
|
||||
document.getElementById('searchAddAllSongs').setAttribute('disabled', 'disabled');
|
||||
document.getElementById('searchAddAllSongsBtn').setAttribute('disabled', 'disabled');
|
||||
document.getElementById('panel-heading-search').innerText = '';
|
||||
document.getElementById('cardFooterSearch').innerText = '';
|
||||
document.getElementById('SearchList').classList.remove('opacity05');
|
||||
setPagination(0);
|
||||
}
|
||||
@ -608,8 +651,81 @@ function appInit() {
|
||||
document.getElementById('searchstr').addEventListener('keyup', function(event) {
|
||||
if (event.key == 'Escape')
|
||||
this.blur();
|
||||
else if (event.key == 'Enter' && settings.featAdvsearch) {
|
||||
if (this.value != '') {
|
||||
var match = document.getElementById('searchMatch');
|
||||
var li = document.createElement('button');
|
||||
li.classList.add('btn', 'btn-light', 'mr-2');
|
||||
li.setAttribute('data-filter', encodeURI(app.current.filter + ' ' + match.options[match.selectedIndex].value +' \'' + this.value + '\''));
|
||||
li.innerHTML = app.current.filter + ' ' + match.options[match.selectedIndex].value + ' \'' + this.value + '\'<span class="ml-2 badge badge-secondary">×</span>';
|
||||
this.value = '';
|
||||
document.getElementById('searchCrumb').appendChild(li);
|
||||
}
|
||||
else
|
||||
search(this.value);
|
||||
}
|
||||
else
|
||||
appGoto('Search', undefined, undefined, '0/' + app.current.filter + '/' + this.value);
|
||||
search(this.value);
|
||||
}, false);
|
||||
|
||||
document.getElementById('searchCrumb').addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.target.nodeName == 'SPAN') {
|
||||
event.target.parentNode.remove();
|
||||
search('');
|
||||
}
|
||||
else if (event.target.nodeName == 'BUTTON') {
|
||||
var value = decodeURI(event.target.getAttribute('data-filter'));
|
||||
document.getElementById('searchstr').value = value.substring(value.indexOf('\'') + 1, value.length - 1);
|
||||
var filter = value.substring(0, value.indexOf(' '));
|
||||
selectTag('searchtags', 'searchtagsdesc', filter);
|
||||
var match = value.substring(value.indexOf(' ') + 1);
|
||||
match = match.substring(0, match.indexOf(' '));
|
||||
document.getElementById('searchMatch').value = match;
|
||||
event.target.remove();
|
||||
search(document.getElementById('searchstr').value);
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('searchMatch').addEventListener('change', function(event) {
|
||||
search(document.getElementById('searchstr').value);
|
||||
}, false);
|
||||
|
||||
document.getElementById('SearchList').getElementsByTagName('tr')[0].addEventListener('click', function(event) {
|
||||
if (settings.featAdvsearch) {
|
||||
if (event.target.nodeName == 'TH') {
|
||||
var col = event.target.getAttribute('data-col');
|
||||
if (col == 'Duration')
|
||||
return;
|
||||
var sortcol = document.getElementById('SearchList').getAttribute('data-sort');
|
||||
var sortdesc = true;
|
||||
|
||||
if (sortcol == col || sortcol == '-' + col) {
|
||||
if (sortcol.indexOf('-') == 0) {
|
||||
sortdesc = true;
|
||||
sortcol = sortcol.substring(1);
|
||||
}
|
||||
else
|
||||
sortdesc = false;
|
||||
}
|
||||
if (sortdesc == false) {
|
||||
sortcol = '-' + col;
|
||||
sortdesc = true;
|
||||
}
|
||||
else {
|
||||
sortdesc = false;
|
||||
sortcol = col;
|
||||
}
|
||||
|
||||
var s = document.getElementById('SearchList').getElementsByClassName('sort-dir');
|
||||
for (var i = 0; i < s.length; i++)
|
||||
s[i].remove();
|
||||
document.getElementById('SearchList').setAttribute('data-sort', sortcol);
|
||||
event.target.innerHTML = col + '<span class="sort-dir material-icons pull-right">' + (sortdesc == true ? 'arrow_drop_up' : 'arrow_drop_down') + '</span>';
|
||||
appRoute();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('BrowseDatabaseByTagDropdown').addEventListener('click', function(event) {
|
||||
@ -634,8 +750,8 @@ function appInit() {
|
||||
window.addEventListener('focus', function() {
|
||||
sendAPI({"cmd": "MPD_API_PLAYER_STATE"}, parseState);
|
||||
}, false);
|
||||
|
||||
|
||||
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.target.tagName == 'INPUT' || event.target.tagName == 'SELECT' ||
|
||||
event.ctrlKey || event.altKey)
|
||||
@ -712,6 +828,28 @@ function parseCmd(event, href) {
|
||||
}
|
||||
}
|
||||
|
||||
function search(x) {
|
||||
if (settings.featAdvsearch) {
|
||||
var expression = '(';
|
||||
var crumbs = document.getElementById('searchCrumb').children;
|
||||
for (var i = 0; i < crumbs.length; i++) {
|
||||
expression += '(' + decodeURI(crumbs[i].getAttribute('data-filter')) + ')';
|
||||
if (x != '') expression += ' AND ';
|
||||
}
|
||||
if (x != '') {
|
||||
var match = document.getElementById('searchMatch');
|
||||
expression += '(' + app.current.filter + ' ' + match.options[match.selectedIndex].value + ' \'' + x +'\'))';
|
||||
}
|
||||
else
|
||||
expression += ')';
|
||||
if (expression.length <= 2)
|
||||
expression = '';
|
||||
appGoto('Search', undefined, undefined, '0/' + app.current.filter + '/' + encodeURI(expression));
|
||||
}
|
||||
else
|
||||
appGoto('Search', undefined, undefined, '0/' + app.current.filter + '/' + x);
|
||||
}
|
||||
|
||||
function dragAndDropTable(table) {
|
||||
var tableBody=document.getElementById(table).getElementsByTagName('tbody')[0];
|
||||
tableBody.addEventListener('dragstart', function(event) {
|
||||
@ -1059,7 +1197,7 @@ function parseSettings(obj) {
|
||||
|
||||
toggleBtn('btnnotifyPage', settings.notificationPage);
|
||||
|
||||
var features = ["featStickers", "featSmartpls", "featPlaylists", "featTags", "featLocalplayer", "featSyscmds", "featCoverimage"];
|
||||
var features = ["featStickers", "featSmartpls", "featPlaylists", "featTags", "featLocalplayer", "featSyscmds", "featCoverimage", "featAdvsearch"];
|
||||
|
||||
for (var j = 0; j < features.length; j++) {
|
||||
var Els = document.getElementsByClassName(features[j]);
|
||||
@ -1221,6 +1359,14 @@ function setCols(table, className) {
|
||||
}
|
||||
document.getElementById(table + 'ColsDropdown').firstChild.innerHTML = tagChks;
|
||||
|
||||
var sort = document.getElementById('SearchList').getAttribute('data-sort');
|
||||
if (sort == '') {
|
||||
if (settings.featTags)
|
||||
sort = 'Title';
|
||||
else
|
||||
sort = 'Filename';
|
||||
}
|
||||
|
||||
if (table != 'Playback') {
|
||||
var heading = '';
|
||||
for (var i = 0; i < settings['cols' + table].length; i++) {
|
||||
@ -1228,9 +1374,20 @@ function setCols(table, className) {
|
||||
heading += '<th draggable="true" data-col="' + h + '">';
|
||||
if (h == 'Track' || h == 'Pos')
|
||||
h = '#';
|
||||
heading += h + '</th>';
|
||||
heading += h;
|
||||
|
||||
if (table == 'Search' && h == sort ) {
|
||||
var sortdesc = false;
|
||||
if (sort.indexOf('-') == 0) {
|
||||
sortdesc = true;
|
||||
sort = sort.substring(1);
|
||||
}
|
||||
heading += '<span class="sort-dir material-icons pull-right">' + (sortdesc == true ? 'arrow_drop_up' : 'arrow_drop_down') + '</span>';
|
||||
}
|
||||
heading += '</th>';
|
||||
}
|
||||
heading += '<th></th>';
|
||||
|
||||
if (className == undefined)
|
||||
document.getElementById(table + 'List').getElementsByTagName('tr')[0].innerHTML = heading;
|
||||
else {
|
||||
|
@ -56,6 +56,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
|
||||
unsigned int uint_buf1, uint_buf2, uint_rc;
|
||||
int je, int_buf1, int_rc;
|
||||
float float_buf;
|
||||
bool bool_buf;
|
||||
char *p_charbuf1, *p_charbuf2, *p_charbuf3, *p_charbuf4;
|
||||
char p_char[4];
|
||||
enum mpd_cmd_ids cmd_id;
|
||||
@ -594,6 +595,16 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
|
||||
free(p_charbuf2);
|
||||
}
|
||||
break;
|
||||
case MPD_API_DATABASE_SEARCH_ADV:
|
||||
je = json_scanf(msg.p, msg.len, "{data: {expression:%Q, sort:%Q, sortdesc:%B, plist:%Q, offset:%u}}",
|
||||
&p_charbuf1, &p_charbuf2, &bool_buf, &p_charbuf3, &uint_buf1);
|
||||
if (je == 5) {
|
||||
n = mympd_search_adv(mpd.buf, p_charbuf1, p_charbuf2, bool_buf, NULL, p_charbuf3, uint_buf1);
|
||||
free(p_charbuf1);
|
||||
free(p_charbuf2);
|
||||
free(p_charbuf3);
|
||||
}
|
||||
break;
|
||||
case MPD_API_QUEUE_SHUFFLE:
|
||||
mpd_run_shuffle(mpd.conn);
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
|
||||
@ -2202,12 +2213,12 @@ int mympd_search_adv(char *buffer, char *expression, char *sort, bool sortdesc,
|
||||
if (mpd_search_add_expression(mpd.conn, expression) == false)
|
||||
RETURN_ERROR_AND_RECOVER("mpd_search_add_expression");
|
||||
|
||||
if (sort != NULL && strcmp(plist, "") == 0) {
|
||||
if (sort != NULL && strcmp(sort, "") != 0 && strcmp(plist, "") == 0) {
|
||||
if (mpd_search_add_sort_name(mpd.conn, sort, sortdesc) == false)
|
||||
RETURN_ERROR_AND_RECOVER("mpd_search_add_sort_name");
|
||||
}
|
||||
|
||||
if (grouptag != NULL && strcmp(plist, "") == 0) {
|
||||
if (grouptag != NULL && strcmp(grouptag, "") != 0 && strcmp(plist, "") == 0) {
|
||||
if (mpd_search_add_group_tag(mpd.conn, mpd_tag_name_parse(grouptag)) == false)
|
||||
RETURN_ERROR_AND_RECOVER("mpd_search_add_group_tag");
|
||||
}
|
||||
|
@ -98,6 +98,7 @@
|
||||
X(MPD_API_SMARTPLS_UPDATE_ALL) \
|
||||
X(MPD_API_SMARTPLS_SAVE) \
|
||||
X(MPD_API_SMARTPLS_GET) \
|
||||
X(MPD_API_DATABASE_SEARCH_ADV) \
|
||||
X(MPD_API_DATABASE_SEARCH) \
|
||||
X(MPD_API_DATABASE_UPDATE) \
|
||||
X(MPD_API_DATABASE_RESCAN) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user