- Реализованы функции для принудительного обновления кэша и полной очистки кэша в классе PWAManager. - Добавлены обработчики сообщений от сервисного работника для обновления кэша и очистки кэша. - Обновлен сервисный работник для поддержки новых функций управления кэшем и уведомлений о статусе кэша. - Добавлены глобальные функции для управления кэшем через интерфейс браузера.
395 lines
13 KiB
JavaScript
395 lines
13 KiB
JavaScript
// PWA Service Worker Registration и установка
|
||
class PWAManager {
|
||
constructor() {
|
||
this.deferredPrompt = null;
|
||
this.init();
|
||
}
|
||
|
||
init() {
|
||
console.log('PWA Manager инициализирован');
|
||
this.registerServiceWorker();
|
||
this.setupInstallPrompt();
|
||
this.setupAppInstalled();
|
||
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 не поддерживается');
|
||
}
|
||
}
|
||
|
||
// Показ уведомления об обновлении
|
||
showUpdateNotification() {
|
||
if (confirm('Доступна новая версия приложения. Обновить?')) {
|
||
if (navigator.serviceWorker.controller) {
|
||
navigator.serviceWorker.controller.postMessage({ type: 'SKIP_WAITING' });
|
||
}
|
||
window.location.reload();
|
||
}
|
||
}
|
||
|
||
// Настройка промпта установки
|
||
setupInstallPrompt() {
|
||
window.addEventListener('beforeinstallprompt', (e) => {
|
||
console.log('beforeinstallprompt событие получено');
|
||
e.preventDefault();
|
||
this.deferredPrompt = e;
|
||
this.showInstallButton();
|
||
});
|
||
}
|
||
|
||
// Показ кнопки установки
|
||
showInstallButton() {
|
||
console.log('Попытка показать кнопку установки');
|
||
|
||
// Проверяем, не установлено ли уже приложение
|
||
if (this.isPWAInstalled()) {
|
||
console.log('Приложение уже установлено');
|
||
return;
|
||
}
|
||
|
||
const installButton = this.createInstallButton();
|
||
this.addInstallButtonToPage(installButton);
|
||
}
|
||
|
||
// Создание кнопки установки
|
||
createInstallButton() {
|
||
const installButton = document.createElement('button');
|
||
installButton.textContent = '📱 Установить приложение';
|
||
installButton.className = 'btnSave';
|
||
installButton.style.marginTop = '10px';
|
||
installButton.style.width = '100%';
|
||
installButton.style.fontSize = '14px';
|
||
installButton.id = 'pwa-install-button';
|
||
|
||
installButton.addEventListener('click', () => {
|
||
this.installApp();
|
||
});
|
||
|
||
return installButton;
|
||
}
|
||
|
||
// Добавление кнопки на страницу
|
||
addInstallButtonToPage(installButton) {
|
||
// Удаляем существующую кнопку, если есть
|
||
const existingButton = document.getElementById('pwa-install-button');
|
||
if (existingButton) {
|
||
existingButton.remove();
|
||
}
|
||
|
||
// Ищем подходящее место для кнопки
|
||
const authLink = document.querySelector('.auth-link');
|
||
const footer = document.querySelector('.footer');
|
||
const container = document.querySelector('.container');
|
||
|
||
if (authLink) {
|
||
authLink.appendChild(installButton);
|
||
console.log('Кнопка установки добавлена в auth-link');
|
||
} else if (footer) {
|
||
footer.insertBefore(installButton, footer.firstChild);
|
||
console.log('Кнопка установки добавлена в footer');
|
||
} else if (container) {
|
||
container.appendChild(installButton);
|
||
console.log('Кнопка установки добавлена в container');
|
||
} else {
|
||
document.body.appendChild(installButton);
|
||
console.log('Кнопка установки добавлена в body');
|
||
}
|
||
}
|
||
|
||
// Установка приложения
|
||
installApp() {
|
||
console.log('Попытка установки приложения');
|
||
if (this.deferredPrompt) {
|
||
this.deferredPrompt.prompt();
|
||
this.deferredPrompt.userChoice.then((choiceResult) => {
|
||
console.log('Результат установки:', choiceResult.outcome);
|
||
if (choiceResult.outcome === 'accepted') {
|
||
console.log('Пользователь установил приложение');
|
||
}
|
||
this.deferredPrompt = null;
|
||
this.removeInstallButton();
|
||
});
|
||
} else {
|
||
console.log('deferredPrompt не доступен');
|
||
}
|
||
}
|
||
|
||
// Удаление кнопки установки
|
||
removeInstallButton() {
|
||
const installButton = document.getElementById('pwa-install-button');
|
||
if (installButton) {
|
||
installButton.remove();
|
||
console.log('Кнопка установки удалена');
|
||
}
|
||
}
|
||
|
||
// Обработка успешной установки
|
||
setupAppInstalled() {
|
||
window.addEventListener('appinstalled', () => {
|
||
console.log('PWA установлено успешно');
|
||
this.removeInstallButton();
|
||
});
|
||
}
|
||
|
||
// Проверка статуса PWA
|
||
isPWAInstalled() {
|
||
return window.matchMedia('(display-mode: standalone)').matches ||
|
||
window.navigator.standalone === true;
|
||
}
|
||
|
||
// Получение информации о PWA
|
||
getPWAInfo() {
|
||
return {
|
||
isInstalled: this.isPWAInstalled(),
|
||
isOnline: navigator.onLine,
|
||
hasServiceWorker: 'serviceWorker' in navigator,
|
||
userAgent: navigator.userAgent,
|
||
hasDeferredPrompt: this.deferredPrompt !== null
|
||
};
|
||
}
|
||
|
||
// Принудительное обновление кэша
|
||
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:', pwaManager.getPWAInfo());
|
||
};
|
||
|
||
// Принудительное обновление кэша
|
||
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);
|
||
}; |