Laba3
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,455 +1,67 @@
|
|||||||
/* eslint-disable linebreak-style */
|
/* eslint-disable linebreak-style */
|
||||||
// модуль с логикой
|
// Модуль для работы с модальным окном
|
||||||
|
// eslint-disable-next-line linebreak-style
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-self-import
|
// импорт компонента Modal из bootstrap
|
||||||
import {
|
import { Modal } from "bootstrap";
|
||||||
// eslint-disable-next-line import/named
|
import { cntrls, imagePlaceholder } from "./lines-ui";
|
||||||
hideUpdateModal,
|
|
||||||
// eslint-disable-next-line import/named
|
|
||||||
showUpdateModal,
|
|
||||||
} from "./lines-modal";
|
|
||||||
import {
|
|
||||||
createLine,
|
|
||||||
deleteLine,
|
|
||||||
getAllGengeTypes,
|
|
||||||
getAllAuthorTypes,
|
|
||||||
getAllLines,
|
|
||||||
getLine,
|
|
||||||
updateLine,
|
|
||||||
} from "./lines-rest-api";
|
|
||||||
import {
|
|
||||||
cntrls,
|
|
||||||
createTableRow,
|
|
||||||
imagePlaceholder,
|
|
||||||
createGenresOption,
|
|
||||||
createAuthorsOption,
|
|
||||||
createTableRowOnIndex,
|
|
||||||
} from "./lines-ui";
|
|
||||||
|
|
||||||
async function drawGenreSelect() {
|
// поиск модального окна на странице
|
||||||
// вызов метода REST API для получения списка типов товаров
|
const modal = document.getElementById("items-update");
|
||||||
const data = await getAllGengeTypes();
|
// если он найден, то создается экземпляр компонента Modal
|
||||||
const data2 = await getAllAuthorTypes();
|
// для программного управления модальным окном
|
||||||
// очистка содержимого select
|
const myModal = modal ? new Modal(modal, {}) : null;
|
||||||
// удаляется все, что находится между тегами <select></select>
|
|
||||||
// но не атрибуты
|
// поиск тега с заголовком модального кона для его смены
|
||||||
cntrls.genresType.innerHTML = "";
|
const modalTitle = document.getElementById("items-update-title");
|
||||||
cntrls.authorsType.innerHTML = "";
|
|
||||||
// пустое значение
|
// обнуление значений модального окна, т. к.
|
||||||
cntrls.genresType.appendChild(createGenresOption("Выберите значение", "", true));
|
// используется одно окно для всех операций
|
||||||
cntrls.authorsType.appendChild(createGenresOption("Выберите значение", "", true));
|
function resetValues() {
|
||||||
// цикл по результату ответа от сервера
|
cntrls.lineId.value = "";
|
||||||
// используется лямбда-выражение
|
cntrls.nameBook.value = "";
|
||||||
// (item) => {} аналогично function(item) {}
|
cntrls.authorsType.value = "";
|
||||||
data.forEach((genre) => {
|
cntrls.genresType.value = "";
|
||||||
cntrls.genresType.appendChild(createGenresOption(genre.name, genre.id));
|
cntrls.year.value = "";
|
||||||
});
|
cntrls.description.value = "";
|
||||||
data2.forEach((author) => {
|
cntrls.count.value = "";
|
||||||
cntrls.authorsType.appendChild(createAuthorsOption(author.name, author.id));
|
cntrls.image.value = "";
|
||||||
});
|
cntrls.imagePreview.src = imagePlaceholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawLinesTable() {
|
// функция для показа модального окна
|
||||||
console.info("Try to load data");
|
// перед показом происходит заполнение формы для редактирования
|
||||||
if (!cntrls.table) {
|
// если объект item не пуст
|
||||||
return;
|
export function showUpdateModal(item) {
|
||||||
}
|
modalTitle.innerHTML = item === null ? "Добавить" : "Изменить";
|
||||||
// вызов метода REST API для получения всех записей
|
console.info(item);
|
||||||
const data = await getAllLines();
|
|
||||||
// очистка содержимого table
|
if (item) {
|
||||||
// удаляется все, что находится между тегами <table></table>
|
cntrls.lineId.value = item.id;
|
||||||
// но не атрибуты
|
cntrls.nameBook.value = item.nameBook;
|
||||||
cntrls.table.innerHTML = "";
|
cntrls.authorsType.value = item.authorsId;
|
||||||
// цикл по результату ответа от сервера
|
cntrls.genresType.value = item.genresId;
|
||||||
// используется лямбда-выражение
|
cntrls.year.value = item.year;
|
||||||
// (item, index) => {} аналогично function(item, index) {}
|
cntrls.description.value = item.description;
|
||||||
data.forEach((item, index) => {
|
cntrls.count.value = item.count;
|
||||||
cntrls.table.appendChild(
|
// заполнение превью
|
||||||
createTableRow(
|
// Если пользователь выбрал изображение, то оно загружается
|
||||||
item,
|
// в тэг image с id image - preview
|
||||||
index,
|
// иначе устанавливается заглушка, адрес которой указан в imagePlaceholder
|
||||||
// функции передаются в качестве параметра
|
cntrls.imagePreview.src = item.image ? item.image : imagePlaceholder;
|
||||||
// это очень удобно, так как аргументы функций доступны только
|
} else {
|
||||||
// в данном месте кода и не передаются в сервисные модули
|
resetValues();
|
||||||
() => showUpdateModal(item),
|
}
|
||||||
() => removeLine(item.id),
|
|
||||||
),
|
myModal.show();
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawLinesTableOnIndex() {
|
// функция для скрытия модального окна
|
||||||
console.info("Try to load data On Index");
|
export function hideUpdateModal() {
|
||||||
if (!cntrls.container) {
|
resetValues();
|
||||||
return;
|
|
||||||
}
|
// удаление класса was-validated для скрытия результатов валидации
|
||||||
// вызов метода REST API для получения всех записей
|
cntrls.form.classList.remove("was-validated");
|
||||||
const data = await getAllLines();
|
|
||||||
// очистка содержимого table
|
myModal.hide();
|
||||||
// удаляется все, что находится между тегами <table></table>
|
|
||||||
// но не атрибуты
|
|
||||||
cntrls.container.innerHTML = "";
|
|
||||||
// цикл по результату ответа от сервера
|
|
||||||
// используется лямбда-выражение
|
|
||||||
// (item, index) => {} аналогично function(item, index) {}
|
|
||||||
data.forEach((item, index) => {
|
|
||||||
cntrls.container.appendChild(
|
|
||||||
createTableRowOnIndex(
|
|
||||||
item,
|
|
||||||
index,
|
|
||||||
// функции передаются в качестве параметра
|
|
||||||
// это очень удобно, так как аргументы функций доступны только
|
|
||||||
// в данном месте кода и не передаются в сервисные модули
|
|
||||||
() => showUpdateModal(item),
|
|
||||||
() => location.assign(`page3.html?id=${item.id}`),
|
|
||||||
() => removeLine(item.id),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addLine(nameBook, authorsType, genresType, year, description, count, date, image) {
|
|
||||||
console.info("Try to add item");
|
|
||||||
// вызов метода REST API для добавления записи
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const data = await createLine(nameBook, authorsType, genresType, year, description, count, date, image);
|
|
||||||
console.info("Added");
|
|
||||||
console.info(data);
|
|
||||||
// загрузка и заполнение table
|
|
||||||
drawLinesTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
async function editLine(id, nameBook, authorsType, genresType, year, description, count, date, image) {
|
|
||||||
console.info("Try to update item");
|
|
||||||
console.log(id, nameBook, authorsType, genresType, description, count, date, image);
|
|
||||||
// вызов метода REST API для обновления записи
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const data = await updateLine(id, nameBook, authorsType, genresType, year, description, count, date, image);
|
|
||||||
console.info("Updated");
|
|
||||||
console.info(data);
|
|
||||||
// загрузка и заполнение table
|
|
||||||
drawLinesTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeLine(id) {
|
|
||||||
if (!confirm("Вы точно хотите удалить этот товар?")) {
|
|
||||||
console.info("Canceled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.info("Try to remove item");
|
|
||||||
// вызов метода REST API для удаления записи
|
|
||||||
const data = await deleteLine(id);
|
|
||||||
console.info(data);
|
|
||||||
// загрузка и заполнение table
|
|
||||||
drawLinesTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// функция для получения содержимого файла в виде base64 строки
|
|
||||||
// https://ru.wikipedia.org/wiki/Base64
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// функция для обновления блока с превью выбранного изображения
|
|
||||||
async function updateImagePreview() {
|
|
||||||
// получение выбранного файла
|
|
||||||
// возможен выбор нескольких файлов, поэтому необходимо получить только первый
|
|
||||||
const file = cntrls.image.files[0];
|
|
||||||
// чтение содержимого файла в виде base64 строки
|
|
||||||
const fileContent = await readFile(file);
|
|
||||||
console.info("base64 ", fileContent);
|
|
||||||
// обновление атрибута src для тега img с id image-preview
|
|
||||||
cntrls.imagePreview.src = fileContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Функция для обработки создания и редактирования элементов таблицы через модальное окно
|
|
||||||
// Если хотите делать через страницу, то удалите эту функцию
|
|
||||||
export function linesForm() {
|
|
||||||
console.info("linesForm");
|
|
||||||
|
|
||||||
// загрузка и заполнение select со списком товаров
|
|
||||||
drawGenreSelect();
|
|
||||||
// drawAuthorSelect();
|
|
||||||
// загрузка и заполнение table
|
|
||||||
drawLinesTable();
|
|
||||||
|
|
||||||
// Вызов функции обновления превью изображения при возникновении
|
|
||||||
// события oncahnge в тэге input с id image
|
|
||||||
cntrls.image.addEventListener("change", () => updateImagePreview());
|
|
||||||
|
|
||||||
// обработчик события нажатия на кнопку для показа модального окна
|
|
||||||
cntrls.button.addEventListener("click", () => showUpdateModal(null));
|
|
||||||
|
|
||||||
// обработчик события отправки формы
|
|
||||||
// возникает при нажатии на кнопку (button) с типом submit
|
|
||||||
// кнопка должна находится внутри тега form
|
|
||||||
cntrls.form.addEventListener("submit", async (event) => {
|
|
||||||
console.info("Form onSubmit");
|
|
||||||
// отключение стандартного поведения формы при отправке
|
|
||||||
// при отправке страница обновляется и JS перестает работать
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
// если форма не прошла валидацию, то ничего делать не нужно
|
|
||||||
if (!cntrls.form.checkValidity()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let imageBase64 = "";
|
|
||||||
// Получение выбранного пользователем изображения в виде base64 строки
|
|
||||||
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
|
||||||
// дефолтное изображение
|
|
||||||
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
|
||||||
// Загрузка содержимого атрибута src тэга img с id image-preview
|
|
||||||
// Здесь выполняется HTTP запрос с типом GET
|
|
||||||
const result = await fetch(cntrls.imagePreview.src);
|
|
||||||
// Получение из HTTP-ответа бинарного содержимого
|
|
||||||
const blob = await result.blob();
|
|
||||||
// Получение base64 строки для файла
|
|
||||||
// Здесь выполняется Promise из функции readFile
|
|
||||||
// Promise позволяет писать линейный код для работы с асинхронными методами
|
|
||||||
// без использования обработчиков (callback) с помощью await
|
|
||||||
imageBase64 = await readFile(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
// получение id строки для редактирования
|
|
||||||
// это значение содержится в скрытом input
|
|
||||||
const currentId = cntrls.lineId.value;
|
|
||||||
// если значение id не задано,
|
|
||||||
// то необходимо выполнить добавление записи
|
|
||||||
// иначе обновление записи
|
|
||||||
if (!currentId) {
|
|
||||||
await addLine(
|
|
||||||
cntrls.nameBook.value,
|
|
||||||
cntrls.authorsType.value,
|
|
||||||
cntrls.genresType.value,
|
|
||||||
cntrls.year.value,
|
|
||||||
cntrls.description.value,
|
|
||||||
cntrls.count.value,
|
|
||||||
cntrls.date.value,
|
|
||||||
imageBase64,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await editLine(
|
|
||||||
currentId,
|
|
||||||
cntrls.nameBook.value,
|
|
||||||
cntrls.authorsType.value,
|
|
||||||
cntrls.genresType.value,
|
|
||||||
cntrls.year.value,
|
|
||||||
cntrls.description.value,
|
|
||||||
cntrls.count.value,
|
|
||||||
cntrls.date.value,
|
|
||||||
imageBase64,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// после выполнения добавления/обновления модальное окно скрывается
|
|
||||||
hideUpdateModal();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function linesFormOnIndex() {
|
|
||||||
console.info("linesFormOnIndex");
|
|
||||||
|
|
||||||
// await drawGenreSelect();
|
|
||||||
await drawLinesTableOnIndex();
|
|
||||||
|
|
||||||
// обработчик события отправки формы
|
|
||||||
// возникает при нажатии на кнопку (button) с типом submit
|
|
||||||
// кнопка должна находится внутри тега form
|
|
||||||
cntrls.form.addEventListener("submit", async (event) => {
|
|
||||||
console.info("Form onSubmit");
|
|
||||||
// отключение стандартного поведения формы при отправке
|
|
||||||
// при отправке страница обновляется и JS перестает работать
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
// если форма не прошла валидацию, то ничего делать не нужно
|
|
||||||
if (!cntrls.form.checkValidity()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let imageBase64 = "";
|
|
||||||
// Получение выбранного пользователем изображения в виде base64 строки
|
|
||||||
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
|
||||||
// дефолтное изображение
|
|
||||||
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
|
||||||
// Загрузка содержимого атрибута src тэга img с id image-preview
|
|
||||||
// Здесь выполняется HTTP запрос с типом GET
|
|
||||||
const result = await fetch(cntrls.imagePreview.src);
|
|
||||||
// Получение из HTTP-ответа бинарного содержимого
|
|
||||||
const blob = await result.blob();
|
|
||||||
// Получение base64 строки для файла
|
|
||||||
// Здесь выполняется Promise из функции readFile
|
|
||||||
// Promise позволяет писать линейный код для работы с асинхронными методами
|
|
||||||
// без использования обработчиков (callback) с помощью await
|
|
||||||
imageBase64 = await readFile(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
// получение id строки для редактирования
|
|
||||||
// это значение содержится в скрытом input
|
|
||||||
const currentId = cntrls.lineId.value;
|
|
||||||
// если значение id не задано,
|
|
||||||
// то необходимо выполнить добавление записи
|
|
||||||
// иначе обновление записи
|
|
||||||
if (!currentId) {
|
|
||||||
await addLine(
|
|
||||||
cntrls.nameBook.value,
|
|
||||||
cntrls.authorsType.value,
|
|
||||||
cntrls.genresType.value,
|
|
||||||
cntrls.year.value,
|
|
||||||
cntrls.description.value,
|
|
||||||
cntrls.count.value,
|
|
||||||
cntrls.date.value,
|
|
||||||
imageBase64,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await editLine(
|
|
||||||
currentId,
|
|
||||||
cntrls.nameBook.value,
|
|
||||||
cntrls.authorsType.value,
|
|
||||||
cntrls.genresType.value,
|
|
||||||
cntrls.year.value,
|
|
||||||
cntrls.description.value,
|
|
||||||
cntrls.count.value,
|
|
||||||
cntrls.date.value,
|
|
||||||
imageBase64,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// после выполнения добавления/обновления модальное окно скрывается
|
|
||||||
hideUpdateModal();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Функция для обработки создания и редактирования элементов таблицы через страницу page-admin.html
|
|
||||||
// Если хотите делать через модальное окно, то удалите эту функцию
|
|
||||||
export async function linesPageForm() {
|
|
||||||
console.info("linesPageForm");
|
|
||||||
|
|
||||||
// загрузка и заполнение select со списком товаров
|
|
||||||
// drawGenreSelect();
|
|
||||||
|
|
||||||
// func1 = (id) => {} аналогично function func1(id) {}
|
|
||||||
const goBack = () => location.assign("/page3.html");
|
|
||||||
|
|
||||||
// Вызов функции обновления превью изображения при возникновении
|
|
||||||
// события onchange в тэге input с id image
|
|
||||||
cntrls.image.addEventListener("change", () => updateImagePreview());
|
|
||||||
|
|
||||||
// получение параметров GET-запроса из URL
|
|
||||||
// параметры перечислены после символа ? (?id=1&color=black&...)
|
|
||||||
const urlParams = new URLSearchParams(location.search);
|
|
||||||
|
|
||||||
// получение значения конкретного параметра (id)
|
|
||||||
// указан только при редактировании
|
|
||||||
const currentId = urlParams.get("id");
|
|
||||||
// если id задан
|
|
||||||
if (currentId) {
|
|
||||||
try {
|
|
||||||
// вызов метода REST API для получения записи по первичному ключу(id)
|
|
||||||
const line = await getLine(currentId);
|
|
||||||
// заполнение формы для редактирования
|
|
||||||
cntrls.nameBook.value = line.nameBook;
|
|
||||||
cntrls.authorsType.value = line.authorsType;
|
|
||||||
cntrls.genresType.value = line.genresType;
|
|
||||||
cntrls.year.value = line.year;
|
|
||||||
cntrls.description.value = line.description;
|
|
||||||
cntrls.count.value = line.count;
|
|
||||||
cntrls.date.value = line.date;
|
|
||||||
// заполнение превью
|
|
||||||
// Если пользователь выбрал изображение, то оно загружается
|
|
||||||
// в тэг image с id image - preview
|
|
||||||
// иначе устанавливается заглушка, адрес которой указан в imagePlaceholder
|
|
||||||
cntrls.imagePreview.src = line.image ? line.image : imagePlaceholder;
|
|
||||||
} catch {
|
|
||||||
// в случае ошибки происходит возврат к index
|
|
||||||
goBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// обработчик события отправки формы
|
|
||||||
// возникает при нажатии на кнопку (button) с типом submit
|
|
||||||
// кнопка должна находится внутри тега form
|
|
||||||
cntrls.form.addEventListener("submit", async (event) => {
|
|
||||||
console.info("Form onSubmit");
|
|
||||||
// отключение стандартного поведения формы при отправке
|
|
||||||
// при отправке страница обновляется и JS перестает работать
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
// если форма не прошла валидацию, то ничего делать не нужно
|
|
||||||
if (!cntrls.form.checkValidity()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let imageBase64 = "";
|
|
||||||
// Получение выбранного пользователем изображения в виде base64 строки
|
|
||||||
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
|
||||||
// дефолтное изображение
|
|
||||||
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
|
||||||
// Загрузка содержимого атрибута src тэга img с id image-preview
|
|
||||||
// Здесь выполняется HTTP запрос с типом GET
|
|
||||||
const result = await fetch(cntrls.imagePreview.src);
|
|
||||||
// Получение из HTTP-ответа бинарного содержимого
|
|
||||||
const blob = await result.blob();
|
|
||||||
// Получение base64 строки для файла
|
|
||||||
// Здесь выполняется Promise из функции readFile
|
|
||||||
// Promise позволяет писать линейный код для работы с асинхронными методами
|
|
||||||
// без использования обработчиков (callback) с помощью await
|
|
||||||
imageBase64 = await readFile(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
// если значение параметра запроса не задано,
|
|
||||||
// то необходимо выполнить добавление записи
|
|
||||||
// иначе обновление записи
|
|
||||||
if (!currentId) {
|
|
||||||
await addLine(
|
|
||||||
cntrls.nameBook.value,
|
|
||||||
cntrls.authorsType.value,
|
|
||||||
cntrls.genresType.value,
|
|
||||||
cntrls.year.value,
|
|
||||||
cntrls.description.value,
|
|
||||||
cntrls.count.value,
|
|
||||||
cntrls.date.value,
|
|
||||||
imageBase64,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await editLine(
|
|
||||||
currentId,
|
|
||||||
cntrls.nameBook.value,
|
|
||||||
cntrls.authorsType.value,
|
|
||||||
cntrls.genresType.value,
|
|
||||||
cntrls.year.value,
|
|
||||||
cntrls.description.value,
|
|
||||||
cntrls.count.value,
|
|
||||||
cntrls.date.value,
|
|
||||||
imageBase64,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// возврат к странице index
|
|
||||||
goBack();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
/* eslint-disable linebreak-style */
|
/* eslint-disable linebreak-style */
|
||||||
|
// eslint-disable-next-line linebreak-style
|
||||||
|
// eslint-disable-next-line linebreak-style
|
||||||
|
// eslint-disable-next-line linebreak-style
|
||||||
|
/* eslint-disable eol-last */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable max-len */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable comma-dangle */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
// модуль для работы с REST API сервера
|
// модуль для работы с REST API сервера
|
||||||
|
|
||||||
// адрес сервера
|
// адрес сервера
|
||||||
const serverUrl = "http://localhost:8081";
|
const serverUrl = "http://localhost:8081";
|
||||||
|
|
||||||
// функция возвращает объект нужной структуры для отправки на сервер
|
// функция возвращает объект нужной структуры для отправки на сервер
|
||||||
// eslint-disable-next-line max-len
|
function createLineObject(_name, _authorsType, _genresType, _year, _description, _count, _image) {
|
||||||
function createLineObject(_name, _authorsType, _genresType, _year, _description, _count, _date, _image) {
|
|
||||||
return {
|
return {
|
||||||
nameBook: _name,
|
nameBook: _name,
|
||||||
authorsId: _authorsType,
|
authorsId: _authorsType,
|
||||||
@@ -14,8 +22,7 @@ function createLineObject(_name, _authorsType, _genresType, _year, _description,
|
|||||||
year: _year,
|
year: _year,
|
||||||
description: _description,
|
description: _description,
|
||||||
count: _count,
|
count: _count,
|
||||||
date: _date,
|
image: _image
|
||||||
image: _image,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,10 +63,8 @@ export async function getLine(id) {
|
|||||||
|
|
||||||
// обращение к серверу для создания записи (post)
|
// обращение к серверу для создания записи (post)
|
||||||
// объект отправляется в теле запроса (body)
|
// объект отправляется в теле запроса (body)
|
||||||
// eslint-disable-next-line max-len
|
export async function createLine(_name, _authorsType, _genresType, _year, _description, _count, _image) {
|
||||||
export async function createLine(_name, _authorsType, _genresType, _year, _description, _count, _date, _image) {
|
const itemObject = createLineObject(_name, _authorsType, _genresType, _year, _description, _count, _image);
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const itemObject = createLineObject(_name, _authorsType, _genresType, _year, _description, _count, _date, _image);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -80,10 +85,8 @@ export async function createLine(_name, _authorsType, _genresType, _year, _descr
|
|||||||
// обращение к серверу для обновления записи по id (put)
|
// обращение к серверу для обновления записи по id (put)
|
||||||
// объект отправляется в теле запроса (body)
|
// объект отправляется в теле запроса (body)
|
||||||
// id передается в качестве части пути URL get-запроса
|
// id передается в качестве части пути URL get-запроса
|
||||||
// eslint-disable-next-line max-len
|
export async function updateLine(id, _name, _authorsType, _genresType, _year, _description, _count, _image) {
|
||||||
export async function updateLine(id, _name, _authorsType, _genresType, _year, _description, _count, _date, _image) {
|
const itemObject = createLineObject(_name, _authorsType, _genresType, _year, _description, _count, _image);
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const itemObject = createLineObject(_name, _authorsType, _genresType, _year, _description, _count, _date, _image);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
@@ -114,4 +117,4 @@ export async function deleteLine(id) {
|
|||||||
}
|
}
|
||||||
await response.json();
|
await response.json();
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
/* eslint-disable linebreak-style */
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable eol-last */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
// модуль для работы с элементами управления
|
// модуль для работы с элементами управления
|
||||||
|
|
||||||
// eslint-disable-next-line linebreak-style
|
|
||||||
// объект для удобного получения элементов
|
// объект для удобного получения элементов
|
||||||
// при обращении к атрибуту объекта вызывается
|
// при обращении к атрибуту объекта вызывается
|
||||||
// нужная функция для поиска элемента
|
// нужная функция для поиска элемента
|
||||||
@@ -17,7 +20,6 @@ export const cntrls = {
|
|||||||
year: document.getElementById("yearPicker"),
|
year: document.getElementById("yearPicker"),
|
||||||
description: document.getElementById("description"),
|
description: document.getElementById("description"),
|
||||||
count: document.getElementById("count"),
|
count: document.getElementById("count"),
|
||||||
date: document.getElementById("date"),
|
|
||||||
image: document.getElementById("image"),
|
image: document.getElementById("image"),
|
||||||
imagePreview: document.getElementById("image-preview"),
|
imagePreview: document.getElementById("image-preview"),
|
||||||
};
|
};
|
||||||
@@ -101,7 +103,6 @@ export function createTableRow(item, index, editCallback, deleteCallback) {
|
|||||||
row.appendChild(createTableColumn(item.year));
|
row.appendChild(createTableColumn(item.year));
|
||||||
row.appendChild(createTableColumn(item.description));
|
row.appendChild(createTableColumn(item.description));
|
||||||
row.appendChild(createTableColumn(item.count));
|
row.appendChild(createTableColumn(item.count));
|
||||||
row.appendChild(createTableColumn(item.date));
|
|
||||||
|
|
||||||
// редактировать в модальном окне
|
// редактировать в модальном окне
|
||||||
row.appendChild(createTableAnchor("fa-pencil", editCallback));
|
row.appendChild(createTableAnchor("fa-pencil", editCallback));
|
||||||
@@ -110,13 +111,15 @@ export function createTableRow(item, index, editCallback, deleteCallback) {
|
|||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTableRowOnIndex(item) {
|
export function createTableRowOnIndex(item, index, editCallback, editPageCallback, deleteCallback) {
|
||||||
console.log(item);
|
console.log(item);
|
||||||
|
|
||||||
const bookCard = createBookCard(item);
|
const bookCard = createBookCard(item);
|
||||||
return bookCard;
|
return bookCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-multiple-empty-lines
|
||||||
|
|
||||||
function createBookCard(item) {
|
function createBookCard(item) {
|
||||||
const card = document.createElement("div");
|
const card = document.createElement("div");
|
||||||
card.classList.add("book");
|
card.classList.add("book");
|
||||||
@@ -128,14 +131,29 @@ function createBookCard(item) {
|
|||||||
const title = document.createElement("h3");
|
const title = document.createElement("h3");
|
||||||
title.textContent = `${item.nameBook}, ${item.authors.name}`;
|
title.textContent = `${item.nameBook}, ${item.authors.name}`;
|
||||||
|
|
||||||
|
const detailsButton = document.createElement("a");
|
||||||
|
detailsButton.href = "#link";
|
||||||
|
detailsButton.classList.add("btn", "btn-custom");
|
||||||
|
detailsButton.role = "button";
|
||||||
|
detailsButton.textContent = "Подробнее";
|
||||||
|
|
||||||
|
const favoriteButton = document.createElement("a");
|
||||||
|
favoriteButton.href = "#link";
|
||||||
|
favoriteButton.classList.add("btn", "btn-custom");
|
||||||
|
favoriteButton.role = "button";
|
||||||
|
favoriteButton.textContent = "В избранное";
|
||||||
|
|
||||||
card.appendChild(image);
|
card.appendChild(image);
|
||||||
card.appendChild(title);
|
card.appendChild(title);
|
||||||
|
card.appendChild(detailsButton);
|
||||||
|
card.appendChild(favoriteButton);
|
||||||
|
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("col-12");
|
div.classList.add("col-12");
|
||||||
div.classList.add("col-md-4");
|
div.classList.add("col-md-6");
|
||||||
div.classList.add("col-lg-4");
|
div.classList.add("col-lg-4");
|
||||||
div.classList.add("col-xl-3");
|
div.classList.add("col-xl-3");
|
||||||
div.appendChild(card);
|
div.appendChild(card);
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
@@ -1,66 +1,62 @@
|
|||||||
/* eslint-disable linebreak-style */
|
/* eslint-disable linebreak-style */
|
||||||
/* eslint-disable import/named */
|
// eslint-disable-next-line linebreak-style
|
||||||
|
/* eslint-disable spaced-comment */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable comma-dangle */
|
||||||
|
/* eslint-disable linebreak-style */
|
||||||
|
/* eslint-disable no-trailing-spaces */
|
||||||
/* eslint-disable linebreak-style */
|
/* eslint-disable linebreak-style */
|
||||||
// модуль с логикой
|
// модуль с логикой
|
||||||
|
|
||||||
// eslint-disable-next-line import/named
|
import {
|
||||||
import { hideUpdateModal, showUpdateModal } from "./lines-modal";
|
hideUpdateModal,
|
||||||
|
showUpdateModal
|
||||||
|
} from "./lines-modal";
|
||||||
import {
|
import {
|
||||||
createLine,
|
createLine,
|
||||||
deleteLine,
|
deleteLine,
|
||||||
getAllItemTypes,
|
getAllGengeTypes,
|
||||||
getAllItemAuthors,
|
getAllAuthorTypes,
|
||||||
getAllLines,
|
getAllLines,
|
||||||
getLine,
|
getLine,
|
||||||
updateLine,
|
updateLine,
|
||||||
} from "./lines-rest-api";
|
} from "./lines-rest-api";
|
||||||
import {
|
import {
|
||||||
cntrls,
|
cntrls,
|
||||||
createItemsOption,
|
createTableRow,
|
||||||
createTableRow,
|
imagePlaceholder,
|
||||||
imagePlaceholder,
|
createGenresOption,
|
||||||
|
createAuthorsOption,
|
||||||
|
createTableRowOnIndex
|
||||||
} from "./lines-ui";
|
} from "./lines-ui";
|
||||||
|
|
||||||
async function drawItemsSelect() {
|
async function drawGenreSelect() {
|
||||||
// вызов метода REST API для получения списка типов товаров
|
// вызов метода REST API для получения списка типов товаров
|
||||||
const data = await getAllItemTypes();
|
const data = await getAllGengeTypes();
|
||||||
|
const data2 = await getAllAuthorTypes();
|
||||||
// очистка содержимого select
|
// очистка содержимого select
|
||||||
// удаляется все, что находится между тегами <select></select>
|
// удаляется все, что находится между тегами <select></select>
|
||||||
// но не атрибуты
|
// но не атрибуты
|
||||||
cntrls.itemsType.innerHTML = "";
|
cntrls.genresType.innerHTML = "";
|
||||||
|
cntrls.authorsType.innerHTML = "";
|
||||||
// пустое значение
|
// пустое значение
|
||||||
cntrls.itemsType.appendChild(
|
cntrls.genresType.appendChild(createGenresOption("Выберите значение", "", true));
|
||||||
createItemsOption("Выберите значение", "", true),
|
cntrls.authorsType.appendChild(createGenresOption("Выберите значение", "", true));
|
||||||
);
|
|
||||||
// цикл по результату ответа от сервера
|
// цикл по результату ответа от сервера
|
||||||
// используется лямбда-выражение
|
// используется лямбда-выражение
|
||||||
// (item) => {} аналогично function(item) {}
|
// (item) => {} аналогично function(item) {}
|
||||||
data.forEach((item) => {
|
data.forEach((genre) => {
|
||||||
cntrls.itemsType.appendChild(createItemsOption(item.name, item.id));
|
cntrls.genresType.appendChild(createGenresOption(genre.name, genre.id));
|
||||||
});
|
});
|
||||||
}
|
data2.forEach((author) => {
|
||||||
|
cntrls.authorsType.appendChild(createAuthorsOption(author.name, author.id));
|
||||||
async function drawAuthorsSelect() {
|
|
||||||
// вызов метода REST API для получения списка типов товаров
|
|
||||||
const data = await getAllItemAuthors();
|
|
||||||
// очистка содержимого select
|
|
||||||
// удаляется все, что находится между тегами <select></select>
|
|
||||||
// но не атрибуты
|
|
||||||
cntrls.author.innerHTML = "";
|
|
||||||
// пустое значение
|
|
||||||
cntrls.author.appendChild(createItemsOption("Выберите значение", "", true));
|
|
||||||
// цикл по результату ответа от сервера
|
|
||||||
// используется лямбда-выражение
|
|
||||||
// (item) => {} аналогично function(item) {}
|
|
||||||
data.forEach((item) => {
|
|
||||||
cntrls.author.appendChild(createItemsOption(item.name, item.id));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawLinesTable() {
|
async function drawLinesTable() {
|
||||||
console.info("Try to load data");
|
console.info("Try to load data");
|
||||||
if (!cntrls.table) {
|
if (!cntrls.table) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// вызов метода REST API для получения всех записей
|
// вызов метода REST API для получения всех записей
|
||||||
const data = await getAllLines();
|
const data = await getAllLines();
|
||||||
@@ -72,44 +68,66 @@ async function drawLinesTable() {
|
|||||||
// используется лямбда-выражение
|
// используется лямбда-выражение
|
||||||
// (item, index) => {} аналогично function(item, index) {}
|
// (item, index) => {} аналогично function(item, index) {}
|
||||||
data.forEach((item, index) => {
|
data.forEach((item, index) => {
|
||||||
cntrls.table.appendChild(
|
cntrls.table.appendChild(
|
||||||
createTableRow(
|
createTableRow(
|
||||||
item,
|
item,
|
||||||
index,
|
index,
|
||||||
// функции передаются в качестве параметра
|
// функции передаются в качестве параметра
|
||||||
// это очень удобно, так как аргументы функций доступны только
|
// это очень удобно, так как аргументы функций доступны только
|
||||||
// в данном месте кода и не передаются в сервисные модули
|
// в данном месте кода и не передаются в сервисные модули
|
||||||
() => showUpdateModal(item),
|
() => showUpdateModal(item),
|
||||||
() => location.assign(`page-edit.html?id=${item.id}`),
|
() => removeLine(item.id),
|
||||||
() => removeLine(item.id),
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addLine(item, author, name, desc, count, date, image) {
|
async function drawLinesTableOnIndex() {
|
||||||
|
console.info("Try to load data On Index");
|
||||||
|
if (!cntrls.container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// вызов метода REST API для получения всех записей
|
||||||
|
const data = await getAllLines();
|
||||||
|
// очистка содержимого table
|
||||||
|
// удаляется все, что находится между тегами <table></table>
|
||||||
|
// но не атрибуты
|
||||||
|
cntrls.container.innerHTML = "";
|
||||||
|
// цикл по результату ответа от сервера
|
||||||
|
// используется лямбда-выражение
|
||||||
|
// (item, index) => {} аналогично function(item, index) {}
|
||||||
|
data.forEach((item, index) => {
|
||||||
|
cntrls.container.appendChild(
|
||||||
|
createTableRowOnIndex(
|
||||||
|
item,
|
||||||
|
index,
|
||||||
|
// функции передаются в качестве параметра
|
||||||
|
// это очень удобно, так как аргументы функций доступны только
|
||||||
|
// в данном месте кода и не передаются в сервисные модули
|
||||||
|
() => showUpdateModal(item),
|
||||||
|
() => location.assign(`page3.html?id=${item.id}`),
|
||||||
|
() => removeLine(item.id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addLine(nameBook, authorsType, genresType, year, description, count, image) {
|
||||||
console.info("Try to add item");
|
console.info("Try to add item");
|
||||||
// вызов метода REST API для добавления записи
|
// вызов метода REST API для добавления записи
|
||||||
const data = await createLine(item, author, name, desc, count, date, image);
|
const data = await createLine(nameBook, authorsType, genresType, year, description, count, image);
|
||||||
console.info("Added");
|
console.info("Added");
|
||||||
console.info(data);
|
console.info(data);
|
||||||
// загрузка и заполнение table
|
// загрузка и заполнение table
|
||||||
drawLinesTable();
|
drawLinesTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function editLine(id, item, author, name, desc, count, date, image) {
|
async function editLine(id, nameBook, authorsType, genresType, year, description, count, image) {
|
||||||
console.info("Try to update item");
|
console.info("Try to update item");
|
||||||
|
console.log(id, nameBook, authorsType, genresType, description, count, image);
|
||||||
// вызов метода REST API для обновления записи
|
// вызов метода REST API для обновления записи
|
||||||
const data = await updateLine(
|
// eslint-disable-next-line max-len
|
||||||
id,
|
const data = await updateLine(id, nameBook, authorsType, genresType, year, description, count, image);
|
||||||
item,
|
|
||||||
author,
|
|
||||||
name,
|
|
||||||
desc,
|
|
||||||
count,
|
|
||||||
date,
|
|
||||||
image,
|
|
||||||
);
|
|
||||||
console.info("Updated");
|
console.info("Updated");
|
||||||
console.info(data);
|
console.info(data);
|
||||||
// загрузка и заполнение table
|
// загрузка и заполнение table
|
||||||
@@ -117,9 +135,9 @@ async function editLine(id, item, author, name, desc, count, date, image) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function removeLine(id) {
|
async function removeLine(id) {
|
||||||
if (!confirm("Do you really want to remove this item?")) {
|
if (!confirm("Вы точно хотите удалить этот товар?")) {
|
||||||
console.info("Canceled");
|
console.info("Canceled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.info("Try to remove item");
|
console.info("Try to remove item");
|
||||||
// вызов метода REST API для удаления записи
|
// вызов метода REST API для удаления записи
|
||||||
@@ -138,25 +156,25 @@ async function readFile(file) {
|
|||||||
// с помощью await (асинхронно) без коллбэков (callback)
|
// с помощью await (асинхронно) без коллбэков (callback)
|
||||||
// https://learn.javascript.ru/promise
|
// https://learn.javascript.ru/promise
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 2. "Возвращаем" содержимое когда файл прочитан
|
// 2. "Возвращаем" содержимое когда файл прочитан
|
||||||
// через вызов resolve
|
// через вызов resolve
|
||||||
// Если не использовать Promise, то всю работу по взаимодействию
|
// Если не использовать Promise, то всю работу по взаимодействию
|
||||||
// с REST API пришлось бы делать в обработчике (callback) функции
|
// с REST API пришлось бы делать в обработчике (callback) функции
|
||||||
// onloadend
|
// onloadend
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
const fileContent = reader.result;
|
const fileContent = reader.result;
|
||||||
// Здесь могла бы быть работа с REST API
|
// Здесь могла бы быть работа с REST API
|
||||||
// Чтение заканчивает выполняться здесь
|
// Чтение заканчивает выполняться здесь
|
||||||
resolve(fileContent);
|
resolve(fileContent);
|
||||||
};
|
};
|
||||||
// 3. Возвращаем ошибку
|
// 3. Возвращаем ошибку
|
||||||
reader.onerror = () => {
|
reader.onerror = () => {
|
||||||
// Или здесь в случае ошибки
|
// Или здесь в случае ошибки
|
||||||
reject(new Error("oops, something went wrong with the file reader."));
|
reject(new Error("oops, something went wrong with the file reader."));
|
||||||
};
|
};
|
||||||
// Шаг 1. Сначала читаем файл
|
// Шаг 1. Сначала читаем файл
|
||||||
// Чтение начинает выполняться здесь
|
// Чтение начинает выполняться здесь
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,8 +196,8 @@ export function linesForm() {
|
|||||||
console.info("linesForm");
|
console.info("linesForm");
|
||||||
|
|
||||||
// загрузка и заполнение select со списком товаров
|
// загрузка и заполнение select со списком товаров
|
||||||
drawItemsSelect();
|
drawGenreSelect();
|
||||||
drawAuthorsSelect();
|
//drawAuthorSelect();
|
||||||
// загрузка и заполнение table
|
// загрузка и заполнение table
|
||||||
drawLinesTable();
|
drawLinesTable();
|
||||||
|
|
||||||
@@ -194,78 +212,147 @@ export function linesForm() {
|
|||||||
// возникает при нажатии на кнопку (button) с типом submit
|
// возникает при нажатии на кнопку (button) с типом submit
|
||||||
// кнопка должна находится внутри тега form
|
// кнопка должна находится внутри тега form
|
||||||
cntrls.form.addEventListener("submit", async (event) => {
|
cntrls.form.addEventListener("submit", async (event) => {
|
||||||
console.info("Form onSubmit");
|
console.info("Form onSubmit");
|
||||||
// отключение стандартного поведения формы при отправке
|
// отключение стандартного поведения формы при отправке
|
||||||
// при отправке страница обновляется и JS перестает работать
|
// при отправке страница обновляется и JS перестает работать
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
// если форма не прошла валидацию, то ничего делать не нужно
|
// если форма не прошла валидацию, то ничего делать не нужно
|
||||||
if (!cntrls.form.checkValidity()) {
|
if (!cntrls.form.checkValidity()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let imageBase64 = "";
|
let imageBase64 = "";
|
||||||
// Получение выбранного пользователем изображения в виде base64 строки
|
// Получение выбранного пользователем изображения в виде base64 строки
|
||||||
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
||||||
// дефолтное изображение
|
// дефолтное изображение
|
||||||
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
||||||
// Загрузка содержимого атрибута src тэга img с id image-preview
|
// Загрузка содержимого атрибута src тэга img с id image-preview
|
||||||
// Здесь выполняется HTTP запрос с типом GET
|
// Здесь выполняется HTTP запрос с типом GET
|
||||||
const result = await fetch(cntrls.imagePreview.src);
|
const result = await fetch(cntrls.imagePreview.src);
|
||||||
// Получение из HTTP-ответа бинарного содержимого
|
// Получение из HTTP-ответа бинарного содержимого
|
||||||
const blob = await result.blob();
|
const blob = await result.blob();
|
||||||
// Получение base64 строки для файла
|
// Получение base64 строки для файла
|
||||||
// Здесь выполняется Promise из функции readFile
|
// Здесь выполняется Promise из функции readFile
|
||||||
// Promise позволяет писать линейный код для работы с асинхронными методами
|
// Promise позволяет писать линейный код для работы с асинхронными методами
|
||||||
// без использования обработчиков (callback) с помощью await
|
// без использования обработчиков (callback) с помощью await
|
||||||
imageBase64 = await readFile(blob);
|
imageBase64 = await readFile(blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
// получение id строки для редактирования
|
// получение id строки для редактирования
|
||||||
// это значение содержится в скрытом input
|
// это значение содержится в скрытом input
|
||||||
const currentId = cntrls.lineId.value;
|
const currentId = cntrls.lineId.value;
|
||||||
// если значение id не задано,
|
// если значение id не задано,
|
||||||
// то необходимо выполнить добавление записи
|
// то необходимо выполнить добавление записи
|
||||||
// иначе обновление записи
|
// иначе обновление записи
|
||||||
if (!currentId) {
|
if (!currentId) {
|
||||||
await addLine(
|
await addLine(
|
||||||
cntrls.itemsType.value,
|
cntrls.nameBook.value,
|
||||||
cntrls.author.value,
|
cntrls.authorsType.value,
|
||||||
cntrls.name.value,
|
cntrls.genresType.value,
|
||||||
cntrls.desc.value,
|
cntrls.year.value,
|
||||||
cntrls.count.value,
|
cntrls.description.value,
|
||||||
cntrls.date.value,
|
cntrls.count.value,
|
||||||
imageBase64,
|
imageBase64,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await editLine(
|
await editLine(
|
||||||
currentId,
|
currentId,
|
||||||
cntrls.itemsType.value,
|
cntrls.nameBook.value,
|
||||||
cntrls.author.value,
|
cntrls.authorsType.value,
|
||||||
cntrls.name.value,
|
cntrls.genresType.value,
|
||||||
cntrls.desc.value,
|
cntrls.year.value,
|
||||||
cntrls.count.value,
|
cntrls.description.value,
|
||||||
cntrls.date.value,
|
cntrls.count.value,
|
||||||
imageBase64,
|
imageBase64,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// после выполнения добавления/обновления модальное окно скрывается
|
// после выполнения добавления/обновления модальное окно скрывается
|
||||||
hideUpdateModal();
|
hideUpdateModal();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция для обработки создания и редактирования элементов таблицы через страницу page-edit.html
|
export async function linesFormOnIndex() {
|
||||||
|
console.info("linesFormOnIndex");
|
||||||
|
|
||||||
|
// await drawGenreSelect();
|
||||||
|
await drawLinesTableOnIndex();
|
||||||
|
|
||||||
|
// обработчик события отправки формы
|
||||||
|
// возникает при нажатии на кнопку (button) с типом submit
|
||||||
|
// кнопка должна находится внутри тега form
|
||||||
|
cntrls.form.addEventListener("submit", async (event) => {
|
||||||
|
console.info("Form onSubmit");
|
||||||
|
// отключение стандартного поведения формы при отправке
|
||||||
|
// при отправке страница обновляется и JS перестает работать
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
// если форма не прошла валидацию, то ничего делать не нужно
|
||||||
|
if (!cntrls.form.checkValidity()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let imageBase64 = "";
|
||||||
|
// Получение выбранного пользователем изображения в виде base64 строки
|
||||||
|
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
||||||
|
// дефолтное изображение
|
||||||
|
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
||||||
|
// Загрузка содержимого атрибута src тэга img с id image-preview
|
||||||
|
// Здесь выполняется HTTP запрос с типом GET
|
||||||
|
const result = await fetch(cntrls.imagePreview.src);
|
||||||
|
// Получение из HTTP-ответа бинарного содержимого
|
||||||
|
const blob = await result.blob();
|
||||||
|
// Получение base64 строки для файла
|
||||||
|
// Здесь выполняется Promise из функции readFile
|
||||||
|
// Promise позволяет писать линейный код для работы с асинхронными методами
|
||||||
|
// без использования обработчиков (callback) с помощью await
|
||||||
|
imageBase64 = await readFile(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
// получение id строки для редактирования
|
||||||
|
// это значение содержится в скрытом input
|
||||||
|
const currentId = cntrls.lineId.value;
|
||||||
|
// если значение id не задано,
|
||||||
|
// то необходимо выполнить добавление записи
|
||||||
|
// иначе обновление записи
|
||||||
|
if (!currentId) {
|
||||||
|
await addLine(
|
||||||
|
cntrls.nameBook.value,
|
||||||
|
cntrls.authorsType.value,
|
||||||
|
cntrls.genresType.value,
|
||||||
|
cntrls.year.value,
|
||||||
|
cntrls.description.value,
|
||||||
|
cntrls.count.value,
|
||||||
|
imageBase64,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await editLine(
|
||||||
|
currentId,
|
||||||
|
cntrls.nameBook.value,
|
||||||
|
cntrls.authorsType.value,
|
||||||
|
cntrls.genresType.value,
|
||||||
|
cntrls.year.value,
|
||||||
|
cntrls.description.value,
|
||||||
|
cntrls.count.value,
|
||||||
|
imageBase64,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// после выполнения добавления/обновления модальное окно скрывается
|
||||||
|
hideUpdateModal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Функция для обработки создания и редактирования элементов таблицы через страницу page-admin.html
|
||||||
// Если хотите делать через модальное окно, то удалите эту функцию
|
// Если хотите делать через модальное окно, то удалите эту функцию
|
||||||
export async function linesPageForm() {
|
export async function linesPageForm() {
|
||||||
console.info("linesPageForm");
|
console.info("linesPageForm");
|
||||||
|
|
||||||
// загрузка и заполнение select со списком товаров
|
// загрузка и заполнение select со списком товаров
|
||||||
drawItemsSelect();
|
// drawGenreSelect();
|
||||||
drawAuthorsSelect();
|
|
||||||
|
|
||||||
// func1 = (id) => {} аналогично function func1(id) {}
|
// func1 = (id) => {} аналогично function func1(id) {}
|
||||||
const goBack = () => location.assign("/page4.html");
|
const goBack = () => location.assign("/Catalog.html");
|
||||||
|
|
||||||
// Вызов функции обновления превью изображения при возникновении
|
// Вызов функции обновления превью изображения при возникновении
|
||||||
// события onchange в тэге input с id image
|
// события onchange в тэге input с id image
|
||||||
@@ -280,84 +367,84 @@ export async function linesPageForm() {
|
|||||||
const currentId = urlParams.get("id");
|
const currentId = urlParams.get("id");
|
||||||
// если id задан
|
// если id задан
|
||||||
if (currentId) {
|
if (currentId) {
|
||||||
try {
|
try {
|
||||||
// вызов метода REST API для получения записи по первичному ключу(id)
|
// вызов метода REST API для получения записи по первичному ключу(id)
|
||||||
const line = await getLine(currentId);
|
const line = await getLine(currentId);
|
||||||
// заполнение формы для редактирования
|
// заполнение формы для редактирования
|
||||||
cntrls.itemsType.value = line.itemsId;
|
cntrls.nameBook.value = line.nameBook;
|
||||||
cntrls.author.value = line.authorsId;
|
cntrls.authorsType.value = line.authorsType;
|
||||||
cntrls.name.value = line.name;
|
cntrls.genresType.value = line.genresType;
|
||||||
cntrls.desc.value = line.desc;
|
cntrls.year.value = line.year;
|
||||||
cntrls.count.value = line.count;
|
cntrls.description.value = line.description;
|
||||||
cntrls.date.value = line.date;
|
cntrls.count.value = line.count;
|
||||||
// заполнение превью
|
// заполнение превью
|
||||||
// Если пользователь выбрал изображение, то оно загружается
|
// Если пользователь выбрал изображение, то оно загружается
|
||||||
// в тэг image с id image - preview
|
// в тэг image с id image - preview
|
||||||
// иначе устанавливается заглушка, адрес которой указан в imagePlaceholder
|
// иначе устанавливается заглушка, адрес которой указан в imagePlaceholder
|
||||||
cntrls.imagePreview.src = line.image ? line.image : imagePlaceholder;
|
cntrls.imagePreview.src = line.image ? line.image : imagePlaceholder;
|
||||||
} catch {
|
} catch {
|
||||||
// в случае ошибки происходит возврат к page4
|
// в случае ошибки происходит возврат к index
|
||||||
goBack();
|
goBack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// обработчик события отправки формы
|
// обработчик события отправки формы
|
||||||
// возникает при нажатии на кнопку (button) с типом submit
|
// возникает при нажатии на кнопку (button) с типом submit
|
||||||
// кнопка должна находится внутри тега form
|
// кнопка должна находится внутри тега form
|
||||||
cntrls.form.addEventListener("submit", async (event) => {
|
cntrls.form.addEventListener("submit", async (event) => {
|
||||||
console.info("Form onSubmit");
|
console.info("Form onSubmit");
|
||||||
// отключение стандартного поведения формы при отправке
|
// отключение стандартного поведения формы при отправке
|
||||||
// при отправке страница обновляется и JS перестает работать
|
// при отправке страница обновляется и JS перестает работать
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
// если форма не прошла валидацию, то ничего делать не нужно
|
// если форма не прошла валидацию, то ничего делать не нужно
|
||||||
if (!cntrls.form.checkValidity()) {
|
if (!cntrls.form.checkValidity()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let imageBase64 = "";
|
let imageBase64 = "";
|
||||||
// Получение выбранного пользователем изображения в виде base64 строки
|
// Получение выбранного пользователем изображения в виде base64 строки
|
||||||
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
||||||
// дефолтное изображение
|
// дефолтное изображение
|
||||||
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
if (cntrls.imagePreview.src !== imagePlaceholder) {
|
||||||
// Загрузка содержимого атрибута src тэга img с id image-preview
|
// Загрузка содержимого атрибута src тэга img с id image-preview
|
||||||
// Здесь выполняется HTTP запрос с типом GET
|
// Здесь выполняется HTTP запрос с типом GET
|
||||||
const result = await fetch(cntrls.imagePreview.src);
|
const result = await fetch(cntrls.imagePreview.src);
|
||||||
// Получение из HTTP-ответа бинарного содержимого
|
// Получение из HTTP-ответа бинарного содержимого
|
||||||
const blob = await result.blob();
|
const blob = await result.blob();
|
||||||
// Получение base64 строки для файла
|
// Получение base64 строки для файла
|
||||||
// Здесь выполняется Promise из функции readFile
|
// Здесь выполняется Promise из функции readFile
|
||||||
// Promise позволяет писать линейный код для работы с асинхронными методами
|
// Promise позволяет писать линейный код для работы с асинхронными методами
|
||||||
// без использования обработчиков (callback) с помощью await
|
// без использования обработчиков (callback) с помощью await
|
||||||
imageBase64 = await readFile(blob);
|
imageBase64 = await readFile(blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
// если значение параметра запроса не задано,
|
// если значение параметра запроса не задано,
|
||||||
// то необходимо выполнить добавление записи
|
// то необходимо выполнить добавление записи
|
||||||
// иначе обновление записи
|
// иначе обновление записи
|
||||||
if (!currentId) {
|
if (!currentId) {
|
||||||
await addLine(
|
await addLine(
|
||||||
cntrls.itemsType.value,
|
cntrls.nameBook.value,
|
||||||
cntrls.author.value,
|
cntrls.authorsType.value,
|
||||||
cntrls.name.value,
|
cntrls.genresType.value,
|
||||||
cntrls.desc.value,
|
cntrls.year.value,
|
||||||
cntrls.count.value,
|
cntrls.description.value,
|
||||||
cntrls.date.value,
|
cntrls.count.value,
|
||||||
imageBase64,
|
imageBase64,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await editLine(
|
await editLine(
|
||||||
currentId,
|
currentId,
|
||||||
cntrls.itemsType.value,
|
cntrls.nameBook.value,
|
||||||
cntrls.author.value,
|
cntrls.authorsType.value,
|
||||||
cntrls.name.value,
|
cntrls.genresType.value,
|
||||||
cntrls.desc.value,
|
cntrls.year.value,
|
||||||
cntrls.count.value,
|
cntrls.description.value,
|
||||||
cntrls.date.value,
|
cntrls.count.value,
|
||||||
imageBase64,
|
imageBase64,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// возврат к странице page4
|
// возврат к странице index
|
||||||
goBack();
|
goBack();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable linebreak-style */
|
||||||
// модуль используется для валидации форма на странице
|
// модуль используется для валидации форма на странице
|
||||||
|
|
||||||
function validation() {
|
function validation() {
|
||||||
|
|||||||
20
3 proba/node_modules/.package-lock.json
generated
vendored
20
3 proba/node_modules/.package-lock.json
generated
vendored
@@ -1678,9 +1678,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.4",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2756,9 +2756,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3229,9 +3229,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.30",
|
"version": "8.4.33",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||||
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
|
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3248,7 +3248,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
|||||||
6
3 proba/node_modules/.vite/deps/_metadata.json
generated
vendored
6
3 proba/node_modules/.vite/deps/_metadata.json
generated
vendored
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"hash": "2b23bead",
|
"hash": "fa1fc037",
|
||||||
"browserHash": "d63b02ce",
|
"browserHash": "c20cb0a6",
|
||||||
"optimized": {
|
"optimized": {
|
||||||
"bootstrap": {
|
"bootstrap": {
|
||||||
"src": "../../bootstrap/dist/js/bootstrap.esm.js",
|
"src": "../../bootstrap/dist/js/bootstrap.esm.js",
|
||||||
"file": "bootstrap.js",
|
"file": "bootstrap.js",
|
||||||
"fileHash": "c09afe4f",
|
"fileHash": "fba3a4d5",
|
||||||
"needsInterop": false
|
"needsInterop": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
2
3 proba/node_modules/.vite/deps/bootstrap.js.map
generated
vendored
2
3 proba/node_modules/.vite/deps/bootstrap.js.map
generated
vendored
File diff suppressed because one or more lines are too long
208
3 proba/node_modules/follow-redirects/index.js
generated
vendored
208
3 proba/node_modules/follow-redirects/index.js
generated
vendored
@@ -6,6 +6,29 @@ var Writable = require("stream").Writable;
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var debug = require("./debug");
|
var debug = require("./debug");
|
||||||
|
|
||||||
|
// Whether to use the native URL object or the legacy url module
|
||||||
|
var useNativeURL = false;
|
||||||
|
try {
|
||||||
|
assert(new URL());
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
useNativeURL = error.code === "ERR_INVALID_URL";
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL fields to preserve in copy operations
|
||||||
|
var preservedUrlFields = [
|
||||||
|
"auth",
|
||||||
|
"host",
|
||||||
|
"hostname",
|
||||||
|
"href",
|
||||||
|
"path",
|
||||||
|
"pathname",
|
||||||
|
"port",
|
||||||
|
"protocol",
|
||||||
|
"query",
|
||||||
|
"search",
|
||||||
|
];
|
||||||
|
|
||||||
// Create handlers that pass events from native requests
|
// Create handlers that pass events from native requests
|
||||||
var events = ["abort", "aborted", "connect", "error", "socket", "timeout"];
|
var events = ["abort", "aborted", "connect", "error", "socket", "timeout"];
|
||||||
var eventHandlers = Object.create(null);
|
var eventHandlers = Object.create(null);
|
||||||
@@ -15,19 +38,20 @@ events.forEach(function (event) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Error types with codes
|
||||||
var InvalidUrlError = createErrorType(
|
var InvalidUrlError = createErrorType(
|
||||||
"ERR_INVALID_URL",
|
"ERR_INVALID_URL",
|
||||||
"Invalid URL",
|
"Invalid URL",
|
||||||
TypeError
|
TypeError
|
||||||
);
|
);
|
||||||
// Error types with codes
|
|
||||||
var RedirectionError = createErrorType(
|
var RedirectionError = createErrorType(
|
||||||
"ERR_FR_REDIRECTION_FAILURE",
|
"ERR_FR_REDIRECTION_FAILURE",
|
||||||
"Redirected request failed"
|
"Redirected request failed"
|
||||||
);
|
);
|
||||||
var TooManyRedirectsError = createErrorType(
|
var TooManyRedirectsError = createErrorType(
|
||||||
"ERR_FR_TOO_MANY_REDIRECTS",
|
"ERR_FR_TOO_MANY_REDIRECTS",
|
||||||
"Maximum number of redirects exceeded"
|
"Maximum number of redirects exceeded",
|
||||||
|
RedirectionError
|
||||||
);
|
);
|
||||||
var MaxBodyLengthExceededError = createErrorType(
|
var MaxBodyLengthExceededError = createErrorType(
|
||||||
"ERR_FR_MAX_BODY_LENGTH_EXCEEDED",
|
"ERR_FR_MAX_BODY_LENGTH_EXCEEDED",
|
||||||
@@ -38,6 +62,9 @@ var WriteAfterEndError = createErrorType(
|
|||||||
"write after end"
|
"write after end"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// istanbul ignore next
|
||||||
|
var destroy = Writable.prototype.destroy || noop;
|
||||||
|
|
||||||
// An HTTP(S) request that can be redirected
|
// An HTTP(S) request that can be redirected
|
||||||
function RedirectableRequest(options, responseCallback) {
|
function RedirectableRequest(options, responseCallback) {
|
||||||
// Initialize the request
|
// Initialize the request
|
||||||
@@ -59,7 +86,13 @@ function RedirectableRequest(options, responseCallback) {
|
|||||||
// React to responses of native requests
|
// React to responses of native requests
|
||||||
var self = this;
|
var self = this;
|
||||||
this._onNativeResponse = function (response) {
|
this._onNativeResponse = function (response) {
|
||||||
self._processResponse(response);
|
try {
|
||||||
|
self._processResponse(response);
|
||||||
|
}
|
||||||
|
catch (cause) {
|
||||||
|
self.emit("error", cause instanceof RedirectionError ?
|
||||||
|
cause : new RedirectionError({ cause: cause }));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Perform the first request
|
// Perform the first request
|
||||||
@@ -68,10 +101,17 @@ function RedirectableRequest(options, responseCallback) {
|
|||||||
RedirectableRequest.prototype = Object.create(Writable.prototype);
|
RedirectableRequest.prototype = Object.create(Writable.prototype);
|
||||||
|
|
||||||
RedirectableRequest.prototype.abort = function () {
|
RedirectableRequest.prototype.abort = function () {
|
||||||
abortRequest(this._currentRequest);
|
destroyRequest(this._currentRequest);
|
||||||
|
this._currentRequest.abort();
|
||||||
this.emit("abort");
|
this.emit("abort");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RedirectableRequest.prototype.destroy = function (error) {
|
||||||
|
destroyRequest(this._currentRequest, error);
|
||||||
|
destroy.call(this, error);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
// Writes buffered data to the current native request
|
// Writes buffered data to the current native request
|
||||||
RedirectableRequest.prototype.write = function (data, encoding, callback) {
|
RedirectableRequest.prototype.write = function (data, encoding, callback) {
|
||||||
// Writing is not allowed if end has been called
|
// Writing is not allowed if end has been called
|
||||||
@@ -184,6 +224,7 @@ RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
|||||||
self.removeListener("abort", clearTimer);
|
self.removeListener("abort", clearTimer);
|
||||||
self.removeListener("error", clearTimer);
|
self.removeListener("error", clearTimer);
|
||||||
self.removeListener("response", clearTimer);
|
self.removeListener("response", clearTimer);
|
||||||
|
self.removeListener("close", clearTimer);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
self.removeListener("timeout", callback);
|
self.removeListener("timeout", callback);
|
||||||
}
|
}
|
||||||
@@ -210,6 +251,7 @@ RedirectableRequest.prototype.setTimeout = function (msecs, callback) {
|
|||||||
this.on("abort", clearTimer);
|
this.on("abort", clearTimer);
|
||||||
this.on("error", clearTimer);
|
this.on("error", clearTimer);
|
||||||
this.on("response", clearTimer);
|
this.on("response", clearTimer);
|
||||||
|
this.on("close", clearTimer);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -268,8 +310,7 @@ RedirectableRequest.prototype._performRequest = function () {
|
|||||||
var protocol = this._options.protocol;
|
var protocol = this._options.protocol;
|
||||||
var nativeProtocol = this._options.nativeProtocols[protocol];
|
var nativeProtocol = this._options.nativeProtocols[protocol];
|
||||||
if (!nativeProtocol) {
|
if (!nativeProtocol) {
|
||||||
this.emit("error", new TypeError("Unsupported protocol " + protocol));
|
throw new TypeError("Unsupported protocol " + protocol);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If specified, use the agent corresponding to the protocol
|
// If specified, use the agent corresponding to the protocol
|
||||||
@@ -361,15 +402,14 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The response is a redirect, so abort the current request
|
// The response is a redirect, so abort the current request
|
||||||
abortRequest(this._currentRequest);
|
destroyRequest(this._currentRequest);
|
||||||
// Discard the remainder of the response to avoid waiting for data
|
// Discard the remainder of the response to avoid waiting for data
|
||||||
response.destroy();
|
response.destroy();
|
||||||
|
|
||||||
// RFC7231§6.4: A client SHOULD detect and intervene
|
// RFC7231§6.4: A client SHOULD detect and intervene
|
||||||
// in cyclical redirections (i.e., "infinite" redirection loops).
|
// in cyclical redirections (i.e., "infinite" redirection loops).
|
||||||
if (++this._redirectCount > this._options.maxRedirects) {
|
if (++this._redirectCount > this._options.maxRedirects) {
|
||||||
this.emit("error", new TooManyRedirectsError());
|
throw new TooManyRedirectsError();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the request headers if applicable
|
// Store the request headers if applicable
|
||||||
@@ -403,33 +443,23 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|||||||
var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
|
var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
|
||||||
|
|
||||||
// If the redirect is relative, carry over the host of the last request
|
// If the redirect is relative, carry over the host of the last request
|
||||||
var currentUrlParts = url.parse(this._currentUrl);
|
var currentUrlParts = parseUrl(this._currentUrl);
|
||||||
var currentHost = currentHostHeader || currentUrlParts.host;
|
var currentHost = currentHostHeader || currentUrlParts.host;
|
||||||
var currentUrl = /^\w+:/.test(location) ? this._currentUrl :
|
var currentUrl = /^\w+:/.test(location) ? this._currentUrl :
|
||||||
url.format(Object.assign(currentUrlParts, { host: currentHost }));
|
url.format(Object.assign(currentUrlParts, { host: currentHost }));
|
||||||
|
|
||||||
// Determine the URL of the redirection
|
|
||||||
var redirectUrl;
|
|
||||||
try {
|
|
||||||
redirectUrl = url.resolve(currentUrl, location);
|
|
||||||
}
|
|
||||||
catch (cause) {
|
|
||||||
this.emit("error", new RedirectionError({ cause: cause }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the redirected request
|
// Create the redirected request
|
||||||
debug("redirecting to", redirectUrl);
|
var redirectUrl = resolveUrl(location, currentUrl);
|
||||||
|
debug("redirecting to", redirectUrl.href);
|
||||||
this._isRedirect = true;
|
this._isRedirect = true;
|
||||||
var redirectUrlParts = url.parse(redirectUrl);
|
spreadUrlObject(redirectUrl, this._options);
|
||||||
Object.assign(this._options, redirectUrlParts);
|
|
||||||
|
|
||||||
// Drop confidential headers when redirecting to a less secure protocol
|
// Drop confidential headers when redirecting to a less secure protocol
|
||||||
// or to a different domain that is not a superdomain
|
// or to a different domain that is not a superdomain
|
||||||
if (redirectUrlParts.protocol !== currentUrlParts.protocol &&
|
if (redirectUrl.protocol !== currentUrlParts.protocol &&
|
||||||
redirectUrlParts.protocol !== "https:" ||
|
redirectUrl.protocol !== "https:" ||
|
||||||
redirectUrlParts.host !== currentHost &&
|
redirectUrl.host !== currentHost &&
|
||||||
!isSubdomain(redirectUrlParts.host, currentHost)) {
|
!isSubdomain(redirectUrl.host, currentHost)) {
|
||||||
removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers);
|
removeMatchingHeaders(/^(?:authorization|cookie)$/i, this._options.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,23 +474,12 @@ RedirectableRequest.prototype._processResponse = function (response) {
|
|||||||
method: method,
|
method: method,
|
||||||
headers: requestHeaders,
|
headers: requestHeaders,
|
||||||
};
|
};
|
||||||
try {
|
beforeRedirect(this._options, responseDetails, requestDetails);
|
||||||
beforeRedirect(this._options, responseDetails, requestDetails);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
this.emit("error", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._sanitizeOptions(this._options);
|
this._sanitizeOptions(this._options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the redirected request
|
// Perform the redirected request
|
||||||
try {
|
this._performRequest();
|
||||||
this._performRequest();
|
|
||||||
}
|
|
||||||
catch (cause) {
|
|
||||||
this.emit("error", new RedirectionError({ cause: cause }));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wraps the key/value object of protocols with redirect functionality
|
// Wraps the key/value object of protocols with redirect functionality
|
||||||
@@ -480,27 +499,16 @@ function wrap(protocols) {
|
|||||||
|
|
||||||
// Executes a request, following redirects
|
// Executes a request, following redirects
|
||||||
function request(input, options, callback) {
|
function request(input, options, callback) {
|
||||||
// Parse parameters
|
// Parse parameters, ensuring that input is an object
|
||||||
if (isString(input)) {
|
if (isURL(input)) {
|
||||||
var parsed;
|
input = spreadUrlObject(input);
|
||||||
try {
|
|
||||||
parsed = urlToOptions(new URL(input));
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
/* istanbul ignore next */
|
|
||||||
parsed = url.parse(input);
|
|
||||||
}
|
|
||||||
if (!isString(parsed.protocol)) {
|
|
||||||
throw new InvalidUrlError({ input });
|
|
||||||
}
|
|
||||||
input = parsed;
|
|
||||||
}
|
}
|
||||||
else if (URL && (input instanceof URL)) {
|
else if (isString(input)) {
|
||||||
input = urlToOptions(input);
|
input = spreadUrlObject(parseUrl(input));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = input;
|
options = validateUrl(input);
|
||||||
input = { protocol: protocol };
|
input = { protocol: protocol };
|
||||||
}
|
}
|
||||||
if (isFunction(options)) {
|
if (isFunction(options)) {
|
||||||
@@ -539,27 +547,57 @@ function wrap(protocols) {
|
|||||||
return exports;
|
return exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
function noop() { /* empty */ }
|
function noop() { /* empty */ }
|
||||||
|
|
||||||
// from https://github.com/nodejs/node/blob/master/lib/internal/url.js
|
function parseUrl(input) {
|
||||||
function urlToOptions(urlObject) {
|
var parsed;
|
||||||
var options = {
|
/* istanbul ignore else */
|
||||||
protocol: urlObject.protocol,
|
if (useNativeURL) {
|
||||||
hostname: urlObject.hostname.startsWith("[") ?
|
parsed = new URL(input);
|
||||||
/* istanbul ignore next */
|
|
||||||
urlObject.hostname.slice(1, -1) :
|
|
||||||
urlObject.hostname,
|
|
||||||
hash: urlObject.hash,
|
|
||||||
search: urlObject.search,
|
|
||||||
pathname: urlObject.pathname,
|
|
||||||
path: urlObject.pathname + urlObject.search,
|
|
||||||
href: urlObject.href,
|
|
||||||
};
|
|
||||||
if (urlObject.port !== "") {
|
|
||||||
options.port = Number(urlObject.port);
|
|
||||||
}
|
}
|
||||||
return options;
|
else {
|
||||||
|
// Ensure the URL is valid and absolute
|
||||||
|
parsed = validateUrl(url.parse(input));
|
||||||
|
if (!isString(parsed.protocol)) {
|
||||||
|
throw new InvalidUrlError({ input });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveUrl(relative, base) {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
return useNativeURL ? new URL(relative, base) : parseUrl(url.resolve(base, relative));
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateUrl(input) {
|
||||||
|
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||||
|
throw new InvalidUrlError({ input: input.href || input });
|
||||||
|
}
|
||||||
|
if (/^\[/.test(input.host) && !/^\[[:0-9a-f]+\](:\d+)?$/i.test(input.host)) {
|
||||||
|
throw new InvalidUrlError({ input: input.href || input });
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
function spreadUrlObject(urlObject, target) {
|
||||||
|
var spread = target || {};
|
||||||
|
for (var key of preservedUrlFields) {
|
||||||
|
spread[key] = urlObject[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix IPv6 hostname
|
||||||
|
if (spread.hostname.startsWith("[")) {
|
||||||
|
spread.hostname = spread.hostname.slice(1, -1);
|
||||||
|
}
|
||||||
|
// Ensure port is a number
|
||||||
|
if (spread.port !== "") {
|
||||||
|
spread.port = Number(spread.port);
|
||||||
|
}
|
||||||
|
// Concatenate path
|
||||||
|
spread.path = spread.search ? spread.pathname + spread.search : spread.pathname;
|
||||||
|
|
||||||
|
return spread;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeMatchingHeaders(regex, headers) {
|
function removeMatchingHeaders(regex, headers) {
|
||||||
@@ -585,17 +623,25 @@ function createErrorType(code, message, baseClass) {
|
|||||||
|
|
||||||
// Attach constructor and set default properties
|
// Attach constructor and set default properties
|
||||||
CustomError.prototype = new (baseClass || Error)();
|
CustomError.prototype = new (baseClass || Error)();
|
||||||
CustomError.prototype.constructor = CustomError;
|
Object.defineProperties(CustomError.prototype, {
|
||||||
CustomError.prototype.name = "Error [" + code + "]";
|
constructor: {
|
||||||
|
value: CustomError,
|
||||||
|
enumerable: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
value: "Error [" + code + "]",
|
||||||
|
enumerable: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
return CustomError;
|
return CustomError;
|
||||||
}
|
}
|
||||||
|
|
||||||
function abortRequest(request) {
|
function destroyRequest(request, error) {
|
||||||
for (var event of events) {
|
for (var event of events) {
|
||||||
request.removeListener(event, eventHandlers[event]);
|
request.removeListener(event, eventHandlers[event]);
|
||||||
}
|
}
|
||||||
request.on("error", noop);
|
request.on("error", noop);
|
||||||
request.abort();
|
request.destroy(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSubdomain(subdomain, domain) {
|
function isSubdomain(subdomain, domain) {
|
||||||
@@ -616,6 +662,10 @@ function isBuffer(value) {
|
|||||||
return typeof value === "object" && ("length" in value);
|
return typeof value === "object" && ("length" in value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isURL(value) {
|
||||||
|
return URL && value instanceof URL;
|
||||||
|
}
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
module.exports = wrap({ http: http, https: https });
|
module.exports = wrap({ http: http, https: https });
|
||||||
module.exports.wrap = wrap;
|
module.exports.wrap = wrap;
|
||||||
|
|||||||
5
3 proba/node_modules/follow-redirects/package.json
generated
vendored
5
3 proba/node_modules/follow-redirects/package.json
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "follow-redirects",
|
"name": "follow-redirects",
|
||||||
"version": "1.15.2",
|
"version": "1.15.4",
|
||||||
"description": "HTTP and HTTPS modules that follow redirects.",
|
"description": "HTTP and HTTPS modules that follow redirects.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
@@ -11,9 +11,8 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run lint && npm run mocha",
|
|
||||||
"lint": "eslint *.js test",
|
"lint": "eslint *.js test",
|
||||||
"mocha": "nyc mocha"
|
"test": "nyc mocha"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
2
3 proba/node_modules/nanoid/README.md
generated
vendored
2
3 proba/node_modules/nanoid/README.md
generated
vendored
@@ -36,4 +36,4 @@ Supports modern browsers, IE [with Babel], Node.js and React Native.
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
Read **[full docs](https://github.com/ai/nanoid#readme)** on GitHub.
|
Read full docs **[here](https://github.com/ai/nanoid#readme)**.
|
||||||
|
|||||||
91
3 proba/node_modules/nanoid/index.d.cts
generated
vendored
Normal file
91
3 proba/node_modules/nanoid/index.d.cts
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Generate secure URL-friendly unique ID.
|
||||||
|
*
|
||||||
|
* By default, the ID will have 21 symbols to have a collision probability
|
||||||
|
* similar to UUID v4.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { nanoid } from 'nanoid'
|
||||||
|
* model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL"
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param size Size of the ID. The default size is 21.
|
||||||
|
* @returns A random string.
|
||||||
|
*/
|
||||||
|
export function nanoid(size?: number): string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate secure unique ID with custom alphabet.
|
||||||
|
*
|
||||||
|
* Alphabet must contain 256 symbols or less. Otherwise, the generator
|
||||||
|
* will not be secure.
|
||||||
|
*
|
||||||
|
* @param alphabet Alphabet used to generate the ID.
|
||||||
|
* @param defaultSize Size of the ID. The default size is 21.
|
||||||
|
* @returns A random string generator.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const { customAlphabet } = require('nanoid')
|
||||||
|
* const nanoid = customAlphabet('0123456789абвгдеё', 5)
|
||||||
|
* nanoid() //=> "8ё56а"
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function customAlphabet(
|
||||||
|
alphabet: string,
|
||||||
|
defaultSize?: number
|
||||||
|
): (size?: number) => string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate unique ID with custom random generator and alphabet.
|
||||||
|
*
|
||||||
|
* Alphabet must contain 256 symbols or less. Otherwise, the generator
|
||||||
|
* will not be secure.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { customRandom } from 'nanoid/format'
|
||||||
|
*
|
||||||
|
* const nanoid = customRandom('abcdef', 5, size => {
|
||||||
|
* const random = []
|
||||||
|
* for (let i = 0; i < size; i++) {
|
||||||
|
* random.push(randomByte())
|
||||||
|
* }
|
||||||
|
* return random
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* nanoid() //=> "fbaef"
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param alphabet Alphabet used to generate a random string.
|
||||||
|
* @param size Size of the random string.
|
||||||
|
* @param random A random bytes generator.
|
||||||
|
* @returns A random string generator.
|
||||||
|
*/
|
||||||
|
export function customRandom(
|
||||||
|
alphabet: string,
|
||||||
|
size: number,
|
||||||
|
random: (bytes: number) => Uint8Array
|
||||||
|
): () => string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL safe symbols.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { urlAlphabet } from 'nanoid'
|
||||||
|
* const nanoid = customAlphabet(urlAlphabet, 10)
|
||||||
|
* nanoid() //=> "Uakgb_J5m9"
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const urlAlphabet: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an array of random bytes collected from hardware noise.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { customRandom, random } from 'nanoid'
|
||||||
|
* const nanoid = customRandom("abcdef", 5, random)
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param bytes Size of the array.
|
||||||
|
* @returns An array of random bytes.
|
||||||
|
*/
|
||||||
|
export function random(bytes: number): Uint8Array
|
||||||
44
3 proba/node_modules/nanoid/package.json
generated
vendored
44
3 proba/node_modules/nanoid/package.json
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nanoid",
|
"name": "nanoid",
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"description": "A tiny (116 bytes), secure URL-friendly unique string ID generator",
|
"description": "A tiny (116 bytes), secure URL-friendly unique string ID generator",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"uuid",
|
"uuid",
|
||||||
@@ -35,31 +35,53 @@
|
|||||||
"module": "index.js",
|
"module": "index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./index.d.ts",
|
|
||||||
"browser": "./index.browser.js",
|
"browser": "./index.browser.js",
|
||||||
"require": "./index.cjs",
|
"require": {
|
||||||
"import": "./index.js",
|
"types": "./index.d.cts",
|
||||||
|
"default": "./index.cjs"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"default": "./index.js"
|
||||||
|
},
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
"./index.d.ts": "./index.d.ts",
|
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
"./async/package.json": "./async/package.json",
|
"./async/package.json": "./async/package.json",
|
||||||
"./async": {
|
"./async": {
|
||||||
"browser": "./async/index.browser.js",
|
"browser": "./async/index.browser.js",
|
||||||
"require": "./async/index.cjs",
|
"require": {
|
||||||
"import": "./async/index.js",
|
"types": "./index.d.cts",
|
||||||
|
"default": "./async/index.cjs"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"default": "./async/index.js"
|
||||||
|
},
|
||||||
"default": "./async/index.js"
|
"default": "./async/index.js"
|
||||||
},
|
},
|
||||||
"./non-secure/package.json": "./non-secure/package.json",
|
"./non-secure/package.json": "./non-secure/package.json",
|
||||||
"./non-secure": {
|
"./non-secure": {
|
||||||
"require": "./non-secure/index.cjs",
|
"require": {
|
||||||
"import": "./non-secure/index.js",
|
"types": "./index.d.cts",
|
||||||
|
"default": "./non-secure/index.cjs"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"default": "./non-secure/index.js"
|
||||||
|
},
|
||||||
"default": "./non-secure/index.js"
|
"default": "./non-secure/index.js"
|
||||||
},
|
},
|
||||||
"./url-alphabet/package.json": "./url-alphabet/package.json",
|
"./url-alphabet/package.json": "./url-alphabet/package.json",
|
||||||
"./url-alphabet": {
|
"./url-alphabet": {
|
||||||
"require": "./url-alphabet/index.cjs",
|
"require": {
|
||||||
"import": "./url-alphabet/index.js",
|
"types": "./index.d.cts",
|
||||||
|
"default": "./url-alphabet/index.cjs"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"default": "./url-alphabet/index.js"
|
||||||
|
},
|
||||||
"default": "./url-alphabet/index.js"
|
"default": "./url-alphabet/index.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
3 proba/node_modules/postcss/README.md
generated
vendored
2
3 proba/node_modules/postcss/README.md
generated
vendored
@@ -13,7 +13,7 @@ and JetBrains. The [Autoprefixer] and [Stylelint] PostCSS plugins is one of
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" /> Made in <b><a href="https://evilmartians.com/?utm_source=postcss&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.
|
<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="" width="22" height="16" /> Made in <b><a href="https://evilmartians.com/devtools?utm_source=postcss&utm_campaign=devtools-button&utm_medium=github">Evil Martians</a></b>, product consulting for <b>developer tools</b>.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
5
3 proba/node_modules/postcss/lib/map-generator.js
generated
vendored
5
3 proba/node_modules/postcss/lib/map-generator.js
generated
vendored
@@ -16,6 +16,7 @@ class MapGenerator {
|
|||||||
this.root = root
|
this.root = root
|
||||||
this.opts = opts
|
this.opts = opts
|
||||||
this.css = cssString
|
this.css = cssString
|
||||||
|
this.originalCSS = cssString
|
||||||
this.usesFileUrls = !this.mapOpts.from && this.mapOpts.absolute
|
this.usesFileUrls = !this.mapOpts.from && this.mapOpts.absolute
|
||||||
|
|
||||||
this.memoizedFileURLs = new Map()
|
this.memoizedFileURLs = new Map()
|
||||||
@@ -74,7 +75,7 @@ class MapGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (this.css) {
|
} else if (this.css) {
|
||||||
this.css = this.css.replace(/(\n)?\/\*#[\S\s]*?\*\/$/gm, '')
|
this.css = this.css.replace(/\n*?\/\*#[\S\s]*?\*\/$/gm, '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +277,7 @@ class MapGenerator {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let input = new Input(this.css, this.opts)
|
let input = new Input(this.originalCSS, this.opts)
|
||||||
if (input.map) this.previousMaps.push(input.map)
|
if (input.map) this.previousMaps.push(input.map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
3 proba/node_modules/postcss/lib/no-work-result.js
generated
vendored
3
3 proba/node_modules/postcss/lib/no-work-result.js
generated
vendored
@@ -37,6 +37,9 @@ class NoWorkResult {
|
|||||||
if (generatedMap) {
|
if (generatedMap) {
|
||||||
this.result.map = generatedMap
|
this.result.map = generatedMap
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
map.clearAnnotation();
|
||||||
|
this.result.css = map.css;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
3 proba/node_modules/postcss/lib/postcss.d.ts
generated
vendored
2
3 proba/node_modules/postcss/lib/postcss.d.ts
generated
vendored
@@ -309,7 +309,7 @@ declare namespace postcss {
|
|||||||
* The path of the CSS source file. You should always set `from`,
|
* The path of the CSS source file. You should always set `from`,
|
||||||
* because it is used in source map generation and syntax error messages.
|
* because it is used in source map generation and syntax error messages.
|
||||||
*/
|
*/
|
||||||
from?: string
|
from?: string | undefined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source map options
|
* Source map options
|
||||||
|
|||||||
10
3 proba/node_modules/postcss/lib/processor.js
generated
vendored
10
3 proba/node_modules/postcss/lib/processor.js
generated
vendored
@@ -7,7 +7,7 @@ let Root = require('./root')
|
|||||||
|
|
||||||
class Processor {
|
class Processor {
|
||||||
constructor(plugins = []) {
|
constructor(plugins = []) {
|
||||||
this.version = '8.4.30'
|
this.version = '8.4.33'
|
||||||
this.plugins = this.normalize(plugins)
|
this.plugins = this.normalize(plugins)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ class Processor {
|
|||||||
|
|
||||||
process(css, opts = {}) {
|
process(css, opts = {}) {
|
||||||
if (
|
if (
|
||||||
this.plugins.length === 0 &&
|
!this.plugins.length &&
|
||||||
typeof opts.parser === 'undefined' &&
|
!opts.parser &&
|
||||||
typeof opts.stringifier === 'undefined' &&
|
!opts.stringifier &&
|
||||||
typeof opts.syntax === 'undefined'
|
!opts.syntax
|
||||||
) {
|
) {
|
||||||
return new NoWorkResult(this, css, opts)
|
return new NoWorkResult(this, css, opts)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
2
3 proba/node_modules/postcss/lib/tokenize.js
generated
vendored
2
3 proba/node_modules/postcss/lib/tokenize.js
generated
vendored
@@ -22,7 +22,7 @@ const AT = '@'.charCodeAt(0)
|
|||||||
|
|
||||||
const RE_AT_END = /[\t\n\f\r "#'()/;[\\\]{}]/g
|
const RE_AT_END = /[\t\n\f\r "#'()/;[\\\]{}]/g
|
||||||
const RE_WORD_END = /[\t\n\f\r !"#'():;@[\\\]{}]|\/(?=\*)/g
|
const RE_WORD_END = /[\t\n\f\r !"#'():;@[\\\]{}]|\/(?=\*)/g
|
||||||
const RE_BAD_BRACKET = /.[\n"'(/\\]/
|
const RE_BAD_BRACKET = /.[\r\n"'(/\\]/
|
||||||
const RE_HEX_ESCAPE = /[\da-f]/i
|
const RE_HEX_ESCAPE = /[\da-f]/i
|
||||||
|
|
||||||
module.exports = function tokenizer(input, options = {}) {
|
module.exports = function tokenizer(input, options = {}) {
|
||||||
|
|||||||
4
3 proba/node_modules/postcss/package.json
generated
vendored
4
3 proba/node_modules/postcss/package.json
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "postcss",
|
"name": "postcss",
|
||||||
"version": "8.4.30",
|
"version": "8.4.33",
|
||||||
"description": "Tool for transforming styles with JS plugins",
|
"description": "Tool for transforming styles with JS plugins",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
"url": "https://github.com/postcss/postcss/issues"
|
"url": "https://github.com/postcss/postcss/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
|||||||
40
3 proba/package-lock.json
generated
40
3 proba/package-lock.json
generated
@@ -2031,9 +2031,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.4",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3123,9 +3123,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3596,9 +3596,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.30",
|
"version": "8.4.33",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||||
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
|
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3615,7 +3615,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
@@ -6058,9 +6058,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.4",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"for-each": {
|
"for-each": {
|
||||||
@@ -6866,9 +6866,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"natural-compare": {
|
"natural-compare": {
|
||||||
@@ -7216,12 +7216,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.30",
|
"version": "8.4.33",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||||
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
|
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,13 +50,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center">
|
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center fixed-bottom">
|
||||||
Жирнова Алена ПИбд-21
|
Жирнова Алена ПИбд-21
|
||||||
</footer>
|
</footer>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import validation from "./scripts/validation";
|
import validation from "./js/validation";
|
||||||
import { linesForm } from "./scripts/lines";
|
import { linesForm } from "./js/lines";
|
||||||
import {linesFormOnIndex} from "./scripts/lines";
|
import {linesFormOnIndex} from "./js/lines";
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
validation();
|
validation();
|
||||||
linesFormOnIndex();
|
linesFormOnIndex();
|
||||||
|
|||||||
@@ -37,146 +37,94 @@
|
|||||||
<button id="items-add" type="submit" class="btn btn-success">
|
<button id="items-add" type="submit" class="btn btn-success">
|
||||||
Добавить книгу (диалог)
|
Добавить книгу (диалог)
|
||||||
</button>
|
</button>
|
||||||
<a class="btn btn-secondary" href="/page-edit.html"
|
|
||||||
>Добавить книгу (страница)</a
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<table id="items-table" class="table table-light table-striped">
|
<table id="items-table" class="table table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<th scope="col">№</th>
|
<th scope="col">№</th>
|
||||||
<th scope="col" class="w-25">Жанр</th>
|
<th scope="col" class="w-25">Название</th>
|
||||||
<th scope="col" class="w-25">Автор</th>
|
<th scope="col" class="w-25">Автор</th>
|
||||||
<th scope="col" class="w-25">Название</th>
|
<th scope="col" class="w-25">Жанр</th>
|
||||||
<th scope="col" class="w-25">Описание</th>
|
<th scope="col" class="w-15">Год выпуска</th>
|
||||||
<th scope="col" class="w-25">Количество</th>
|
<th scope="col" class="w-25">Описание</th>
|
||||||
<th scope="col" class="w-25">Дата</th>
|
<th scope="col" class="w-25">Кол-во</th>
|
||||||
<th scope="col"></th>
|
<th scope="col"></th>
|
||||||
<th scope="col"></th>
|
<th scope="col"></th>
|
||||||
<th scope="col"></th>
|
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</div>
|
||||||
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center fixed-bottom">
|
|
||||||
Жирнова Алена ПИбд-21
|
<footer class="footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center fixed-bottom">
|
||||||
</footer>
|
Жирнова Алена ПИбд-21
|
||||||
<div
|
</footer>
|
||||||
id="items-update"
|
|
||||||
class="modal fade"
|
|
||||||
tabindex="-1"
|
<div id="items-update" class="modal fade" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||||
data-bs-backdrop="static"
|
<div class="modal-dialog">
|
||||||
data-bs-keyboard="false"
|
|
||||||
>
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<form id="items-form" class="needs-validation" novalidate>
|
<form id="items-form" class="needs-validation" novalidate>
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h1 class="modal-title fs-5" id="items-update-title"></h1>
|
<h1 class="modal-title fs-5" id="items-update-title"></h1>
|
||||||
<button
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
type="button"
|
</div>
|
||||||
class="btn-close"
|
<div class="modal-body">
|
||||||
data-bs-dismiss="modal"
|
<div class="text-center">
|
||||||
aria-label="Close"
|
<img id="image-preview" src="https://via.placeholder.com/200" class="rounded"
|
||||||
></button>
|
alt="placeholder">
|
||||||
|
</div>
|
||||||
|
<input id="items-line-id" type="number" hidden>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="nameBook" class="form-label">Название</label>
|
||||||
|
<input id="nameBook" class="form-control" name="nameBook" type="text" required="">
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="author" class="form-label">Автор</label>
|
||||||
|
<select id="author" class="form-select" name="author" required>
|
||||||
|
</div>
|
||||||
|
<input id="genres-line-id" type="number" hidden>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="genre" class="form-label">Жанр</label>
|
||||||
|
<select id="genre" class="form-select" name="genre" required>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="description" class="form-label">Описание</label>
|
||||||
|
<input id="description" class="form-control" name="description" type="text" required="">
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="yearPicker" class="form-label">Год выпуска</label>
|
||||||
|
<input id="yearPicker" class="form-control" name="yearPicker" type="text" required="">
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="count" class="form-label">Количество книг</label>
|
||||||
|
<input
|
||||||
|
id="count"
|
||||||
|
name="count"
|
||||||
|
class="form-control"
|
||||||
|
type="number"
|
||||||
|
value="0"
|
||||||
|
min="1"
|
||||||
|
step="1"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="image" class="form-label">Изображение</label>
|
||||||
|
<input id="image" type="file" name="image" class="form-control" accept="image/*">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Сохранить</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
</form>
|
||||||
<div class="text-center">
|
</div>
|
||||||
<img
|
</div>
|
||||||
id="image-preview"
|
</form>
|
||||||
src="https://via.placeholder.com/200"
|
</div>
|
||||||
class="rounded rounded-circle"
|
</div>
|
||||||
alt="placeholder"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<input id="items-line-id" type="number" hidden />
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="item" class="form-label">Жанр</label>
|
|
||||||
<select
|
|
||||||
id="item"
|
|
||||||
class="form-select"
|
|
||||||
name="selected"
|
|
||||||
required
|
|
||||||
></select>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="author" class="form-label">Автор</label>
|
|
||||||
<select
|
|
||||||
id="author"
|
|
||||||
class="form-select"
|
|
||||||
name="selected"
|
|
||||||
required>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="name" class="form-label">Название</label>
|
|
||||||
<input
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
class="form-control"
|
|
||||||
type="text"
|
|
||||||
maxlength="100"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="desc" class="form-label">Описание</label>
|
|
||||||
<input
|
|
||||||
id="desc"
|
|
||||||
name="desc"
|
|
||||||
class="form-control"
|
|
||||||
type="text"
|
|
||||||
maxlength="100"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="count" class="form-label">Количество книг</label>
|
|
||||||
<input
|
|
||||||
id="count"
|
|
||||||
name="count"
|
|
||||||
class="form-control"
|
|
||||||
type="number"
|
|
||||||
value="0"
|
|
||||||
min="1"
|
|
||||||
step="1"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="date" class="form-label">Дата</label>
|
|
||||||
<input
|
|
||||||
id="date"
|
|
||||||
name="date"
|
|
||||||
class="form-control"
|
|
||||||
type="date"
|
|
||||||
value="2022-01-01"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="image" class="form-label">Изображение</label>
|
|
||||||
<input
|
|
||||||
id="image"
|
|
||||||
type="file"
|
|
||||||
name="image"
|
|
||||||
class="form-control"
|
|
||||||
accept="image/*"
|
|
||||||
/>
|
|
||||||
</div></div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="submit-grey"
|
|
||||||
class="btn btn-secondary"
|
|
||||||
data-bs-dismiss="modal"
|
|
||||||
>
|
|
||||||
Закрыть
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-success">Сохранить</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import validation from "./js/validation";
|
import validation from "./js/validation";
|
||||||
import { linesForm } from "./js/lines";
|
import { linesForm } from "./js/lines";
|
||||||
|
|||||||
Reference in New Issue
Block a user