NoteJS/public/pwa.js
Fovway d89a617264 Добавлены функции для работы с AI настройками и улучшения текста
- Реализованы API для сохранения и получения AI настроек пользователя, включая OpenAI API ключ, базовый URL и модель.
- Добавлена возможность окончательного удаления всех архивных заметок с подтверждением пароля.
- Внедрена функция улучшения текста через AI, с обработкой запросов к OpenAI API.
- Обновлены интерфейсы для работы с AI настройками и добавлены уведомления для улучшения пользовательского опыта.
2025-10-26 14:45:02 +07:00

410 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Универсальная функция для модальных окон подтверждения
function showConfirmModal(title, message, options = {}) {
return new Promise((resolve) => {
// Создаем модальное окно
const modal = document.createElement("div");
modal.className = "modal";
modal.style.display = "block";
// Создаем содержимое модального окна
const modalContent = document.createElement("div");
modalContent.className = "modal-content";
// Создаем заголовок
const modalHeader = document.createElement("div");
modalHeader.className = "modal-header";
modalHeader.innerHTML = `
<h3>${title}</h3>
<span class="modal-close">&times;</span>
`;
// Создаем тело модального окна
const modalBody = document.createElement("div");
modalBody.className = "modal-body";
modalBody.innerHTML = `<p>${message}</p>`;
// Создаем футер с кнопками
const modalFooter = document.createElement("div");
modalFooter.className = "modal-footer";
modalFooter.innerHTML = `
<button id="confirmBtn" class="${
options.confirmType === "danger" ? "btn-danger" : "btn-primary"
}" style="margin-right: 10px">
${options.confirmText || "OK"}
</button>
<button id="cancelBtn" class="btn-secondary">
${options.cancelText || "Отмена"}
</button>
`;
// Собираем модальное окно
modalContent.appendChild(modalHeader);
modalContent.appendChild(modalBody);
modalContent.appendChild(modalFooter);
modal.appendChild(modalContent);
// Добавляем на страницу
document.body.appendChild(modal);
// Функция закрытия
function closeModal() {
modal.style.display = "none";
if (modal.parentNode) {
modal.parentNode.removeChild(modal);
}
}
// Обработчики событий
const closeBtn = modalHeader.querySelector(".modal-close");
const cancelBtn = modalFooter.querySelector("#cancelBtn");
const confirmBtn = modalFooter.querySelector("#confirmBtn");
closeBtn.addEventListener("click", () => {
closeModal();
resolve(false);
});
cancelBtn.addEventListener("click", () => {
closeModal();
resolve(false);
});
confirmBtn.addEventListener("click", () => {
closeModal();
resolve(true);
});
// Закрытие при клике вне модального окна
modal.addEventListener("click", (e) => {
if (e.target === modal) {
closeModal();
resolve(false);
}
});
// Закрытие по Escape
const handleEscape = (e) => {
if (e.key === "Escape") {
closeModal();
resolve(false);
document.removeEventListener("keydown", handleEscape);
}
};
document.addEventListener("keydown", handleEscape);
});
}
// PWA Service Worker Registration
class PWAManager {
constructor() {
this.init();
}
init() {
console.log("PWA Manager инициализирован");
this.registerServiceWorker();
this.checkPWARequirements();
this.setupServiceWorkerMessages();
}
// Проверка требований PWA
checkPWARequirements() {
console.log("Проверка требований PWA:");
console.log("- Service Worker:", "serviceWorker" in navigator);
console.log(
"- HTTPS:",
location.protocol === "https:" || location.hostname === "localhost"
);
console.log(
"- Manifest:",
document.querySelector('link[rel="manifest"]') !== null
);
console.log(
"- Icons:",
document.querySelector('link[rel="icon"]') !== null
);
}
// Регистрация Service Worker
registerServiceWorker() {
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/sw.js")
.then((registration) => {
console.log("SW зарегистрирован успешно:", registration.scope);
// Проверяем обновления
registration.addEventListener("updatefound", () => {
const newWorker = registration.installing;
newWorker.addEventListener("statechange", () => {
if (
newWorker.state === "installed" &&
navigator.serviceWorker.controller
) {
this.showUpdateNotification();
}
});
});
})
.catch((error) => {
console.log("Ошибка регистрации SW:", error);
});
});
} else {
console.log("Service Worker не поддерживается");
}
}
// Показ уведомления об обновлении
async showUpdateNotification() {
const confirmed = await showConfirmModal(
"Обновление приложения",
"Доступна новая версия приложения. Обновить?",
{ confirmText: "Обновить" }
);
if (confirmed) {
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({
type: "SKIP_WAITING",
});
}
window.location.reload();
}
}
// Проверка на мобильное устройство
isMobileDevice() {
const ua = navigator.userAgent;
return (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
ua
) ||
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2) ||
window.matchMedia("(max-width: 768px)").matches ||
/Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua)
);
}
// Принудительное обновление кэша
async forceUpdateCache() {
console.log("Принудительное обновление кэша...");
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
try {
// Отправляем сообщение Service Worker для обновления кэша
navigator.serviceWorker.controller.postMessage({
type: "FORCE_UPDATE_CACHE",
});
console.log("Запрос на обновление кэша отправлен");
return true;
} catch (error) {
console.error("Ошибка при обновлении кэша:", error);
return false;
}
} else {
console.log("Service Worker не доступен");
return false;
}
}
// Полная очистка кэша
async clearAllCache() {
console.log("Полная очистка кэша...");
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
try {
// Отправляем сообщение Service Worker для очистки кэша
navigator.serviceWorker.controller.postMessage({
type: "CLEAR_ALL_CACHE",
});
console.log("Запрос на очистку кэша отправлен");
return true;
} catch (error) {
console.error("Ошибка при очистке кэша:", error);
return false;
}
} else {
console.log("Service Worker не доступен");
return false;
}
}
// Получение версии кэша
async getCacheVersion() {
return new Promise((resolve) => {
if ("serviceWorker" in navigator && navigator.serviceWorker.controller) {
const messageChannel = new MessageChannel();
messageChannel.port1.onmessage = (event) => {
resolve(event.data.version || "Неизвестно");
};
navigator.serviceWorker.controller.postMessage(
{ type: "GET_VERSION" },
[messageChannel.port2]
);
} else {
resolve("Service Worker не доступен");
}
});
}
// Проверка обновлений и принудительное обновление
async checkForUpdates() {
console.log("Проверка обновлений...");
if ("serviceWorker" in navigator) {
try {
const registration = await navigator.serviceWorker.getRegistration();
if (registration) {
await registration.update();
console.log("Проверка обновлений завершена");
return true;
}
} catch (error) {
console.error("Ошибка при проверке обновлений:", error);
return false;
}
}
return false;
}
// Настройка обработки сообщений от Service Worker
setupServiceWorkerMessages() {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", (event) => {
console.log("Получено сообщение от SW:", event.data);
switch (event.data.type) {
case "CACHE_UPDATED":
console.log("Кэш обновлен до версии:", event.data.version);
this.showNotification("Кэш успешно обновлен!", "success");
break;
case "CACHE_CLEARED":
console.log("Кэш полностью очищен");
this.showNotification("Кэш полностью очищен!", "info");
break;
}
});
}
}
// Показ уведомления
showNotification(message, type = "info") {
// Создаем уведомление
const notification = document.createElement("div");
notification.className = `pwa-notification pwa-notification-${type}`;
notification.textContent = message;
// Стили для уведомления
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 20px;
border-radius: 8px;
color: white;
font-weight: bold;
z-index: 10000;
max-width: 300px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
transform: translateX(100%);
transition: transform 0.3s ease;
`;
// Цвета для разных типов уведомлений
switch (type) {
case "success":
notification.style.backgroundColor = "#28a745";
break;
case "error":
notification.style.backgroundColor = "#dc3545";
break;
case "warning":
notification.style.backgroundColor = "#ffc107";
notification.style.color = "#000";
break;
default:
notification.style.backgroundColor = "#007bff";
}
// Добавляем на страницу
document.body.appendChild(notification);
// Анимация появления
setTimeout(() => {
notification.style.transform = "translateX(0)";
}, 100);
// Автоматическое удаление через 3 секунды
setTimeout(() => {
notification.style.transform = "translateX(100%)";
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 3000);
}
}
// Инициализация PWA Manager
const pwaManager = new PWAManager();
// Экспорт для использования в других скриптах
window.PWAManager = pwaManager;
// Добавляем глобальные функции для управления кэшем
window.debugPWA = () => {
console.log("PWA Debug Info:", {
isOnline: navigator.onLine,
hasServiceWorker: "serviceWorker" in navigator,
userAgent: navigator.userAgent,
platform: navigator.platform,
language: navigator.language,
displayMode: window.matchMedia("(display-mode: standalone)").matches
? "standalone"
: "browser",
});
};
// Принудительное обновление кэша
window.updateCache = () => {
return pwaManager.forceUpdateCache();
};
// Полная очистка кэша
window.clearCache = () => {
return pwaManager.clearAllCache();
};
// Получение версии кэша
window.getCacheVersion = () => {
return pwaManager.getCacheVersion();
};
// Проверка обновлений
window.checkUpdates = () => {
return pwaManager.checkForUpdates();
};
// Комбинированная функция: проверка обновлений + принудительное обновление кэша
window.forceUpdate = async () => {
console.log("Принудительное обновление приложения...");
// Сначала проверяем обновления
await pwaManager.checkForUpdates();
// Затем принудительно обновляем кэш
await pwaManager.forceUpdateCache();
// Перезагружаем страницу
setTimeout(() => {
window.location.reload();
}, 1000);
};