library back refactored
This commit is contained in:
parent
0cd8ca8a55
commit
dd64ba4d42
3 changed files with 67 additions and 46 deletions
|
@ -7,6 +7,7 @@ export default class Back extends Item {
|
||||||
super();
|
super();
|
||||||
this._title = title;
|
this._title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.appendChild(html.icon("keyboard-backspace"));
|
this.appendChild(html.icon("keyboard-backspace"));
|
||||||
this._buildTitle(this._title);
|
this._buildTitle(this._title);
|
||||||
|
|
|
@ -8,6 +8,10 @@ import { escape, serializeFilter } from "../mpd.js";
|
||||||
|
|
||||||
|
|
||||||
const SORT = "-Track";
|
const SORT = "-Track";
|
||||||
|
const TAGS = {
|
||||||
|
"Album": "Albums",
|
||||||
|
"AlbumArtist": "Artists"
|
||||||
|
}
|
||||||
|
|
||||||
function nonempty(str) { return (str.length > 0); }
|
function nonempty(str) { return (str.length > 0); }
|
||||||
|
|
||||||
|
@ -30,9 +34,22 @@ function createEnqueueCommand(node) {
|
||||||
class Library extends Component {
|
class Library extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({selection:"multi"});
|
super({selection:"multi"});
|
||||||
|
this._stateStack = [];
|
||||||
this._initCommands();
|
this._initCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_popState() {
|
||||||
|
this.selection.clear();
|
||||||
|
|
||||||
|
this._stateStack.pop();
|
||||||
|
if (this._stateStack.length > 0) {
|
||||||
|
let state = this._stateStack[this._stateStack.length-1];
|
||||||
|
this._showState(state);
|
||||||
|
} else {
|
||||||
|
this._showRoot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_onAppLoad() {
|
_onAppLoad() {
|
||||||
this._showRoot();
|
this._showRoot();
|
||||||
}
|
}
|
||||||
|
@ -45,25 +62,40 @@ class Library extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
_showRoot() {
|
_showRoot() {
|
||||||
|
this._stateStack = [];
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
|
|
||||||
const nav = html.node("nav", {}, "", this);
|
const nav = html.node("nav", {}, "", this);
|
||||||
|
|
||||||
html.button({icon:"artist"}, "Artists and albums", nav)
|
html.button({icon:"artist"}, "Artists and albums", nav)
|
||||||
.addEventListener("click", _ => this._listTags("AlbumArtist"));
|
.addEventListener("click", _ => this._pushState({type:"tags", tag:"AlbumArtist"}));
|
||||||
|
|
||||||
html.button({icon:"folder"}, "Files and directories", nav)
|
html.button({icon:"folder"}, "Files and directories", nav)
|
||||||
.addEventListener("click", _ => this._listPath(""));
|
.addEventListener("click", _ => this._pushState({type:"path", path:""}));
|
||||||
|
|
||||||
html.button({icon:"magnify"}, "Search", nav)
|
html.button({icon:"magnify"}, "Search", nav)
|
||||||
.addEventListener("click", _ => this._showSearch());
|
.addEventListener("click", _ => this._pushState({type:"search"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
_pushState(state) {
|
||||||
|
this._stateStack.push(state);
|
||||||
|
this._showState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
_showState(state) {
|
||||||
|
switch (state.type) {
|
||||||
|
case "tags": this._listTags(state.tag, state.filter); break;
|
||||||
|
case "songs": this._listSongs(state.filter); break;
|
||||||
|
case "path": this._listPath(state.path); break;
|
||||||
|
case "search": this._showSearch(state.query); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _listTags(tag, filter = {}) {
|
async _listTags(tag, filter = {}) {
|
||||||
const values = await this._mpd.listTags(tag, filter);
|
const values = await this._mpd.listTags(tag, filter);
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
|
|
||||||
if ("AlbumArtist" in filter) { this._buildBack(filter); }
|
if ("AlbumArtist" in filter) { this._buildBack(); }
|
||||||
values.filter(nonempty).forEach(value => this._buildTag(tag, value, filter));
|
values.filter(nonempty).forEach(value => this._buildTag(tag, value, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +103,7 @@ class Library extends Component {
|
||||||
let paths = await this._mpd.listPath(path);
|
let paths = await this._mpd.listPath(path);
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
|
|
||||||
path && this._buildBack(path);
|
path && this._buildBack();
|
||||||
paths["directory"].forEach(path => this._buildPath(path));
|
paths["directory"].forEach(path => this._buildPath(path));
|
||||||
paths["file"].forEach(path => this._buildPath(path));
|
paths["file"].forEach(path => this._buildPath(path));
|
||||||
}
|
}
|
||||||
|
@ -79,30 +111,34 @@ class Library extends Component {
|
||||||
async _listSongs(filter) {
|
async _listSongs(filter) {
|
||||||
const songs = await this._mpd.listSongs(filter);
|
const songs = await this._mpd.listSongs(filter);
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
this._buildBack(filter);
|
this._buildBack();
|
||||||
songs.forEach(song => this.appendChild(new Song(song)));
|
songs.forEach(song => this.appendChild(new Song(song)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_showSearch() {
|
_showSearch(query = "") {
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
|
|
||||||
const form = html.node("form", {}, "", this);
|
const form = html.node("form", {}, "", this);
|
||||||
const input = html.node("input", {type:"text"}, "", form);
|
const input = html.node("input", {type:"text", value:query}, "", form);
|
||||||
html.button({icon:"magnify"}, "", form);
|
html.button({icon:"magnify"}, "", form);
|
||||||
form.addEventListener("submit", e => {
|
form.addEventListener("submit", e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const q = input.value.trim();
|
const query = input.value.trim();
|
||||||
if (q.length < 3) { return; }
|
if (query.length < 3) { return; }
|
||||||
this._doSearch(q, form);
|
this._doSearch(query, form);
|
||||||
});
|
});
|
||||||
|
|
||||||
input.focus();
|
input.focus();
|
||||||
|
if (query) { this._doSearch(query, form); }
|
||||||
}
|
}
|
||||||
|
|
||||||
async _doSearch(q, form) {
|
async _doSearch(query, form) {
|
||||||
const songs1 = await this._mpd.searchSongs({"AlbumArtist": q});
|
let state = this._stateStack[this._stateStack.length-1];
|
||||||
const songs2 = await this._mpd.searchSongs({"Album": q});
|
state.query = query;
|
||||||
const songs3 = await this._mpd.searchSongs({"Title": q});
|
|
||||||
|
const songs1 = await this._mpd.searchSongs({"AlbumArtist": query});
|
||||||
|
const songs2 = await this._mpd.searchSongs({"Album": query});
|
||||||
|
const songs3 = await this._mpd.searchSongs({"Title": query});
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
this.appendChild(form);
|
this.appendChild(form);
|
||||||
|
|
||||||
|
@ -136,47 +172,29 @@ class Library extends Component {
|
||||||
case "AlbumArtist":
|
case "AlbumArtist":
|
||||||
node = new Tag(tag, value, filter);
|
node = new Tag(tag, value, filter);
|
||||||
this.appendChild(node);
|
this.appendChild(node);
|
||||||
node.onClick = () => this._listTags("Album", node.createChildFilter());
|
node.onClick = () => this._pushState({type:"tags", tag:"Album", filter:node.createChildFilter()});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Album":
|
case "Album":
|
||||||
node = new Tag(tag, value, filter);
|
node = new Tag(tag, value, filter);
|
||||||
this.appendChild(node);
|
this.appendChild(node);
|
||||||
node.addButton("chevron-double-right", _ => this._listSongs(node.createChildFilter()));
|
node.addButton("chevron-double-right", _ => this._pushState({type:"songs", filter:node.createChildFilter()}));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildBack(filterOrPath) {
|
_buildBack() {
|
||||||
if (typeof(filterOrPath) == "string") {
|
const backState = this._stateStack[this._stateStack.length-2];
|
||||||
const path = filterOrPath.split("/").slice(0, -1).join("");
|
let title;
|
||||||
const node = new Back("..");
|
switch (backState.type) {
|
||||||
this.appendChild(node);
|
case "path": title = ".."; break;
|
||||||
node.onClick = () => {
|
case "search": title = "Search"; break;
|
||||||
this.selection.clear();
|
case "tags": title = TAGS[backState.tag]; break;
|
||||||
this._listPath(path);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const filter = Object.assign({}, filterOrPath)
|
|
||||||
let tag, title;
|
|
||||||
|
|
||||||
if ("Album" in filter) {
|
|
||||||
tag = "Album";
|
|
||||||
title = filter["AlbumArtist"];
|
|
||||||
} else if ("AlbumArtist" in filter) {
|
|
||||||
tag = "AlbumArtist";
|
|
||||||
title = "Artists";
|
|
||||||
}
|
|
||||||
|
|
||||||
delete filter[tag];
|
|
||||||
const node = new Back(title);
|
const node = new Back(title);
|
||||||
this.appendChild(node);
|
this.appendChild(node);
|
||||||
node.onClick = () => {
|
node.onClick = () => this._popState();
|
||||||
this.selection.clear();
|
|
||||||
this._listTags(tag, filter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildPath(data) {
|
_buildPath(data) {
|
||||||
|
@ -185,7 +203,7 @@ class Library extends Component {
|
||||||
|
|
||||||
if ("directory" in data) {
|
if ("directory" in data) {
|
||||||
const path = data["directory"];
|
const path = data["directory"];
|
||||||
node.addButton("chevron-double-right", _ => this._listPath(path));
|
node.addButton("chevron-double-right", _ => this._pushState({type:"path", path}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import * as html from "./html.js";
|
import * as html from "./html.js";
|
||||||
|
|
||||||
|
|
||||||
|
const TAGS = ["cyp-song", "cyp-tag", "cyp-path"];
|
||||||
|
|
||||||
export default class Selection {
|
export default class Selection {
|
||||||
constructor(component, mode) {
|
constructor(component, mode) {
|
||||||
this._component = component;
|
this._component = component;
|
||||||
|
@ -25,8 +28,7 @@ export default class Selection {
|
||||||
|
|
||||||
addCommandAll() {
|
addCommandAll() {
|
||||||
this.addCommand(_ => {
|
this.addCommand(_ => {
|
||||||
Array.from(this._component.children)
|
Array.from(this._component.querySelectorAll(TAGS.join(", ")))
|
||||||
.filter(node => node.tagName.toLowerCase().startsWith("cyp-"))
|
|
||||||
.forEach(node => this.add(node));
|
.forEach(node => this.add(node));
|
||||||
}, {label:"Select all", icon:"checkbox-marked-outline"});
|
}, {label:"Select all", icon:"checkbox-marked-outline"});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue