Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="ru">
- <head>
- <meta charset="UTF-8">
- <title>Просмотрщик JSON диалогов</title>
- <style>
- body {
- font-family: Arial, sans-serif;
- margin: 20px;
- }
- h1 {
- font-size: 24px;
- }
- #conversation {
- margin-top: 20px;
- }
- .message {
- border: 1px solid #ccc;
- border-radius: 5px;
- padding: 10px;
- margin-bottom: 10px;
- display: flex; /* Включаем флекс‑раскладку, чтобы разместить аватар и контент в одной строке */
- align-items: flex-start; /* Аватар и текст выравниваем по верхнему краю */
- }
- .message-avatar {
- margin-right: 10px;
- }
- .message-avatar img {
- width: 40px;
- height: 40px;
- border-radius: 50%;
- object-fit: cover;
- }
- .message-content {
- flex: 1; /* Заставляем контент занимать оставшееся пространство */
- }
- .message-header {
- font-weight: bold;
- margin-bottom: 5px;
- }
- .message-text {
- margin-bottom: 5px;
- white-space: pre-wrap;
- }
- .attachments img {
- max-width: 300px;
- display: block;
- margin-bottom: 5px;
- cursor: pointer;
- }
- .attachments a {
- text-decoration: none;
- color: #0066cc;
- }
- .forwards {
- border-left: 2px solid #999;
- margin-left: 10px;
- padding-left: 10px;
- margin-top: 10px;
- }
- /* Кнопки навигации */
- #navButtons {
- position: fixed;
- top: 20px;
- right: 20px;
- z-index: 999; /* чтобы кнопки были поверх контента */
- }
- #navButtons button {
- margin-right: 5px;
- padding: 8px 12px;
- cursor: pointer;
- }
- </style>
- </head>
- <body>
- <h1>Просмотрщик JSON диалогов</h1>
- <p>Выберите JSON‑файл с диалогом (например, 397536668.json):</p>
- <input type="file" id="fileInput" accept=".json">
- <!-- Кнопки навигации -->
- <div id="navButtons">
- <button id="prevButton">Назад</button>
- <button id="nextButton">Вперёд</button>
- </div>
- <div id="conversation"></div>
- <script>
- // Глобальные переменные для работы с фото
- let photoMessages = []; // массив индексов сообщений, где есть хотя бы одно фото
- let currentPhotoIndex = 0; // индекс в массиве photoMessages
- /**
- * Рекурсивная функция для создания DOM‑элемента для одного сообщения.
- * Если у сообщения есть вложенные пересылаемые сообщения (fwd), они также обрабатываются.
- */
- function createMessageElement(message, profiles) {
- const messageDiv = document.createElement('div');
- messageDiv.className = 'message';
- // Определяем имя отправителя по полю from через массив profiles
- const sender = profiles.find(p => p.id === message.from);
- const senderName = sender ? `${sender.firstName} ${sender.lastName}` : 'Неизвестно';
- const senderPhoto = sender && sender.photo ? sender.photo : ''; // ссылка на фото отправителя
- // Создаем блок для аватарки
- const avatarDiv = document.createElement('div');
- avatarDiv.className = 'message-avatar';
- const avatarImg = document.createElement('img');
- avatarImg.src = senderPhoto;
- avatarImg.alt = senderName;
- avatarDiv.appendChild(avatarImg);
- // Создаем блок для контента (заголовок, текст, вложения)
- const contentDiv = document.createElement('div');
- contentDiv.className = 'message-content';
- // Форматируем дату (в JSON время задано в формате Unix timestamp)
- const date = new Date(message.time * 1000);
- const header = document.createElement('div');
- header.className = 'message-header';
- header.textContent = `${senderName} — ${date.toLocaleString()}`;
- contentDiv.appendChild(header);
- // Текст сообщения
- const textDiv = document.createElement('div');
- textDiv.className = 'message-text';
- textDiv.textContent = message.text || '';
- contentDiv.appendChild(textDiv);
- // Если есть attachments (например, фото или документы)
- if (message.attachments && Array.isArray(message.attachments)) {
- const attachmentsDiv = document.createElement('div');
- attachmentsDiv.className = 'attachments';
- message.attachments.forEach(attachment => {
- if (attachment.type === 'photo') {
- // Для фото выводим изображение, обёрнутое в ссылку,
- // которая открывает полную версию (hd) или превью, если hd отсутствует
- const a = document.createElement('a');
- a.href = attachment.hd || attachment.preview;
- a.target = '_blank';
- const img = document.createElement('img');
- img.src = attachment.preview;
- img.alt = 'Фото';
- a.appendChild(img);
- attachmentsDiv.appendChild(a);
- } else if (attachment.type === 'doc') {
- // Для документов выводим ссылку с названием файла
- const docLink = document.createElement('a');
- docLink.href = attachment.link;
- docLink.textContent = attachment.title;
- docLink.target = '_blank';
- attachmentsDiv.appendChild(docLink);
- }
- // Если нужны другие типы вложений – можно добавить обработку здесь
- });
- contentDiv.appendChild(attachmentsDiv);
- }
- // Если сообщение содержит пересланные (fwd) сообщения, обрабатываем их рекурсивно
- if (message.fwd && Array.isArray(message.fwd)) {
- const fwdDiv = document.createElement('div');
- fwdDiv.className = 'forwards';
- message.fwd.forEach(fwdMsg => {
- const fwdMessageElement = createMessageElement(fwdMsg, profiles);
- fwdDiv.appendChild(fwdMessageElement);
- });
- contentDiv.appendChild(fwdDiv);
- }
- // Добавляем блоки на общую обёртку сообщения
- messageDiv.appendChild(avatarDiv);
- messageDiv.appendChild(contentDiv);
- return messageDiv;
- }
- // Функция для прокрутки к сообщению с фото по индексу в photoMessages
- function scrollToPhotoMessage(index) {
- const conversationDiv = document.getElementById('conversation');
- if (photoMessages.length === 0) return; // Если вообще нет сообщений с фото
- if (index < 0 || index >= photoMessages.length) return; // Вне диапазона
- const messageIndex = photoMessages[index];
- const messageElement = conversationDiv.children[messageIndex];
- if (messageElement) {
- messageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
- }
- }
- // Обработчик нажатия кнопки "Назад"
- function goPrevPhoto() {
- if (photoMessages.length === 0) return;
- currentPhotoIndex = (currentPhotoIndex - 1 + photoMessages.length) % photoMessages.length;
- scrollToPhotoMessage(currentPhotoIndex);
- }
- // Обработчик нажатия кнопки "Вперёд"
- function goNextPhoto() {
- if (photoMessages.length === 0) return;
- currentPhotoIndex = (currentPhotoIndex + 1) % photoMessages.length;
- scrollToPhotoMessage(currentPhotoIndex);
- }
- // Обработчик выбора файла
- document.getElementById('fileInput').addEventListener('change', function(event) {
- const file = event.target.files[0];
- if (!file) return;
- const reader = new FileReader();
- reader.onload = function(e) {
- try {
- let content = e.target.result;
- // Если файл начинается с "let dialogjson =", удаляем эту часть
- if (content.trim().startsWith('let dialogjson')) {
- const index = content.indexOf('{');
- if (index !== -1) {
- content = content.substring(index);
- }
- }
- const data = JSON.parse(content);
- // Проверяем наличие необходимых полей messages и profiles
- if (!data.messages || !data.profiles) {
- alert('Неверный формат JSON: отсутствуют поля messages или profiles');
- return;
- }
- // Сортируем сообщения по времени (от старых к новым)
- data.messages.sort((a, b) => a.time - b.time);
- // Очищаем контейнер для переписки
- const conversationDiv = document.getElementById('conversation');
- conversationDiv.innerHTML = '';
- // Сбрасываем массив фото и индекс
- photoMessages = [];
- currentPhotoIndex = 0;
- // Выводим каждое сообщение и попутно собираем индексы, где есть фото
- data.messages.forEach((message, index) => {
- const messageElement = createMessageElement(message, data.profiles);
- conversationDiv.appendChild(messageElement);
- // Проверяем, есть ли хотя бы одна фотография в attachments
- if (message.attachments && message.attachments.some(a => a.type === 'photo')) {
- photoMessages.push(index);
- }
- });
- } catch (error) {
- alert('Ошибка при чтении JSON: ' + error.message);
- }
- };
- reader.readAsText(file);
- });
- // Слушатели для кнопок "Назад" / "Вперёд"
- document.getElementById('prevButton').addEventListener('click', goPrevPhoto);
- document.getElementById('nextButton').addEventListener('click', goNextPhoto);
- // Слушатель нажатий на клавиши (стрелки влево / вправо)
- document.addEventListener('keydown', (e) => {
- if (e.key === 'ArrowLeft') {
- goPrevPhoto();
- } else if (e.key === 'ArrowRight') {
- goNextPhoto();
- }
- });
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment