settings: fix search with groups
works now, as in searching for a group's name works, and seeing matches within groups works.
This commit is contained in:
+10
-4
@@ -2,15 +2,21 @@ module github.com/hrfee/jfa-go/scripts/ini
|
|||||||
|
|
||||||
replace github.com/hrfee/jfa-go/common => ../../common
|
replace github.com/hrfee/jfa-go/common => ../../common
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/logmessages => ../../logmessages
|
||||||
|
|
||||||
go 1.22.4
|
go 1.22.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0
|
||||||
github.com/hrfee/jfa-go/common v0.0.0-20240824141650-fcdd4e451882 // indirect
|
github.com/hrfee/jfa-go/common v0.0.0-00010101000000-000000000000
|
||||||
|
gopkg.in/ini.v1 v1.67.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a // indirect
|
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
golang.org/x/sys v0.25.0 // indirect
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
+7
-2
@@ -1,16 +1,21 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a h1:qbXZgCqb9eaPSJfLEXczQD2lxTv6jb6silMPIWW9j6o=
|
|
||||||
github.com/hrfee/jfa-go/logmessages v0.0.0-20240806200606-6308db495a0a/go.mod h1:c5HKkLayo0GrEUDlJwT12b67BL9cdPjP271Xlv/KDRQ=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/hrfee/jfa-go/common"
|
"github.com/hrfee/jfa-go/common"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -27,48 +26,6 @@ func generateIni(yamlPath string, iniPath string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Validate that all groups/sections are listed in the root order, if it exists
|
|
||||||
if len(configBase.Order) > 0 {
|
|
||||||
// Expand order
|
|
||||||
var traverseGroup func(groupName string) []string
|
|
||||||
traverseGroup = func(groupName string) []string {
|
|
||||||
out := []string{}
|
|
||||||
for _, group := range configBase.Groups {
|
|
||||||
if group.Group == groupName {
|
|
||||||
for _, groupMember := range group.Members {
|
|
||||||
if groupMember.Group != "" {
|
|
||||||
out = append(out, traverseGroup(groupMember.Group)...)
|
|
||||||
} else if groupMember.Section != "" {
|
|
||||||
out = append(out, groupMember.Section)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
listedSects := map[string]bool{}
|
|
||||||
for _, member := range configBase.Order {
|
|
||||||
if member.Group != "" {
|
|
||||||
for _, sect := range traverseGroup(member.Group) {
|
|
||||||
listedSects[sect] = true
|
|
||||||
}
|
|
||||||
} else if member.Section != "" {
|
|
||||||
listedSects[member.Section] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
missingSections := false
|
|
||||||
for _, section := range configBase.Sections {
|
|
||||||
if _, ok := listedSects[section.Section]; !ok {
|
|
||||||
if !missingSections {
|
|
||||||
color.Red("WARNING: Root order specified but the following sections were not listed, directly or indirectly:")
|
|
||||||
missingSections = true
|
|
||||||
}
|
|
||||||
color.Red("\t%s", section.Section)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conf := ini.Empty()
|
conf := ini.Empty()
|
||||||
|
|
||||||
|
|||||||
+237
-94
@@ -479,6 +479,168 @@ interface Group {
|
|||||||
members: Member[];
|
members: Member[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class groupButton {
|
||||||
|
private _el: HTMLElement;
|
||||||
|
private _button: HTMLElement;
|
||||||
|
private _dropdown: HTMLElement;
|
||||||
|
private _icon: HTMLElement;
|
||||||
|
private _check: HTMLInputElement;
|
||||||
|
private _group: Group;
|
||||||
|
private _indent: number;
|
||||||
|
private _parentSidebar: HTMLElement;
|
||||||
|
|
||||||
|
asElement = () => { return this._el; };
|
||||||
|
|
||||||
|
remove = () => { this._el.remove(); };
|
||||||
|
|
||||||
|
update = (g: Group) => {
|
||||||
|
this._group = g;
|
||||||
|
this.group = g.group;
|
||||||
|
this.name = g.name;
|
||||||
|
this.description = g.description;
|
||||||
|
};
|
||||||
|
|
||||||
|
append(item: HTMLElement|groupButton) {
|
||||||
|
if (item instanceof groupButton) {
|
||||||
|
this._dropdown.appendChild(item.asElement());
|
||||||
|
} else {
|
||||||
|
this._dropdown.appendChild(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get name(): string { return this._group.name; }
|
||||||
|
set name(v: string) {
|
||||||
|
this._group.name = v;
|
||||||
|
this._button.querySelector(".group-button-name").textContent = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
get group(): string { return this._group.group; }
|
||||||
|
set group(v: string) {
|
||||||
|
this._group.group = v;
|
||||||
|
this._el.setAttribute("data-group", v);
|
||||||
|
this._button.setAttribute("data-group", v);
|
||||||
|
this._check.setAttribute("data-group", v);
|
||||||
|
this._dropdown.setAttribute("data-group", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
get description(): string { return this._group.description; }
|
||||||
|
set description(v: string) { this._group.description = v; }
|
||||||
|
|
||||||
|
get indent(): number { return this._indent; }
|
||||||
|
set indent(v: number) {
|
||||||
|
this._dropdown.classList.remove("ml-" + ((this._indent+1)*2));
|
||||||
|
this._indent = v;
|
||||||
|
this._dropdown.classList.add("ml-" + ((this._indent+1)*2));
|
||||||
|
}
|
||||||
|
|
||||||
|
get hidden(): boolean { return this._el.classList.contains("unfocused"); }
|
||||||
|
set hidden(v: boolean) {
|
||||||
|
if (v) this._el.classList.add("unfocused");
|
||||||
|
else this._el.classList.remove("unfocused");
|
||||||
|
}
|
||||||
|
|
||||||
|
get open(): boolean { return this._check.checked; }
|
||||||
|
set open(v: boolean) {
|
||||||
|
this.openCloseWithAnimation(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
openCloseWithAnimation(v: boolean) {
|
||||||
|
this._check.checked = v;
|
||||||
|
// When groups are nested, the outer group's scrollHeight will obviously change when an
|
||||||
|
// inner group is opened/closed. Instead of traversing the tree and adjusting the maxHeight property
|
||||||
|
// each open/close, just set the maxHeight to 9999px once the animation is completed.
|
||||||
|
// On close, quickly set maxHeight back to ~scrollHeight, then animate to 0.
|
||||||
|
if (this._check.checked) {
|
||||||
|
this._icon.classList.add("rotated");
|
||||||
|
// Hide the scrollbar while we animate
|
||||||
|
this._parentSidebar.style.overflowY = "hidden";
|
||||||
|
this._dropdown.classList.remove("unfocused");
|
||||||
|
const fullHeight = () => {
|
||||||
|
this._dropdown.removeEventListener("transitionend", fullHeight);
|
||||||
|
this._dropdown.style.maxHeight = "9999px";
|
||||||
|
// Return the scrollbar (or whatever, just don't hide it)
|
||||||
|
this._parentSidebar.style.overflowY = "";
|
||||||
|
};
|
||||||
|
this._dropdown.addEventListener("transitionend", fullHeight);
|
||||||
|
this._dropdown.style.maxHeight = (1.2*this._dropdown.scrollHeight)+"px";
|
||||||
|
this._dropdown.style.opacity = "100%";
|
||||||
|
} else {
|
||||||
|
this._icon.classList.remove("rotated");
|
||||||
|
const mainTransitionEnd = () => {
|
||||||
|
this._dropdown.removeEventListener("transitionend", mainTransitionEnd);
|
||||||
|
this._dropdown.classList.add("unfocused");
|
||||||
|
// Return the scrollbar (or whatever, just don't hide it)
|
||||||
|
this._parentSidebar.style.overflowY = "";
|
||||||
|
};
|
||||||
|
const mainTransitionStart = () => {
|
||||||
|
this._dropdown.removeEventListener("transitionend", mainTransitionStart)
|
||||||
|
this._dropdown.style.transitionDuration = "";
|
||||||
|
this._dropdown.addEventListener("transitionend", mainTransitionEnd);
|
||||||
|
this._dropdown.style.maxHeight = "0";
|
||||||
|
this._dropdown.style.opacity = "0";
|
||||||
|
}
|
||||||
|
// Hide the scrollbar while we animate
|
||||||
|
this._parentSidebar.style.overflowY = "hidden";
|
||||||
|
// Disabling transitions then going from 9999 - scrollHeight doesn't work in firefox to me,
|
||||||
|
// so instead just make the transition duration really short.
|
||||||
|
this._dropdown.style.transitionDuration = "1ms";
|
||||||
|
this._dropdown.addEventListener("transitionend", mainTransitionStart);
|
||||||
|
this._dropdown.style.maxHeight = (1.2*this._dropdown.scrollHeight)+"px";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openCloseWithoutAnimation(v: boolean) {
|
||||||
|
this._check.checked = v;
|
||||||
|
if (this._check.checked) {
|
||||||
|
this._icon.classList.add("rotated");
|
||||||
|
this._dropdown.style.maxHeight = "9999px";
|
||||||
|
this._dropdown.style.opacity = "100%";
|
||||||
|
this._dropdown.classList.remove("unfocused");
|
||||||
|
} else {
|
||||||
|
this._icon.classList.remove("rotated");
|
||||||
|
this._dropdown.style.maxHeight = "0";
|
||||||
|
this._dropdown.style.opacity = "0";
|
||||||
|
this._dropdown.classList.add("unfocused");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes sidebar as we need to disable scrolling on it when animation starts.
|
||||||
|
constructor(parentSidebar: HTMLElement) {
|
||||||
|
this._parentSidebar = parentSidebar;
|
||||||
|
|
||||||
|
this._el = document.createElement("div");
|
||||||
|
this._el.classList.add("flex", "flex-col", "gap-2");
|
||||||
|
|
||||||
|
this._button = document.createElement("span") as HTMLSpanElement;
|
||||||
|
this._el.appendChild(this._button);
|
||||||
|
this._button.classList.add("button", "~neutral", "@low", "settings-section-button", "justify-between");
|
||||||
|
this._button.innerHTML = `
|
||||||
|
<span class="group-button-name"></span>
|
||||||
|
<label>
|
||||||
|
<i class="icon ri-arrow-down-s-line"></i>
|
||||||
|
<input class="unfocused" type="checkbox">
|
||||||
|
</label>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this._dropdown = document.createElement("div") as HTMLDivElement;
|
||||||
|
this._el.appendChild(this._dropdown);
|
||||||
|
this._dropdown.style.maxHeight = "0";
|
||||||
|
this._dropdown.style.opacity = "0";
|
||||||
|
this._dropdown.classList.add("settings-dropdown", "unfocused", "flex", "flex-col", "gap-2", "transition-all");
|
||||||
|
|
||||||
|
this._icon = this._button.querySelector("i.icon");
|
||||||
|
this._check = this._button.querySelector("input[type=checkbox]") as HTMLInputElement;
|
||||||
|
|
||||||
|
this._button.onclick = () => {
|
||||||
|
this.open = !this.open;
|
||||||
|
};
|
||||||
|
this._check.onclick = () => {
|
||||||
|
this.open = this.open;
|
||||||
|
}
|
||||||
|
this.openCloseWithoutAnimation(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
interface Section {
|
interface Section {
|
||||||
section: string;
|
section: string;
|
||||||
meta: Meta;
|
meta: Meta;
|
||||||
@@ -595,7 +757,7 @@ export class settingsList {
|
|||||||
private _buttons: { [name: string]: HTMLSpanElement };
|
private _buttons: { [name: string]: HTMLSpanElement };
|
||||||
|
|
||||||
private _groups: { [name: string]: Group };
|
private _groups: { [name: string]: Group };
|
||||||
private _groupButtons: { [name: string]: HTMLSpanElement };
|
private _groupButtons: { [name: string]: groupButton };
|
||||||
|
|
||||||
private _needsRestart: boolean = false;
|
private _needsRestart: boolean = false;
|
||||||
private _messageEditor = new MessageEditor();
|
private _messageEditor = new MessageEditor();
|
||||||
@@ -614,82 +776,12 @@ export class settingsList {
|
|||||||
// Takes all groups at once since members might contain each other.
|
// Takes all groups at once since members might contain each other.
|
||||||
addGroups = (groups: Group[]) => {
|
addGroups = (groups: Group[]) => {
|
||||||
groups.forEach((g) => { this._groups[g.group] = g });
|
groups.forEach((g) => { this._groups[g.group] = g });
|
||||||
const addGroup = (g: Group, indent: number = 0): HTMLElement => {
|
const addGroup = (g: Group, indent: number = 0): groupButton => {
|
||||||
if (g.group in this._groupButtons) return null;
|
if (g.group in this._groupButtons) return null;
|
||||||
|
|
||||||
const container = document.createElement("div") as HTMLDivElement;
|
const container = new groupButton(this._sidebar);
|
||||||
container.classList.add("flex", "flex-col", "gap-2");
|
container.update(g);
|
||||||
|
container.indent = indent;
|
||||||
const button = document.createElement("span") as HTMLSpanElement;
|
|
||||||
container.appendChild(button);
|
|
||||||
button.classList.add("button", "~neutral", "@low", "settings-section-button", "justify-between");
|
|
||||||
button.innerHTML = `
|
|
||||||
${g.name}
|
|
||||||
<label>
|
|
||||||
<i class="icon ri-arrow-down-s-line"></i>
|
|
||||||
<input class="unfocused" type="checkbox">
|
|
||||||
</label>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const dropdown = document.createElement("div") as HTMLDivElement;
|
|
||||||
container.appendChild(dropdown);
|
|
||||||
dropdown.classList.add("ml-" + ((indent+1)*2));
|
|
||||||
dropdown.style.maxHeight = "0";
|
|
||||||
dropdown.style.opacity = "0";
|
|
||||||
dropdown.classList.add("settings-dropdown", "unfocused", "flex", "flex-col", "gap-2", "transition-all");
|
|
||||||
|
|
||||||
const icon = button.querySelector("i.icon");
|
|
||||||
const check = button.querySelector("input[type=checkbox]") as HTMLInputElement;
|
|
||||||
|
|
||||||
|
|
||||||
button.onclick = () => {
|
|
||||||
check.checked = !check.checked;
|
|
||||||
onCheck();
|
|
||||||
};
|
|
||||||
// When groups are nested, the outer group's scrollHeight will obviously change when an
|
|
||||||
// inner group is opened/closed. Instead of traversing the tree and adjusting the maxHeight property
|
|
||||||
// each open/close, just set the maxHeight to 9999px once the animation is completed.
|
|
||||||
// On close, quickly set maxHeight back to ~scrollHeight, then animate to 0.
|
|
||||||
const onCheck = () => {
|
|
||||||
if (check.checked) {
|
|
||||||
icon.classList.add("rotated");
|
|
||||||
// Hide the scrollbar while we animate
|
|
||||||
this._sidebar.style.overflowY = "hidden";
|
|
||||||
dropdown.classList.remove("unfocused");
|
|
||||||
const fullHeight = () => {
|
|
||||||
dropdown.removeEventListener("transitionend", fullHeight);
|
|
||||||
dropdown.style.maxHeight = "9999px";
|
|
||||||
// Return the scrollbar (or whatever, just don't hide it)
|
|
||||||
this._sidebar.style.overflowY = "";
|
|
||||||
};
|
|
||||||
dropdown.addEventListener("transitionend", fullHeight);
|
|
||||||
dropdown.style.maxHeight = (1.2*dropdown.scrollHeight)+"px";
|
|
||||||
dropdown.style.opacity = "100%";
|
|
||||||
} else {
|
|
||||||
icon.classList.remove("rotated");
|
|
||||||
const mainTransitionEnd = () => {
|
|
||||||
dropdown.removeEventListener("transitionend", mainTransitionEnd);
|
|
||||||
dropdown.classList.add("unfocused");
|
|
||||||
// Return the scrollbar (or whatever, just don't hide it)
|
|
||||||
this._sidebar.style.overflowY = "";
|
|
||||||
};
|
|
||||||
const mainTransitionStart = () => {
|
|
||||||
dropdown.removeEventListener("transitionend", mainTransitionStart)
|
|
||||||
dropdown.style.transitionDuration = "";
|
|
||||||
dropdown.addEventListener("transitionend", mainTransitionEnd);
|
|
||||||
dropdown.style.maxHeight = "0";
|
|
||||||
dropdown.style.opacity = "0";
|
|
||||||
}
|
|
||||||
// Hide the scrollbar while we animate
|
|
||||||
this._sidebar.style.overflowY = "hidden";
|
|
||||||
// Disabling transitions then going from 9999 - scrollHeight doesn't work in firefox to me,
|
|
||||||
// so instead just make the transition duration really short.
|
|
||||||
dropdown.style.transitionDuration = "1ms";
|
|
||||||
dropdown.addEventListener("transitionend", mainTransitionStart);
|
|
||||||
dropdown.style.maxHeight = (1.2*dropdown.scrollHeight)+"px";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check.onchange = onCheck;
|
|
||||||
|
|
||||||
for (const member of g.members) {
|
for (const member of g.members) {
|
||||||
if ("group" in member) {
|
if ("group" in member) {
|
||||||
@@ -699,12 +791,12 @@ export class settingsList {
|
|||||||
// Remove from page
|
// Remove from page
|
||||||
subgroup.remove();
|
subgroup.remove();
|
||||||
}
|
}
|
||||||
dropdown.appendChild(subgroup);
|
container.append(subgroup);
|
||||||
} else if ("section" in member) {
|
} else if ("section" in member) {
|
||||||
const subsection = this._buttons[member.section];
|
const subsection = this._buttons[member.section];
|
||||||
// Remove from page
|
// Remove from page
|
||||||
subsection.remove();
|
subsection.remove();
|
||||||
dropdown.appendChild(subsection);
|
container.append(subsection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,7 +806,8 @@ export class settingsList {
|
|||||||
for (let g of groups) {
|
for (let g of groups) {
|
||||||
const container = addGroup(g);
|
const container = addGroup(g);
|
||||||
if (container) {
|
if (container) {
|
||||||
this._sidebar.appendChild(container);
|
this._sidebar.appendChild(container.asElement());
|
||||||
|
container.openCloseWithoutAnimation(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,11 +855,27 @@ export class settingsList {
|
|||||||
this._sidebar.appendChild(this._buttons[name]);
|
this._sidebar.appendChild(this._buttons[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setOrder(order: Member[]) {
|
private _traverseMemberList = (list: Member[], func: (sect: string) => void) => {
|
||||||
|
for (const member of list) {
|
||||||
|
if ("group" in member) {
|
||||||
|
for (const group of this._settings.groups) {
|
||||||
|
if (group.group == member.group) {
|
||||||
|
this._traverseMemberList(group.members, func);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func(member.section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setUIOrder(order: Member[]) {
|
||||||
this._sidebar.textContent = ``;
|
this._sidebar.textContent = ``;
|
||||||
for (const member of order) {
|
for (const member of order) {
|
||||||
if ("group" in member) {
|
if ("group" in member) {
|
||||||
this._sidebar.appendChild(this._groupButtons[member.group]);
|
this._sidebar.appendChild(this._groupButtons[member.group].asElement());
|
||||||
|
this._groupButtons[member.group].openCloseWithoutAnimation(false);
|
||||||
} else if ("section" in member) {
|
} else if ("section" in member) {
|
||||||
if (member.section in this._buttons) {
|
if (member.section in this._buttons) {
|
||||||
this._sidebar.appendChild(this._buttons[member.section]);
|
this._sidebar.appendChild(this._buttons[member.section]);
|
||||||
@@ -1079,7 +1188,7 @@ export class settingsList {
|
|||||||
|
|
||||||
this.addGroups(this._settings.groups);
|
this.addGroups(this._settings.groups);
|
||||||
|
|
||||||
if ("order" in this._settings && this._settings.order) this.setOrder(this._settings.order);
|
if ("order" in this._settings && this._settings.order) this.setUIOrder(this._settings.order);
|
||||||
|
|
||||||
removeLoader(this._loader);
|
removeLoader(this._loader);
|
||||||
for (let i = 0; i < this._loader.children.length; i++) {
|
for (let i = 0; i < this._loader.children.length; i++) {
|
||||||
@@ -1097,6 +1206,7 @@ export class settingsList {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: Fix searching groups
|
||||||
// FIXME: Search "About" & "User profiles", pseudo-search "User profiles" for things like "Ombi", "Referrals", etc.
|
// FIXME: Search "About" & "User profiles", pseudo-search "User profiles" for things like "Ombi", "Referrals", etc.
|
||||||
search = (query: string) => {
|
search = (query: string) => {
|
||||||
query = query.toLowerCase().trim();
|
query = query.toLowerCase().trim();
|
||||||
@@ -1104,11 +1214,20 @@ export class settingsList {
|
|||||||
if (query.replace(/\s+/g, "") == "") query = "";
|
if (query.replace(/\s+/g, "") == "") query = "";
|
||||||
|
|
||||||
let firstVisibleSection = "";
|
let firstVisibleSection = "";
|
||||||
for (let section of this._settings.sections) {
|
|
||||||
|
// Close and hide all groups to start with
|
||||||
|
for (const groupButton of Object.values(this._groupButtons)) {
|
||||||
|
groupButton.openCloseWithoutAnimation(false);
|
||||||
|
groupButton.hidden = !(groupButton.group.toLowerCase().includes(query) ||
|
||||||
|
groupButton.name.toLowerCase().includes(query) ||
|
||||||
|
groupButton.description.toLowerCase().includes(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchSection = (section: Section) => {
|
||||||
// Section might be disabled at build-time (like Updates), or deprecated and so not appear.
|
// Section might be disabled at build-time (like Updates), or deprecated and so not appear.
|
||||||
if (!(section.section in this._sections)) {
|
if (!(section.section in this._sections)) {
|
||||||
// console.log(`Couldn't find section "${section.section}"`);
|
// console.log(`Couldn't find section "${section.section}"`);
|
||||||
continue
|
return;
|
||||||
}
|
}
|
||||||
const sectionElement = this._sections[section.section].asElement();
|
const sectionElement = this._sections[section.section].asElement();
|
||||||
let dependencyCard = sectionElement.querySelector(".settings-dependency-message");
|
let dependencyCard = sectionElement.querySelector(".settings-dependency-message");
|
||||||
@@ -1117,19 +1236,38 @@ export class settingsList {
|
|||||||
let dependencyList = null;
|
let dependencyList = null;
|
||||||
|
|
||||||
// hide button, unhide if matched
|
// hide button, unhide if matched
|
||||||
this._buttons[section.section].classList.add("unfocused");
|
const button = this._buttons[section.section];
|
||||||
|
button.classList.add("unfocused");
|
||||||
|
const parentGroup = button.parentElement.getAttribute("data-group");
|
||||||
|
let parentGroupButton: groupButton = null;
|
||||||
|
let matchedGroup = false;
|
||||||
|
if (parentGroup) {
|
||||||
|
parentGroupButton = this._groupButtons[parentGroup];
|
||||||
|
matchedGroup = !(parentGroupButton.hidden);
|
||||||
|
}
|
||||||
|
|
||||||
let matchedSection = false;
|
const show = () => {
|
||||||
|
button.classList.remove("unfocused");
|
||||||
if (section.section.toLowerCase().includes(query) ||
|
if (parentGroupButton) {
|
||||||
section.meta.name.toLowerCase().includes(query) ||
|
if (query != "") parentGroupButton.openCloseWithoutAnimation(true);
|
||||||
section.meta.description.toLowerCase().includes(query)) {
|
parentGroupButton.hidden = false;
|
||||||
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
|
||||||
this._buttons[section.section].classList.remove("unfocused");
|
|
||||||
firstVisibleSection = firstVisibleSection || section.section;
|
|
||||||
matchedSection = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const hide = () => {
|
||||||
|
button.classList.add("unfocused");
|
||||||
|
}
|
||||||
|
|
||||||
|
let matchedSection = matchedGroup ||
|
||||||
|
section.section.toLowerCase().includes(query) ||
|
||||||
|
section.meta.name.toLowerCase().includes(query) ||
|
||||||
|
section.meta.description.toLowerCase().includes(query);
|
||||||
|
matchedSection &&= ((section.meta.advanced && this._advanced) || !(section.meta.advanced));
|
||||||
|
|
||||||
|
if (matchedSection) {
|
||||||
|
show();
|
||||||
|
firstVisibleSection = firstVisibleSection || section.section;
|
||||||
|
}
|
||||||
|
|
||||||
for (let setting of section.settings) {
|
for (let setting of section.settings) {
|
||||||
if (setting.type == "note") continue;
|
if (setting.type == "note") continue;
|
||||||
const element = sectionElement.querySelector(`div[data-name="${setting.setting}"]`) as HTMLElement;
|
const element = sectionElement.querySelector(`div[data-name="${setting.setting}"]`) as HTMLElement;
|
||||||
@@ -1153,7 +1291,7 @@ export class settingsList {
|
|||||||
setting.description.toLowerCase().includes(query) ||
|
setting.description.toLowerCase().includes(query) ||
|
||||||
String(setting.value).toLowerCase().includes(query)) {
|
String(setting.value).toLowerCase().includes(query)) {
|
||||||
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
if ((section.meta.advanced && this._advanced) || !(section.meta.advanced)) {
|
||||||
this._buttons[section.section].classList.remove("unfocused");
|
show();
|
||||||
firstVisibleSection = firstVisibleSection || section.section;
|
firstVisibleSection = firstVisibleSection || section.section;
|
||||||
}
|
}
|
||||||
const shouldShow = (query != "" &&
|
const shouldShow = (query != "" &&
|
||||||
@@ -1198,7 +1336,12 @@ export class settingsList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let section of this._settings.sections) {
|
||||||
|
searchSection(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstVisibleSection && (query != "" || this._visibleSection == "")) {
|
if (firstVisibleSection && (query != "" || this._visibleSection == "")) {
|
||||||
this._buttons[firstVisibleSection].onclick(null);
|
this._buttons[firstVisibleSection].onclick(null);
|
||||||
this._noResultsPanel.classList.add("unfocused");
|
this._noResultsPanel.classList.add("unfocused");
|
||||||
|
|||||||
Reference in New Issue
Block a user