Работает добавление и удаление фильмов в админке
This commit is contained in:
parent
f75924a03c
commit
52f9769b41
@ -77,7 +77,7 @@
|
|||||||
</header>
|
</header>
|
||||||
<main class="flex-fill d-flex flex-column px-1 px-md-2">
|
<main class="flex-fill d-flex flex-column px-1 px-md-2">
|
||||||
<div class="control-group py-2">
|
<div class="control-group py-2">
|
||||||
<button id="items-add" class="btn btn-light">
|
<button id="movie-button-add" class="btn btn-light">
|
||||||
Добавить фильм (диалог)
|
Добавить фильм (диалог)
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -150,7 +150,7 @@
|
|||||||
<img
|
<img
|
||||||
id="image-preview"
|
id="image-preview"
|
||||||
src="https://via.placeholder.com/160x230"
|
src="https://via.placeholder.com/160x230"
|
||||||
class="rounded-2"
|
class="rounded-2 img-fluid"
|
||||||
alt="placeholder"
|
alt="placeholder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,151 @@
|
|||||||
import { ApiEndpoint } from "./apiendpoint";
|
import { ApiEndpoint, createMovieObject } from "./apiendpoint";
|
||||||
import { Modal } from "bootstrap";
|
import { Modal } from "bootstrap";
|
||||||
|
import { modalControls } from "./modalui";
|
||||||
|
|
||||||
const moviesApiEndpoint = new ApiEndpoint("movies");
|
const moviesApiEndpoint = new ApiEndpoint("movies");
|
||||||
const categoriesApiEndpoint = new ApiEndpoint("categories");
|
const categoriesApiEndpoint = new ApiEndpoint("categories");
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", loadMoviesTableData());
|
document.addEventListener("DOMContentLoaded", loadMoviesTableData());
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById("movie-button-add")
|
||||||
|
.addEventListener("click", buttonMovieAddClicked);
|
||||||
|
|
||||||
const modal = document.getElementById("modal-movie");
|
const modal = document.getElementById("modal-movie");
|
||||||
const myModal = modal ? new Modal(modal, {}) : null;
|
const myModal = modal ? new Modal(modal, {}) : null;
|
||||||
|
|
||||||
// myModal.show();
|
// myModal.show();
|
||||||
|
|
||||||
|
function createItemsOption(name, value = "", isSelected = false) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = value || "";
|
||||||
|
option.selected = isSelected;
|
||||||
|
option.text = name;
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readFile(file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
// создание Promise-объекта для использования функции
|
||||||
|
// с помощью await (асинхронно) без коллбэков (callback)
|
||||||
|
// https://learn.javascript.ru/promise
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 2. "Возвращаем" содержимое когда файл прочитан
|
||||||
|
// через вызов resolve
|
||||||
|
// Если не использовать Promise, то всю работу по взаимодействию
|
||||||
|
// с REST API пришлось бы делать в обработчике (callback) функции
|
||||||
|
// onloadend
|
||||||
|
reader.onloadend = () => {
|
||||||
|
const fileContent = reader.result;
|
||||||
|
// Здесь могла бы быть работа с REST API
|
||||||
|
// Чтение заканчивает выполняться здесь
|
||||||
|
resolve(fileContent);
|
||||||
|
};
|
||||||
|
// 3. Возвращаем ошибку
|
||||||
|
reader.onerror = () => {
|
||||||
|
// Или здесь в случае ошибки
|
||||||
|
reject(new Error("oops, something went wrong with the file reader."));
|
||||||
|
};
|
||||||
|
// Шаг 1. Сначала читаем файл
|
||||||
|
// Чтение начинает выполняться здесь
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// функция для обновления блока с превью выбранного изображения
|
||||||
|
async function updateImagePreview() {
|
||||||
|
// получение выбранного файла
|
||||||
|
// возможен выбор нескольких файлов, поэтому необходимо получить только первый
|
||||||
|
const file = modalControls.inputImage.files[0];
|
||||||
|
// чтение содержимого файла в виде base64 строки
|
||||||
|
const fileContent = await readFile(file);
|
||||||
|
console.info("base64 ", fileContent);
|
||||||
|
// обновление атрибута src для тега img с id image-preview
|
||||||
|
modalControls.imagePreview.src = fileContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imagePlaceholder = "./static/images/cover-placeholder160x230.png";
|
||||||
|
|
||||||
|
modalControls.form.addEventListener("submit", async (event) => {
|
||||||
|
// отключение стандартного поведения формы при отправке
|
||||||
|
// при отправке страница обновляется и JS перестает работать
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
// если форма не прошла валидацию, то ничего делать не нужно
|
||||||
|
// if (!cntrls.form.checkValidity()) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let imageBase64 = "";
|
||||||
|
// Получение выбранного пользователем изображения в виде base64 строки
|
||||||
|
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
||||||
|
// дефолтное изображение
|
||||||
|
|
||||||
|
// modalControls.imagePreview.src !== imagePlaceholder
|
||||||
|
// TODO
|
||||||
|
// прописать логиук отображения превью
|
||||||
|
if (modalControls.imagePreview.src !== imagePlaceholder) {
|
||||||
|
// Загрузка содержимого атрибута src тэга img с id image-preview
|
||||||
|
// Здесь выполняется HTTP запрос с типом GET
|
||||||
|
const result = await fetch(modalControls.imagePreview.src);
|
||||||
|
// Получение из HTTP-ответа бинарного содержимого
|
||||||
|
const blob = await result.blob();
|
||||||
|
// Получение base64 строки для файла
|
||||||
|
// Здесь выполняется Promise из функции readFile
|
||||||
|
// Promise позволяет писать линейный код для работы с асинхронными методами
|
||||||
|
// без использования обработчиков (callback) с помощью await
|
||||||
|
imageBase64 = await readFile(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
// получение id строки для редактирования
|
||||||
|
// это значение содержится в скрытом input
|
||||||
|
const currentId = modalControls.movieId.value;
|
||||||
|
// если значение id не задано,
|
||||||
|
// то необходимо выполнить добавление записи
|
||||||
|
// иначе обновление записи
|
||||||
|
if (!currentId) {
|
||||||
|
const movie = createMovieObject(
|
||||||
|
modalControls.inputName.value,
|
||||||
|
parseInt(modalControls.selectCategory.value),
|
||||||
|
modalControls.inputDuration.value,
|
||||||
|
modalControls.inputDescription.value,
|
||||||
|
imageBase64
|
||||||
|
);
|
||||||
|
await moviesApiEndpoint.createObject(movie);
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
// await editLine(
|
||||||
|
// currentId,
|
||||||
|
// cntrls.itemsType.value,
|
||||||
|
// cntrls.price.value,
|
||||||
|
// cntrls.count.value,
|
||||||
|
// imageBase64,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
// после выполнения добавления/обновления модальное окно скрывается
|
||||||
|
myModal.hide();
|
||||||
|
await loadMoviesTableData();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function buttonMovieAddClicked(e) {
|
||||||
|
modalControls.title.innerText = "Добавить фильм";
|
||||||
|
modalControls.selectCategory.innerHTML = "";
|
||||||
|
const categories = await categoriesApiEndpoint.getObjects();
|
||||||
|
modalControls.selectCategory.appendChild(
|
||||||
|
createItemsOption("Выберите жанр", "", true)
|
||||||
|
);
|
||||||
|
for (let i = 0; i < categories.length; i++) {
|
||||||
|
const category = categories[i];
|
||||||
|
modalControls.selectCategory.appendChild(
|
||||||
|
createItemsOption(category.name, category.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
myModal.show();
|
||||||
|
}
|
||||||
|
|
||||||
async function movieDeleteButtonClicked(e) {
|
async function movieDeleteButtonClicked(e) {
|
||||||
console.log(e.target);
|
console.log(e.target);
|
||||||
const movieId = parseInt(e.target.id.split("-")[3]);
|
const movieId = parseInt(e.target.id.split("-")[3]);
|
||||||
@ -18,12 +153,24 @@ async function movieDeleteButtonClicked(e) {
|
|||||||
await loadMoviesTableData();
|
await loadMoviesTableData();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function movieEditButtonClicked(e) {}
|
async function movieEditButtonClicked(e) {
|
||||||
|
// TODO
|
||||||
|
// получить объект по id
|
||||||
|
// заполнение модального окна по данным объекта
|
||||||
|
// показ модального окна
|
||||||
|
}
|
||||||
|
|
||||||
async function loadMoviesTableData() {
|
async function loadMoviesTableData() {
|
||||||
const movies = await moviesApiEndpoint.getObjects();
|
const movies = await moviesApiEndpoint.getObjects();
|
||||||
const category = await categoriesApiEndpoint.getObjects();
|
const category = await categoriesApiEndpoint.getObjects();
|
||||||
const tableWrapper = document.getElementById("movie-table-body");
|
const tableWrapper = document.getElementById("movie-table-body");
|
||||||
|
|
||||||
|
// Вызов функции обновления превью изображения при возникновении
|
||||||
|
// события oncahnge в тэге input с id image
|
||||||
|
modalControls.inputImage.addEventListener("change", () =>
|
||||||
|
updateImagePreview()
|
||||||
|
);
|
||||||
|
|
||||||
tableWrapper.innerHTML = "";
|
tableWrapper.innerHTML = "";
|
||||||
|
|
||||||
for (let i = 0; i < movies.length; i++) {
|
for (let i = 0; i < movies.length; i++) {
|
||||||
|
@ -1,89 +1,91 @@
|
|||||||
const serverUrl = "http://localhost:8081";
|
const serverUrl = "http://localhost:8081";
|
||||||
|
|
||||||
// export function createPostObject(
|
export function createMovieObject(
|
||||||
// userId,
|
name,
|
||||||
// createdDateTime,
|
categoryId,
|
||||||
// text,
|
duration,
|
||||||
// img,
|
description,
|
||||||
// ) {
|
img
|
||||||
// return {
|
) {
|
||||||
// userId,
|
return {
|
||||||
// createdDateTime,
|
name,
|
||||||
// text,
|
categoryId,
|
||||||
// img,
|
duration,
|
||||||
// };
|
description,
|
||||||
// }
|
img,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class ApiEndpoint {
|
export class ApiEndpoint {
|
||||||
constructor(endpoint) {
|
constructor(endpoint) {
|
||||||
this.endpoint = endpoint;
|
this.endpoint = endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getObjects() {
|
||||||
|
const response = await fetch(`${serverUrl}/${this.endpoint}`);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw response.statusText;
|
||||||
}
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
async getObjects() {
|
async getObject(id) {
|
||||||
const response = await fetch(`${serverUrl}/${this.endpoint}`);
|
const response = await fetch(`${serverUrl}/${this.endpoint}/${id}`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw response.statusText;
|
throw response.statusText;
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
}
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
async getObject(id) {
|
async createObject(obj) {
|
||||||
const response = await fetch(`${serverUrl}/${this.endpoint}/${id}`);
|
const options = {
|
||||||
if (!response.ok) {
|
method: "POST",
|
||||||
throw response.statusText;
|
body: JSON.stringify(obj),
|
||||||
}
|
headers: {
|
||||||
return response.json();
|
Accept: "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(`${serverUrl}/${this.endpoint}`, options);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw response.statusText;
|
||||||
}
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
async createObject(obj) {
|
async updateObject(obj) {
|
||||||
const options = {
|
const options = {
|
||||||
method: "POST",
|
method: "PUT",
|
||||||
body: JSON.stringify(obj),
|
body: JSON.stringify(obj),
|
||||||
headers: {
|
headers: {
|
||||||
"Accept": "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${serverUrl}/${this.endpoint}`, options);
|
const response = await fetch(
|
||||||
if (!response.ok) {
|
`${serverUrl}/${this.endpoint}/${obj.id}`,
|
||||||
throw response.statusText;
|
options
|
||||||
}
|
);
|
||||||
return response.json();
|
if (!response.ok) {
|
||||||
|
throw response.statusText;
|
||||||
}
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
async updateObject(obj) {
|
async deleteObject(id) {
|
||||||
const options = {
|
const options = {
|
||||||
method: "PUT",
|
method: "DELETE",
|
||||||
body: JSON.stringify(obj),
|
};
|
||||||
headers: {
|
|
||||||
"Accept": "application/json",
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${serverUrl}/${this.endpoint}/${obj.id}`,
|
`${serverUrl}/${this.endpoint}/${id}`,
|
||||||
options,
|
options
|
||||||
);
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw response.statusText;
|
throw response.statusText;
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteObject(id) {
|
|
||||||
const options = {
|
|
||||||
method: "DELETE",
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await fetch(
|
|
||||||
`${serverUrl}/${this.endpoint}/${id}`,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (!response.ok) {
|
|
||||||
throw response.statusText;
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
}
|
}
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
13
static/js/modalui.js
Normal file
13
static/js/modalui.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const movieModal = document.getElementById("modal-movie");
|
||||||
|
|
||||||
|
export const modalControls = {
|
||||||
|
title: document.getElementById("movie-modal-title"),
|
||||||
|
imagePreview: document.getElementById("image-preview"),
|
||||||
|
selectCategory: document.getElementById("category"),
|
||||||
|
inputName: document.getElementById("name"),
|
||||||
|
inputDuration: document.getElementById("duration"),
|
||||||
|
inputDescription: document.getElementById("description"),
|
||||||
|
inputImage: document.getElementById("image"),
|
||||||
|
form: document.getElementById("movie-form"),
|
||||||
|
movieId: document.getElementById("movie-id"),
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user