Merge pull request #3540 from WoodyLetsCode/search

Improve search and filter functionality
This commit is contained in:
Blaž Kristan 2023-11-29 13:41:38 +01:00 committed by GitHub
commit 8c69b85280
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 2134 additions and 2085 deletions

View File

@ -469,6 +469,7 @@ button {
height: 54px; height: 54px;
line-height: 1.5; line-height: 1.5;
padding-bottom: 8px; padding-bottom: 8px;
pointer-events: none;
} }
/* New tooltip */ /* New tooltip */
@ -1240,6 +1241,7 @@ TD .checkmark, TD .radiomark {
.filter .fchkl { .filter .fchkl {
margin: 0 4px; margin: 0 4px;
min-width: 20px; min-width: 20px;
pointer-events: auto;
} }
.lbl-l { .lbl-l {

View File

@ -197,33 +197,33 @@
<div id="Effects" class="tabcontent"> <div id="Effects" class="tabcontent">
<div id="fx"> <div id="fx">
<p class="labels hd" id="modeLabel">Effect mode</p> <p class="labels hd" id="modeLabel">Effect mode</p>
<div class="staytop fnd" id="fxFind"> <div class="staytop fnd" id="fxFind" onmousedown="preventBlur(event);">
<input type="text" placeholder="Search" oninput="search(this,'fxlist')" onfocus="filterFocus(event);search(this,'fxlist');" onblur="filterFocus(event);" /> <input type="text" placeholder="Search" oninput="search(this,'fxlist')" onfocus="filterFocus(event);search(this,'fxlist');" onblur="filterFocus(event);">
<i class="icons clear-icon" onclick="clean(this);">&#xe38f;</i> <i class="icons clear-icon" onclick="clean(this);">&#xe38f;</i>
<i class="icons search-icon" style="cursor:pointer;">&#xe0a1;</i> <i class="icons search-icon" style="cursor:pointer;">&#xe0a1;</i>
<div id="filters" class="filter fade"> <div id="filters" class="filter fade">
<label id="filterPal" tooltip="Uses palette" class="check fchkl">&#x1F3A8; <label id="filterPal" tooltip="Uses palette" class="check fchkl">&#x1F3A8;
<input type="checkbox" data-flt="&#x1F3A8;" onchange="filterFx(this);"> <input type="checkbox" data-flt="&#x1F3A8;" onchange="filterFx();">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<label id="filter0D" tooltip="Single pixel" class="check fchkl">&#8226; <label id="filter0D" tooltip="Single pixel" class="check fchkl">&#8226;
<input type="checkbox" data-flt="&#8226;" onchange="filterFx(this);"> <input type="checkbox" data-flt="&#8226;" onchange="filterFx();">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<label id="filter1D" tooltip="1D" class="check fchkl">&#8942; <label id="filter1D" tooltip="1D" class="check fchkl">&#8942;
<input type="checkbox" data-flt="&#8942;" onchange="filterFx(this);"> <input type="checkbox" data-flt="&#8942;" onchange="filterFx();">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<label id="filter2D" tooltip="2D" class="check fchkl">&#9638; <label id="filter2D" tooltip="2D" class="check fchkl">&#9638;
<input type="checkbox" data-flt="&#9638;" onchange="filterFx(this);"> <input type="checkbox" data-flt="&#9638;" onchange="filterFx();">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<label id="filterVol" tooltip="Volume" class="check fchkl">&#9834; <label id="filterVol" tooltip="Volume" class="check fchkl">&#9834;
<input type="checkbox" data-flt="&#9834;" onchange="filterFx(this);"> <input type="checkbox" data-flt="&#9834;" onchange="filterFx();">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
<label id="filterFreq" tooltip="Frequency" class="check fchkl">&#9835; <label id="filterFreq" tooltip="Frequency" class="check fchkl">&#9835;
<input type="checkbox" data-flt="&#9835;" onchange="filterFx(this);"> <input type="checkbox" data-flt="&#9835;" onchange="filterFx();">
<span class="checkmark"></span> <span class="checkmark"></span>
</label> </label>
</div> </div>

View File

@ -232,6 +232,7 @@ function onLoad()
tooltip(); tooltip();
resetPUtil(); resetPUtil();
initFilters();
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true); if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
applyCfg(); applyCfg();
@ -2716,58 +2717,94 @@ function hideModes(txt)
} }
} }
*/ */
function search(f,l=null) function search(field, listId = null) {
{ field.nextElementSibling.style.display = (field.value !== '') ? 'block' : 'none';
f.nextElementSibling.style.display=(f.value!=='')?'block':'none'; if (!listId) return;
if (!l) return;
var el = gId(l).querySelectorAll('.lstI'); // clear filter if searching in fxlist
if (listId === 'fxlist' && field.value !== '') {
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { e.checked = false; });
}
// do not search if filter is active
if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return;
const listItems = gId(listId).querySelectorAll('.lstI');
// filter list items but leave (Default & Solid) always visible // filter list items but leave (Default & Solid) always visible
for (i = (l==='pcont'?0:1); i < el.length; i++) { for (i = (listId === 'pcont' ? 0 : 1); i < listItems.length; i++) {
var it = el[i]; const listItem = listItems[i];
var itT = it.querySelector('.lstIname').innerText.toUpperCase(); const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase();
it.style.display = (itT.indexOf(f.value.toUpperCase())<0) ? 'none' : ''; const searchIndex = listItemName.indexOf(field.value.toUpperCase());
listItem.style.display = (searchIndex < 0) ? 'none' : '';
listItem.dataset.searchIndex = searchIndex;
} }
// sort list items by search index and name
const sortedListItems = Array.from(listItems).sort((a, b) => {
const aSearchIndex = parseInt(a.dataset.searchIndex);
const bSearchIndex = parseInt(b.dataset.searchIndex);
if (aSearchIndex !== bSearchIndex) {
return aSearchIndex - bSearchIndex;
}
const aName = a.querySelector('.lstIname').innerText.toUpperCase();
const bName = b.querySelector('.lstIname').innerText.toUpperCase();
return aName.localeCompare(bName);
});
sortedListItems.forEach(item => {
gId(listId).append(item);
});
} }
function clean(c) function clean(clearButton) {
{ clearButton.style.display = 'none';
c.style.display='none'; const inputField = clearButton.previousElementSibling;
var i=c.previousElementSibling; inputField.value = '';
i.value=''; search(inputField, clearButton.parentElement.nextElementSibling.id);
i.focus();
i.dispatchEvent(new Event('input'));
if (i.parentElement.id=='fxFind') {
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e)=>{e.checked=false;});
}
} }
function filterFocus(e) function initFilters() {
{ gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { e.checked = false; });
let f = gId("filters"); }
function filterFocus(e) {
const f = gId("filters");
if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition) if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition)
// compute sticky top (with delay for transition) // compute sticky top (with delay for transition)
setTimeout(()=>{ setTimeout(() => {
let sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight; const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight;
sCol('--sti', sti+"px"); sCol('--sti', sti + "px");
}, 252); }, 252);
if (e.type === "blur") { if (e.type === "blur") {
let t = e.relatedTarget ? e.relatedTarget : e.explicitOriginalTarget; setTimeout(() => {
do { if (e.target === document.activeElement && document.hasFocus()) return;
if (t.id && (t.id === "fxFind")) { setTimeout(()=>{t.firstElementChild.focus();},150); return; } // do not hide if filter is active
t = t.parentElement; if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return;
} while (t.tagName !== "BODY"); f.classList.add('fade');
setTimeout(()=>{f.classList.add('fade');},255); // wait with hiding }, 255); // wait with hiding
} }
} }
function filterFx(o) function filterFx() {
{ const inputField = gId('fxFind').children[0];
if (!o) return; inputField.value = '';
let i = gId('fxFind').children[0]; inputField.focus();
i.value=!o.checked?'':o.dataset.flt; clean(inputField.nextElementSibling);
i.focus(); const listItems = gId("fxlist").querySelectorAll('.lstI');
i.dispatchEvent(new Event('input')); for (let i = 1; i < listItems.length; i++) {
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e)=>{if(e!==o)e.checked=false;}); const listItem = listItems[i];
const listItemName = listItem.querySelector('.lstIname').innerText;
let hide = false;
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = true; });
listItem.style.display = hide ? 'none' : '';
}
}
function preventBlur(e) {
if (e.target === gId("fxFind").children[0] || e.target === gId("filters")) return;
e.preventDefault();
} }
// make sure "dur" and "transition" are arrays with at least the length of "ps" // make sure "dur" and "transition" are arrays with at least the length of "ps"

File diff suppressed because it is too large Load Diff