890 lines
47 KiB
HTML
890 lines
47 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||
<title>Тест мобильной адаптации AI Drawer</title>
|
||
<style>
|
||
body {
|
||
font-family: Arial, sans-serif;
|
||
margin: 0;
|
||
padding: 20px;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.test-container {
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
background: white;
|
||
padding: 20px;
|
||
border-radius: 10px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.test-section {
|
||
margin-bottom: 30px;
|
||
padding: 20px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.test-title {
|
||
color: #007bff;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.test-description {
|
||
color: #666;
|
||
margin-bottom: 15px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.test-button {
|
||
background: #007bff;
|
||
color: white;
|
||
border: none;
|
||
padding: 12px 24px;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
margin: 5px;
|
||
}
|
||
|
||
.test-button:hover {
|
||
background: #0056b3;
|
||
}
|
||
|
||
.test-button.secondary {
|
||
background: #6c757d;
|
||
}
|
||
|
||
.test-button.secondary:hover {
|
||
background: #545b62;
|
||
}
|
||
|
||
.status {
|
||
padding: 10px;
|
||
border-radius: 5px;
|
||
margin: 10px 0;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.status.success {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
border: 1px solid #c3e6cb;
|
||
}
|
||
|
||
.status.info {
|
||
background: #d1ecf1;
|
||
color: #0c5460;
|
||
border: 1px solid #bee5eb;
|
||
}
|
||
|
||
.status.warning {
|
||
background: #fff3cd;
|
||
color: #856404;
|
||
border: 1px solid #ffeaa7;
|
||
}
|
||
|
||
.device-info {
|
||
background: #f8f9fa;
|
||
padding: 15px;
|
||
border-radius: 5px;
|
||
margin: 15px 0;
|
||
font-family: monospace;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.instructions {
|
||
background: #e7f3ff;
|
||
padding: 15px;
|
||
border-radius: 5px;
|
||
border-left: 4px solid #007bff;
|
||
margin: 15px 0;
|
||
}
|
||
|
||
.instructions h4 {
|
||
margin-top: 0;
|
||
color: #007bff;
|
||
}
|
||
|
||
.instructions ol {
|
||
margin: 10px 0;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
.instructions li {
|
||
margin: 5px 0;
|
||
}
|
||
|
||
.log-container {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 5px;
|
||
padding: 15px;
|
||
margin: 15px 0;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 12px;
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
.log-entry {
|
||
margin: 2px 0;
|
||
padding: 2px 5px;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.log-info {
|
||
background: #d1ecf1;
|
||
color: #0c5460;
|
||
}
|
||
|
||
.log-success {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
}
|
||
|
||
.log-warning {
|
||
background: #fff3cd;
|
||
color: #856404;
|
||
}
|
||
|
||
.log-error {
|
||
background: #f8d7da;
|
||
color: #721c24;
|
||
}
|
||
|
||
.log-debug {
|
||
background: #e2e3e5;
|
||
color: #383d41;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="test-container">
|
||
<h1>🧪 Тест мобильной адаптации AI Drawer</h1>
|
||
|
||
<div class="device-info">
|
||
<strong>Информация об устройстве:</strong><br>
|
||
Ширина экрана: <span id="screen-width">-</span>px<br>
|
||
Высота экрана: <span id="screen-height">-</span>px<br>
|
||
User Agent: <span id="user-agent">-</span><br>
|
||
Мобильное устройство: <span id="is-mobile">-</span>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<div class="test-title">📱 Тест 1: Открытие AI Drawer на мобильном</div>
|
||
<div class="test-description">
|
||
Проверяем, что AI Drawer корректно открывается на мобильных устройствах и занимает всю ширину экрана.
|
||
</div>
|
||
<button class="test-button" onclick="testOpenDrawer()">Открыть AI Drawer</button>
|
||
<button class="test-button secondary" onclick="testCloseDrawer()">Закрыть AI Drawer</button>
|
||
<div id="test1-status"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<div class="test-title">⌨️ Тест 2: Адаптация к виртуальной клавиатуре</div>
|
||
<div class="test-description">
|
||
Проверяем, что поле ввода остается доступным при появлении виртуальной клавиатуры, правильно ужимается под размер экрана и поднимается выше от нижнего края.
|
||
</div>
|
||
<div class="instructions">
|
||
<h4>Инструкции для тестирования:</h4>
|
||
<ol>
|
||
<li>Откройте AI Drawer</li>
|
||
<li>Нажмите на поле ввода сообщения</li>
|
||
<li>Проверьте, что поле ввода и кнопка "Отправить" остаются видимыми</li>
|
||
<li>Проверьте, что поле ввода ужимается под размер экрана</li>
|
||
<li>Проверьте, что поле ввода поднимается выше от нижнего края (20-40px)</li>
|
||
<li>Проверьте, что кнопка "Отправить" не перекрывается</li>
|
||
<li>Проверьте, что чат автоматически прокручивается к последнему сообщению</li>
|
||
</ol>
|
||
</div>
|
||
<button class="test-button" onclick="testKeyboardAdaptation()">Начать тест клавиатуры</button>
|
||
<div id="test2-status"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<div class="test-title">📏 Тест 3: Размеры элементов на мобильном</div>
|
||
<div class="test-description">
|
||
Проверяем, что все элементы имеют подходящие размеры для мобильных устройств.
|
||
</div>
|
||
<button class="test-button" onclick="testElementSizes()">Проверить размеры</button>
|
||
<div id="test3-status"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<div class="test-title">🔄 Тест 4: Прокрутка и навигация</div>
|
||
<div class="test-description">
|
||
Проверяем плавность прокрутки и навигации в чате.
|
||
</div>
|
||
<button class="test-button" onclick="testScrolling()">Тест прокрутки</button>
|
||
<div id="test4-status"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<div class="test-title">🎨 Тест 5: Адаптивность интерфейса</div>
|
||
<div class="test-description">
|
||
Проверяем, что интерфейс корректно адаптируется к разным размерам экрана.
|
||
</div>
|
||
<button class="test-button" onclick="testResponsiveness()">Тест адаптивности</button>
|
||
<div id="test5-status"></div>
|
||
</div>
|
||
|
||
<div class="instructions">
|
||
<h4>🔧 Дополнительные тесты:</h4>
|
||
<ol>
|
||
<li><strong>Поворот экрана:</strong> Поверните устройство и проверьте адаптацию</li>
|
||
<li><strong>Разные браузеры:</strong> Протестируйте в Chrome, Safari, Firefox</li>
|
||
<li><strong>Разные размеры экрана:</strong> Протестируйте на разных устройствах</li>
|
||
<li><strong>Производительность:</strong> Проверьте плавность анимаций</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<div class="test-title">📋 Лог тестирования</div>
|
||
<div class="test-description">
|
||
Здесь отображаются подробные логи всех тестов и проверок.
|
||
</div>
|
||
<button class="test-button secondary" onclick="clearLog()">Очистить лог</button>
|
||
<button class="test-button secondary" onclick="exportLog()">Экспорт лога</button>
|
||
<button class="test-button secondary" onclick="loadServerLogs()">Загрузить с сервера</button>
|
||
<button class="test-button secondary" onclick="clearServerLogs()">Очистить сервер</button>
|
||
<button class="test-button secondary" onclick="checkServerStatus()">Статус сервера</button>
|
||
<div id="test-log" class="log-container"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Подключаем AI Drawer -->
|
||
<link rel="stylesheet" href="layouts/v7/resources/css/ai-drawer.css">
|
||
<script src="layouts/v7/resources/js/ai-drawer.js"></script>
|
||
|
||
<script>
|
||
// Система логирования
|
||
let testLog = [];
|
||
|
||
function addLog(message, type = 'info', details = null) {
|
||
const timestamp = new Date().toLocaleTimeString();
|
||
const logEntry = {
|
||
timestamp: timestamp,
|
||
message: message,
|
||
type: type,
|
||
details: details,
|
||
userAgent: navigator.userAgent,
|
||
screenSize: `${window.innerWidth}x${window.innerHeight}`,
|
||
url: window.location.href
|
||
};
|
||
|
||
testLog.push(logEntry);
|
||
|
||
const logContainer = document.getElementById('test-log');
|
||
if (logContainer) {
|
||
const logElement = document.createElement('div');
|
||
logElement.className = `log-entry log-${type}`;
|
||
|
||
let logText = `[${timestamp}] ${message}`;
|
||
if (details) {
|
||
logText += `\nДетали: ${JSON.stringify(details, null, 2)}`;
|
||
}
|
||
|
||
logElement.textContent = logText;
|
||
logContainer.appendChild(logElement);
|
||
logContainer.scrollTop = logContainer.scrollHeight;
|
||
}
|
||
|
||
// Также выводим в консоль браузера
|
||
console.log(`[TEST LOG ${type.toUpperCase()}] ${message}`, details || '');
|
||
|
||
// Отправляем на сервер
|
||
sendLogToServer(logEntry);
|
||
}
|
||
|
||
function sendLogToServer(logEntry) {
|
||
fetch('/test_log_server.php?action=write', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify(logEntry)
|
||
}).catch(error => {
|
||
console.warn('Не удалось отправить лог на сервер:', error);
|
||
});
|
||
}
|
||
|
||
function clearLog() {
|
||
testLog = [];
|
||
const logContainer = document.getElementById('test-log');
|
||
if (logContainer) {
|
||
logContainer.innerHTML = '';
|
||
}
|
||
addLog('Лог очищен', 'info');
|
||
}
|
||
|
||
function exportLog() {
|
||
const logText = testLog.map(entry =>
|
||
`[${entry.timestamp}] ${entry.type.toUpperCase()}: ${entry.message}` +
|
||
(entry.details ? `\nДетали: ${JSON.stringify(entry.details, null, 2)}` : '')
|
||
).join('\n\n');
|
||
|
||
const blob = new Blob([logText], { type: 'text/plain' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `ai-drawer-test-log-${new Date().toISOString().slice(0, 19)}.txt`;
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
|
||
addLog('Лог экспортирован', 'success');
|
||
}
|
||
|
||
function loadServerLogs() {
|
||
fetch('/test_log_server.php?action=read&limit=50')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
addLog(`Загружено ${data.logs.length} записей с сервера`, 'info');
|
||
|
||
// Добавляем серверные логи в контейнер
|
||
const logContainer = document.getElementById('test-log');
|
||
if (logContainer) {
|
||
data.logs.forEach(logEntry => {
|
||
const logElement = document.createElement('div');
|
||
logElement.className = `log-entry log-${logEntry.data.type || 'info'}`;
|
||
logElement.style.opacity = '0.7'; // Помечаем как серверные
|
||
|
||
let logText = `[СЕРВЕР ${logEntry.timestamp}] ${logEntry.data.message}`;
|
||
if (logEntry.data.details) {
|
||
logText += `\nДетали: ${JSON.stringify(logEntry.data.details, null, 2)}`;
|
||
}
|
||
|
||
logElement.textContent = logText;
|
||
logContainer.insertBefore(logElement, logContainer.firstChild);
|
||
});
|
||
}
|
||
} else {
|
||
addLog('Ошибка загрузки серверных логов', 'error', data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
addLog('Ошибка подключения к серверу логов', 'error', error.message);
|
||
});
|
||
}
|
||
|
||
function clearServerLogs() {
|
||
fetch('/test_log_server.php?action=clear')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
addLog('Серверные логи очищены', 'success');
|
||
} else {
|
||
addLog('Ошибка очистки серверных логов', 'error', data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
addLog('Ошибка подключения к серверу логов', 'error', error.message);
|
||
});
|
||
}
|
||
|
||
function checkServerStatus() {
|
||
fetch('/test_log_server.php?action=status')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
addLog('Статус сервера логов', 'info', data.status);
|
||
} else {
|
||
addLog('Ошибка получения статуса сервера', 'error', data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
addLog('Сервер логов недоступен', 'warning', error.message);
|
||
});
|
||
}
|
||
|
||
// Обновляем информацию об устройстве
|
||
function updateDeviceInfo() {
|
||
document.getElementById('screen-width').textContent = window.innerWidth;
|
||
document.getElementById('screen-height').textContent = window.innerHeight;
|
||
document.getElementById('user-agent').textContent = navigator.userAgent.substring(0, 50) + '...';
|
||
document.getElementById('is-mobile').textContent = window.innerWidth <= 768 ? 'Да' : 'Нет';
|
||
|
||
addLog('Информация об устройстве обновлена', 'info', {
|
||
width: window.innerWidth,
|
||
height: window.innerHeight,
|
||
isMobile: window.innerWidth <= 768,
|
||
userAgent: navigator.userAgent
|
||
});
|
||
}
|
||
|
||
// Обновляем информацию при изменении размера окна
|
||
window.addEventListener('resize', updateDeviceInfo);
|
||
updateDeviceInfo();
|
||
|
||
// Инициализируем AI Drawer
|
||
let aiDrawerInstance;
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
addLog('Начало инициализации AI Drawer', 'info');
|
||
|
||
try {
|
||
aiDrawerInstance = new AIDrawer();
|
||
addLog('AI Drawer успешно инициализирован', 'success', {
|
||
drawer: !!aiDrawerInstance.drawer,
|
||
toggleBtn: !!aiDrawerInstance.toggleBtn,
|
||
closeBtn: !!aiDrawerInstance.closeBtn,
|
||
chatInput: !!aiDrawerInstance.chatInput,
|
||
sendButton: !!aiDrawerInstance.sendButton
|
||
});
|
||
} catch (error) {
|
||
addLog('Ошибка инициализации AI Drawer', 'error', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
}
|
||
});
|
||
|
||
// Тест 1: Открытие/закрытие drawer
|
||
function testOpenDrawer() {
|
||
const status = document.getElementById('test1-status');
|
||
addLog('Начало теста: Открытие AI Drawer', 'info');
|
||
|
||
try {
|
||
if (aiDrawerInstance) {
|
||
aiDrawerInstance.open();
|
||
addLog('AI Drawer открыт', 'success');
|
||
status.innerHTML = '<div class="status success">✅ AI Drawer успешно открыт</div>';
|
||
|
||
// Проверяем размеры
|
||
setTimeout(() => {
|
||
const drawer = document.querySelector('.ai-drawer');
|
||
if (drawer) {
|
||
const rect = drawer.getBoundingClientRect();
|
||
const isFullWidth = window.innerWidth <= 768 ? rect.width >= window.innerWidth * 0.95 : rect.width >= 350;
|
||
|
||
addLog('Проверка размеров drawer', 'debug', {
|
||
drawerWidth: rect.width,
|
||
screenWidth: window.innerWidth,
|
||
isMobile: window.innerWidth <= 768,
|
||
isFullWidth: isFullWidth,
|
||
expectedMinWidth: window.innerWidth <= 768 ? window.innerWidth * 0.95 : 350
|
||
});
|
||
|
||
if (isFullWidth) {
|
||
status.innerHTML += '<div class="status success">✅ Размеры drawer корректны</div>';
|
||
addLog('Размеры drawer корректны', 'success');
|
||
} else {
|
||
status.innerHTML += '<div class="status warning">⚠️ Размеры drawer могут быть некорректными</div>';
|
||
addLog('Размеры drawer некорректны', 'warning', {
|
||
actualWidth: rect.width,
|
||
expectedMinWidth: window.innerWidth <= 768 ? window.innerWidth * 0.95 : 350
|
||
});
|
||
}
|
||
} else {
|
||
addLog('Drawer элемент не найден', 'error');
|
||
}
|
||
}, 500);
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ AI Drawer не инициализирован</div>';
|
||
addLog('AI Drawer не инициализирован', 'error');
|
||
}
|
||
} catch (error) {
|
||
status.innerHTML = '<div class="status warning">⚠️ Ошибка: ' + error.message + '</div>';
|
||
addLog('Ошибка при открытии drawer', 'error', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
}
|
||
}
|
||
|
||
function testCloseDrawer() {
|
||
const status = document.getElementById('test1-status');
|
||
|
||
try {
|
||
if (aiDrawerInstance) {
|
||
aiDrawerInstance.close();
|
||
status.innerHTML = '<div class="status success">✅ AI Drawer успешно закрыт</div>';
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ AI Drawer не инициализирован</div>';
|
||
}
|
||
} catch (error) {
|
||
status.innerHTML = '<div class="status warning">⚠️ Ошибка: ' + error.message + '</div>';
|
||
}
|
||
}
|
||
|
||
// Тест 2: Адаптация к клавиатуре
|
||
function testKeyboardAdaptation() {
|
||
const status = document.getElementById('test2-status');
|
||
addLog('Начало теста: Адаптация к виртуальной клавиатуре', 'info');
|
||
|
||
try {
|
||
if (aiDrawerInstance) {
|
||
aiDrawerInstance.open();
|
||
addLog('AI Drawer открыт для теста клавиатуры', 'info');
|
||
|
||
// Добавляем тестовые сообщения
|
||
aiDrawerInstance.addMessage('Тестовое сообщение 1', false);
|
||
aiDrawerInstance.addMessage('Тестовое сообщение 2', true);
|
||
aiDrawerInstance.addMessage('Тестовое сообщение 3', false);
|
||
addLog('Добавлены тестовые сообщения', 'info');
|
||
|
||
status.innerHTML = '<div class="status info">ℹ️ Добавлены тестовые сообщения. Теперь нажмите на поле ввода для проверки адаптации к клавиатуре.</div>';
|
||
|
||
// Проверяем поле ввода
|
||
const input = document.querySelector('#ai-chat-input');
|
||
if (input) {
|
||
addLog('Поле ввода найдено, добавляем обработчик фокуса', 'info');
|
||
input.addEventListener('focus', function() {
|
||
addLog('Поле ввода получило фокус', 'info');
|
||
setTimeout(() => {
|
||
const inputContainer = document.querySelector('.ai-chat-input-container');
|
||
const inputField = document.querySelector('#ai-chat-input');
|
||
const sendButton = document.querySelector('#ai-send-button');
|
||
|
||
addLog('Начало проверки элементов после фокуса', 'debug', {
|
||
inputContainer: !!inputContainer,
|
||
inputField: !!inputField,
|
||
sendButton: !!sendButton
|
||
});
|
||
|
||
// Проверяем видимость контейнера
|
||
const containerRect = inputContainer.getBoundingClientRect();
|
||
const isContainerVisible = containerRect.top >= 0 && containerRect.bottom <= window.innerHeight;
|
||
|
||
// Проверяем размеры поля ввода
|
||
const inputRect = inputField.getBoundingClientRect();
|
||
const inputWidth = inputRect.width;
|
||
const screenWidth = window.innerWidth;
|
||
const inputWidthPercent = (inputWidth / screenWidth) * 100;
|
||
|
||
// Проверяем видимость кнопки отправки
|
||
const buttonRect = sendButton.getBoundingClientRect();
|
||
const isButtonVisible = buttonRect.top >= 0 && buttonRect.bottom <= window.innerHeight;
|
||
|
||
// Проверяем высоту поля ввода от нижнего края
|
||
const inputBottom = inputRect.bottom;
|
||
const screenHeight = window.innerHeight;
|
||
const distanceFromBottom = screenHeight - inputBottom;
|
||
|
||
addLog('Измерения элементов', 'debug', {
|
||
containerRect: {
|
||
top: containerRect.top,
|
||
bottom: containerRect.bottom,
|
||
left: containerRect.left,
|
||
right: containerRect.right,
|
||
width: containerRect.width,
|
||
height: containerRect.height
|
||
},
|
||
inputRect: {
|
||
top: inputRect.top,
|
||
bottom: inputRect.bottom,
|
||
left: inputRect.left,
|
||
right: inputRect.right,
|
||
width: inputRect.width,
|
||
height: inputRect.height
|
||
},
|
||
buttonRect: {
|
||
top: buttonRect.top,
|
||
bottom: buttonRect.bottom,
|
||
left: buttonRect.left,
|
||
right: buttonRect.right,
|
||
width: buttonRect.width,
|
||
height: buttonRect.height
|
||
},
|
||
screenDimensions: {
|
||
width: screenWidth,
|
||
height: screenHeight
|
||
},
|
||
calculations: {
|
||
inputWidthPercent: inputWidthPercent,
|
||
distanceFromBottom: distanceFromBottom,
|
||
isContainerVisible: isContainerVisible,
|
||
isButtonVisible: isButtonVisible
|
||
}
|
||
});
|
||
|
||
if (isContainerVisible) {
|
||
status.innerHTML += '<div class="status success">✅ Поле ввода остается видимым при появлении клавиатуры</div>';
|
||
addLog('Поле ввода остается видимым', 'success');
|
||
} else {
|
||
status.innerHTML += '<div class="status warning">⚠️ Поле ввода может быть скрыто клавиатурой</div>';
|
||
addLog('Поле ввода может быть скрыто клавиатурой', 'warning');
|
||
}
|
||
|
||
if (inputWidthPercent >= 60 && inputWidthPercent <= 80) {
|
||
status.innerHTML += '<div class="status success">✅ Поле ввода правильно ужимается под размер экрана (' + Math.round(inputWidthPercent) + '%)</div>';
|
||
addLog('Поле ввода правильно ужимается', 'success', { widthPercent: inputWidthPercent });
|
||
} else {
|
||
status.innerHTML += '<div class="status warning">⚠️ Поле ввода может быть слишком широким или узким (' + Math.round(inputWidthPercent) + '%)</div>';
|
||
addLog('Поле ввода неправильно ужимается', 'warning', { widthPercent: inputWidthPercent });
|
||
}
|
||
|
||
if (isButtonVisible) {
|
||
status.innerHTML += '<div class="status success">✅ Кнопка "Отправить" остается видимой</div>';
|
||
addLog('Кнопка "Отправить" остается видимой', 'success');
|
||
} else {
|
||
status.innerHTML += '<div class="status warning">⚠️ Кнопка "Отправить" может быть перекрыта</div>';
|
||
addLog('Кнопка "Отправить" может быть перекрыта', 'warning');
|
||
}
|
||
|
||
if (distanceFromBottom >= 200 && distanceFromBottom <= 400) {
|
||
status.innerHTML += '<div class="status success">✅ Поле ввода поднято на правильную высоту (' + Math.round(distanceFromBottom) + 'px от низа)</div>';
|
||
addLog('Поле ввода поднято на правильную высоту', 'success', { distanceFromBottom: distanceFromBottom });
|
||
} else {
|
||
status.innerHTML += '<div class="status warning">⚠️ Поле ввода может быть слишком низко или высоко (' + Math.round(distanceFromBottom) + 'px от низа)</div>';
|
||
addLog('Поле ввода неправильно позиционировано', 'warning', { distanceFromBottom: distanceFromBottom });
|
||
}
|
||
}, 500);
|
||
});
|
||
}
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ AI Drawer не инициализирован</div>';
|
||
addLog('AI Drawer не инициализирован для теста клавиатуры', 'error');
|
||
}
|
||
} catch (error) {
|
||
status.innerHTML = '<div class="status warning">⚠️ Ошибка: ' + error.message + '</div>';
|
||
addLog('Ошибка в тесте клавиатуры', 'error', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
}
|
||
}
|
||
|
||
// Тест 3: Размеры элементов
|
||
function testElementSizes() {
|
||
const status = document.getElementById('test3-status');
|
||
addLog('Начало теста: Размеры элементов', 'info');
|
||
|
||
try {
|
||
if (aiDrawerInstance) {
|
||
aiDrawerInstance.open();
|
||
addLog('AI Drawer открыт для теста размеров', 'info');
|
||
|
||
setTimeout(() => {
|
||
const input = document.querySelector('#ai-chat-input');
|
||
const button = document.querySelector('#ai-send-button');
|
||
const header = document.querySelector('.ai-drawer-header');
|
||
|
||
addLog('Проверка размеров элементов', 'debug', {
|
||
input: !!input,
|
||
button: !!button,
|
||
header: !!header
|
||
});
|
||
|
||
let results = [];
|
||
|
||
if (input) {
|
||
const inputRect = input.getBoundingClientRect();
|
||
const isInputSizeOK = inputRect.height >= 40 && inputRect.height <= 60;
|
||
results.push(isInputSizeOK ? '✅ Поле ввода: размер OK' : '⚠️ Поле ввода: размер может быть некорректным');
|
||
addLog('Размер поля ввода', isInputSizeOK ? 'success' : 'warning', {
|
||
height: inputRect.height,
|
||
expectedRange: '40-60px',
|
||
isOK: isInputSizeOK
|
||
});
|
||
}
|
||
|
||
if (button) {
|
||
const buttonRect = button.getBoundingClientRect();
|
||
const isButtonSizeOK = buttonRect.height >= 40 && buttonRect.height <= 60;
|
||
results.push(isButtonSizeOK ? '✅ Кнопка отправки: размер OK' : '⚠️ Кнопка отправки: размер может быть некорректным');
|
||
addLog('Размер кнопки отправки', isButtonSizeOK ? 'success' : 'warning', {
|
||
height: buttonRect.height,
|
||
expectedRange: '40-60px',
|
||
isOK: isButtonSizeOK
|
||
});
|
||
}
|
||
|
||
if (header) {
|
||
const headerRect = header.getBoundingClientRect();
|
||
const isHeaderSizeOK = headerRect.height >= 50 && headerRect.height <= 80;
|
||
results.push(isHeaderSizeOK ? '✅ Заголовок: размер OK' : '⚠️ Заголовок: размер может быть некорректным');
|
||
addLog('Размер заголовка', isHeaderSizeOK ? 'success' : 'warning', {
|
||
height: headerRect.height,
|
||
expectedRange: '50-80px',
|
||
isOK: isHeaderSizeOK
|
||
});
|
||
}
|
||
|
||
status.innerHTML = '<div class="status info">📏 Результаты проверки размеров:</div>' +
|
||
results.map(r => '<div class="status ' + (r.includes('✅') ? 'success' : 'warning') + '">' + r + '</div>').join('');
|
||
}, 500);
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ AI Drawer не инициализирован</div>';
|
||
addLog('AI Drawer не инициализирован для теста размеров', 'error');
|
||
}
|
||
} catch (error) {
|
||
status.innerHTML = '<div class="status warning">⚠️ Ошибка: ' + error.message + '</div>';
|
||
addLog('Ошибка в тесте размеров', 'error', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
}
|
||
}
|
||
|
||
// Тест 4: Прокрутка
|
||
function testScrolling() {
|
||
const status = document.getElementById('test4-status');
|
||
addLog('Начало теста: Прокрутка и навигация', 'info');
|
||
|
||
try {
|
||
if (aiDrawerInstance) {
|
||
aiDrawerInstance.open();
|
||
addLog('AI Drawer открыт для теста прокрутки', 'info');
|
||
|
||
// Добавляем много сообщений для тестирования прокрутки
|
||
for (let i = 1; i <= 10; i++) {
|
||
aiDrawerInstance.addMessage(`Тестовое сообщение ${i} для проверки прокрутки`, i % 2 === 0);
|
||
}
|
||
addLog('Добавлено 10 тестовых сообщений', 'info');
|
||
|
||
setTimeout(() => {
|
||
const content = document.querySelector('.ai-drawer-content');
|
||
if (content) {
|
||
const canScroll = content.scrollHeight > content.clientHeight;
|
||
|
||
addLog('Проверка прокрутки', 'debug', {
|
||
scrollHeight: content.scrollHeight,
|
||
clientHeight: content.clientHeight,
|
||
canScroll: canScroll
|
||
});
|
||
|
||
if (canScroll) {
|
||
status.innerHTML = '<div class="status success">✅ Прокрутка работает корректно</div>';
|
||
addLog('Прокрутка работает корректно', 'success');
|
||
|
||
// Проверяем автоматическую прокрутку к последнему сообщению
|
||
const lastMessage = content.querySelector('.ai-message:last-child');
|
||
if (lastMessage) {
|
||
const lastMessageRect = lastMessage.getBoundingClientRect();
|
||
const contentRect = content.getBoundingClientRect();
|
||
const isLastMessageVisible = lastMessageRect.bottom <= contentRect.bottom;
|
||
|
||
addLog('Проверка автоматической прокрутки', 'debug', {
|
||
lastMessageRect: {
|
||
top: lastMessageRect.top,
|
||
bottom: lastMessageRect.bottom
|
||
},
|
||
contentRect: {
|
||
top: contentRect.top,
|
||
bottom: contentRect.bottom
|
||
},
|
||
isLastMessageVisible: isLastMessageVisible
|
||
});
|
||
|
||
if (isLastMessageVisible) {
|
||
status.innerHTML += '<div class="status success">✅ Автоматическая прокрутка к последнему сообщению работает</div>';
|
||
addLog('Автоматическая прокрутка работает', 'success');
|
||
} else {
|
||
status.innerHTML += '<div class="status warning">⚠️ Автоматическая прокрутка может работать некорректно</div>';
|
||
addLog('Автоматическая прокрутка работает некорректно', 'warning');
|
||
}
|
||
} else {
|
||
addLog('Последнее сообщение не найдено', 'warning');
|
||
}
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ Прокрутка может работать некорректно</div>';
|
||
addLog('Прокрутка работает некорректно', 'warning');
|
||
}
|
||
} else {
|
||
addLog('Контейнер контента не найден', 'error');
|
||
}
|
||
}, 500);
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ AI Drawer не инициализирован</div>';
|
||
addLog('AI Drawer не инициализирован для теста прокрутки', 'error');
|
||
}
|
||
} catch (error) {
|
||
status.innerHTML = '<div class="status warning">⚠️ Ошибка: ' + error.message + '</div>';
|
||
addLog('Ошибка в тесте прокрутки', 'error', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
}
|
||
}
|
||
|
||
// Тест 5: Адаптивность
|
||
function testResponsiveness() {
|
||
const status = document.getElementById('test5-status');
|
||
addLog('Начало теста: Адаптивность интерфейса', 'info');
|
||
|
||
try {
|
||
if (aiDrawerInstance) {
|
||
aiDrawerInstance.open();
|
||
addLog('AI Drawer открыт для теста адаптивности', 'info');
|
||
|
||
setTimeout(() => {
|
||
const drawer = document.querySelector('.ai-drawer');
|
||
if (drawer) {
|
||
const rect = drawer.getBoundingClientRect();
|
||
const isResponsive = window.innerWidth <= 768 ?
|
||
rect.width >= window.innerWidth * 0.95 :
|
||
rect.width >= 350 && rect.width <= 450;
|
||
|
||
addLog('Проверка адаптивности', 'debug', {
|
||
drawerWidth: rect.width,
|
||
screenWidth: window.innerWidth,
|
||
isMobile: window.innerWidth <= 768,
|
||
isResponsive: isResponsive,
|
||
expectedRange: window.innerWidth <= 768 ?
|
||
`${window.innerWidth * 0.95}px+` :
|
||
'350-450px'
|
||
});
|
||
|
||
if (isResponsive) {
|
||
status.innerHTML = '<div class="status success">✅ Адаптивность работает корректно</div>';
|
||
addLog('Адаптивность работает корректно', 'success');
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ Адаптивность может работать некорректно</div>';
|
||
addLog('Адаптивность работает некорректно', 'warning');
|
||
}
|
||
|
||
// Проверяем медиа-запросы
|
||
const mediaQuery = window.matchMedia('(max-width: 768px)');
|
||
const isMobileQuery = mediaQuery.matches;
|
||
|
||
addLog('Проверка медиа-запросов', 'debug', {
|
||
mediaQuery: '(max-width: 768px)',
|
||
isActive: isMobileQuery,
|
||
screenWidth: window.innerWidth
|
||
});
|
||
|
||
status.innerHTML += '<div class="status info">📱 Медиа-запрос (max-width: 768px): ' + (isMobileQuery ? 'Активен' : 'Неактивен') + '</div>';
|
||
} else {
|
||
addLog('Drawer элемент не найден для теста адаптивности', 'error');
|
||
}
|
||
}, 500);
|
||
} else {
|
||
status.innerHTML = '<div class="status warning">⚠️ AI Drawer не инициализирован</div>';
|
||
addLog('AI Drawer не инициализирован для теста адаптивности', 'error');
|
||
}
|
||
} catch (error) {
|
||
status.innerHTML = '<div class="status warning">⚠️ Ошибка: ' + error.message + '</div>';
|
||
addLog('Ошибка в тесте адаптивности', 'error', {
|
||
error: error.message,
|
||
stack: error.stack
|
||
});
|
||
}
|
||
}
|
||
|
||
// Дополнительная информация для отладки
|
||
addLog('Тестовая страница загружена', 'info', {
|
||
screenSize: `${window.innerWidth}x${window.innerHeight}`,
|
||
isMobile: window.innerWidth <= 768,
|
||
userAgent: navigator.userAgent
|
||
});
|
||
|
||
// Проверяем статус сервера логов при загрузке
|
||
setTimeout(() => {
|
||
checkServerStatus();
|
||
}, 1000);
|
||
|
||
console.log('Mobile Keyboard Fix Test Page loaded');
|
||
console.log('Screen size:', window.innerWidth + 'x' + window.innerHeight);
|
||
console.log('Is mobile:', window.innerWidth <= 768);
|
||
</script>
|
||
</body>
|
||
</html>
|