You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
7.9 KiB
276 lines
7.9 KiB
import { menuEnum } from "../constants/index.js";
|
|
import { fetchData, downloadBook, searchByAuthor } from "../requests/index.js";
|
|
|
|
export default class BookSection {
|
|
subElements = [];
|
|
element;
|
|
|
|
constructor({ url = "", label = "" } = {}) {
|
|
this.url = url;
|
|
this.label = label;
|
|
this.render();
|
|
}
|
|
|
|
get template() {
|
|
return `
|
|
<div class='main-book__wrapper'>
|
|
<div data-element="body"></div>
|
|
<div class='flowers mh-auto'></div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
initialize() {
|
|
this.initEventListeners();
|
|
}
|
|
|
|
initEventListeners() {
|
|
const booksListener = document.querySelector(".main-book__wrapper");
|
|
booksListener.addEventListener("click", (event) => {
|
|
let id, title;
|
|
const isLike = event.target.closest("[data-like]");
|
|
|
|
const isMenu = event.target.closest("[data-menu]");
|
|
const isAction = event.target.closest("[data-action]");
|
|
const isLink = event.target.closest("[data-link]");
|
|
const isAuthor = event.target.closest("[data-author]");
|
|
|
|
switch (true) {
|
|
case !!isAction:
|
|
id = isAction.dataset.action;
|
|
const { authorid, bookid } =
|
|
isAction.parentNode.parentNode.dataset || {};
|
|
this.makeAction({ id, authorid, bookid });
|
|
|
|
break;
|
|
case !!isLike:
|
|
this.makeLike(isLike);
|
|
break;
|
|
|
|
case !!isMenu:
|
|
this.openMenu(isMenu);
|
|
|
|
break;
|
|
case !!isLink:
|
|
id = isLink.dataset.bookid;
|
|
title = isLink.dataset.title;
|
|
let format = isLink.dataset.format.toLowerCase();
|
|
downloadBook({ id, title, format });
|
|
|
|
break;
|
|
case !!isAuthor:
|
|
id = isAuthor.dataset.author;
|
|
this.update({ isByAuthor: true, id });
|
|
|
|
default:
|
|
this.closeMenu();
|
|
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
destroyEventListeners() {}
|
|
|
|
getBookBody(data) {
|
|
return (data || [])
|
|
.map(
|
|
({
|
|
id,
|
|
authors,
|
|
description,
|
|
format,
|
|
genres,
|
|
imageUrl,
|
|
title,
|
|
series,
|
|
subseries,
|
|
year,
|
|
tags,
|
|
isFavorite,
|
|
}) => {
|
|
const { name, id: authorid } = authors[0] || "Неизвестно";
|
|
return `
|
|
<article data-element="card" class="main-book__card d-fl mb-m mh-auto">
|
|
<div class="main-book__menu_wrapper d-fl">
|
|
<div class="main-book__menu_like ${
|
|
isFavorite ? "liked" : "not-liked"
|
|
}" data-like data-bookid=${id}></div>
|
|
|
|
<nav class="main-book__menu main-book__menu_closed"
|
|
data-authorid=${authorid}
|
|
data-bookid=${id}
|
|
data-menu></nav>
|
|
</div>
|
|
<div class="main-book__image mr-m">
|
|
<div class='d-fl'>
|
|
<div class="main-book__format pr-s">
|
|
<a class="main-book__link"
|
|
data-link
|
|
data-bookid=${id}
|
|
data-title=${(title || "Unknown")
|
|
.split(" ")
|
|
.join("_")}
|
|
data-format=${format}
|
|
>${format}</a>
|
|
</div>
|
|
<div>
|
|
<img class="d-bl" src=${
|
|
imageUrl ? imageUrl : "../web/assets/cover.jpg"
|
|
} alt="cover" style="width:80px;height:128px;">
|
|
<a class="main-card__author main-book__link second-text mt-s" data-author=${authorid}>
|
|
${name || ""}</a>
|
|
<div class="second-text mt-s">
|
|
${year || "Год неизвестен"}</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<div class="main-book__description ">
|
|
<div class="main-book__header">
|
|
<span class="second-text mt-s no-wrap "><strong>
|
|
${title || "Название неизвестно"}</strong></span>
|
|
<span class="second-text pl-xs no-wrap">
|
|
${series || ""}</span>
|
|
<span class="second-text pl-xs no-wrap ">
|
|
${subseries || ""}</span>
|
|
</div>
|
|
<div class="main-book__body mt-s">
|
|
<div>
|
|
<span class="second-text">
|
|
${description || "Нет описания"}</span>
|
|
</div>
|
|
</div>
|
|
<div class="main-book__footer d-fl mt-m">${this.getTags(
|
|
tags
|
|
)}</div>
|
|
</div>
|
|
|
|
</article>`;
|
|
}
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
getEmptyBody() {
|
|
return `
|
|
<article class="no-book__card d-fl mb-m mh-auto">
|
|
<div class="mh-auto">Ничего не найдено</div>
|
|
</article>`;
|
|
}
|
|
|
|
getMenuBody() {
|
|
return menuEnum
|
|
.map(({ label, id }) => {
|
|
return `
|
|
<li class="main-book__action second-text" id="main-book__action" data-action=${id}>
|
|
${label}
|
|
</li>`;
|
|
})
|
|
.join("");
|
|
}
|
|
|
|
getTags(tags) {
|
|
return (tags || [])
|
|
.map(({ id, name }) => {
|
|
return `<a class="main-book__tag main-book__link" data-id=${id}>#${name}</a>`;
|
|
})
|
|
.join("");
|
|
}
|
|
|
|
openMenu(element) {
|
|
this.closeMenu();
|
|
element.classList.remove("main-book__menu_closed");
|
|
|
|
const divElement = document.createElement("ul");
|
|
divElement.innerHTML = this.getMenuBody();
|
|
|
|
element.append(divElement);
|
|
element.classList.add("main-book__menu_opened");
|
|
}
|
|
|
|
closeMenu() {
|
|
const elements = document.querySelectorAll(".main-book__menu_opened");
|
|
|
|
if (elements && elements.length) {
|
|
for (const subElement of elements) {
|
|
subElement.firstElementChild.remove();
|
|
subElement.classList.remove("main-book__menu_opened");
|
|
subElement.classList.add("main-book__menu_closed");
|
|
}
|
|
}
|
|
}
|
|
|
|
async makeAction({ id, authorid, bookid }) {
|
|
this.element.classList.add("blur", "spinner");
|
|
|
|
if (menuEnum[id].action) {
|
|
const data = await menuEnum[id].action({ id, authorid, bookid });
|
|
} else {
|
|
alert("Напиши меня");
|
|
}
|
|
|
|
this.element.classList.remove("spinner");
|
|
this.closeMenu()
|
|
}
|
|
|
|
makeLike(element) {
|
|
const { bookid: likedBookId } = element.dataset || {};
|
|
this.makeAction({ id: 0, authorid: "", bookid: likedBookId });
|
|
element.classList.add("liked");
|
|
}
|
|
|
|
async update(params) {
|
|
this.element.classList.add("blur", "spinner");
|
|
|
|
let data = [];
|
|
if (params?.isByAuthor) {
|
|
data = await searchByAuthor({ id: params.id });
|
|
} else {
|
|
const query = params;
|
|
data = await fetchData({ query, url: this.url });
|
|
}
|
|
console.log("data", data);
|
|
if (data && Object.values(data).length) {
|
|
this.subElements.body.innerHTML = this.getBookBody(data);
|
|
this.initialize();
|
|
} else {
|
|
this.subElements.body.innerHTML = this.getEmptyBody();
|
|
}
|
|
this.element.classList.remove("spinner");
|
|
}
|
|
|
|
getSubElements(element) {
|
|
const result = {};
|
|
const elements = element.querySelectorAll("[data-element]");
|
|
|
|
for (const subElement of elements) {
|
|
const name = subElement.dataset.element;
|
|
|
|
result[name] = subElement;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
render() {
|
|
const divElement = document.createElement("div");
|
|
|
|
divElement.innerHTML = this.template;
|
|
|
|
this.element = divElement.firstElementChild;
|
|
this.subElements = this.getSubElements(this.element);
|
|
}
|
|
|
|
remove() {
|
|
if (this.element) {
|
|
this.element.remove();
|
|
destroyEventListeners();
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
this.remove();
|
|
this.element = null;
|
|
}
|
|
}
|