Created
March 1, 2026 11:06
-
-
Save bibendi/5b542e2edb05f0701cc8c90221921a55 to your computer and use it in GitHub Desktop.
Tampermonkey Mattermost Thread Extractor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Mattermost Thread Extractor (Sbermarket) - Dual Mode | |
| // @namespace http://tampermonkey.net/ | |
| // @version 2.4 | |
| // @description Копирует тред в буфер из любого режима просмотра (список тредов или правая панель) | |
| // @author You | |
| // @match https://mattermost.sbermarket.tech/* | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // SVG иконка копирования | |
| const copyIcon = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align: middle;"> | |
| <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect> | |
| <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path> | |
| </svg>`; | |
| const checkIcon = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align: middle;"> | |
| <polyline points="20 6 9 17 4 12"></polyline> | |
| </svg>`; | |
| function extractThread() { | |
| // Ищем контейнер треда - пробуем разные варианты для разных режимов | |
| let container = document.getElementById('thread-pane-container') || | |
| document.getElementById('rhsContainer') || | |
| document.querySelector('.sidebar--right'); | |
| if (!container) { | |
| alert('Откройте тред (панель с тредом должна быть видна)'); | |
| return; | |
| } | |
| // Ищем посты | |
| const posts = container.querySelectorAll('[data-testid="rhsPostView"], .post--thread, .post'); | |
| if (posts.length === 0) { | |
| alert('Сообщения не найдены. Прокрутите тред вверх для загрузки всех сообщений.'); | |
| return; | |
| } | |
| let output = `=== Mattermost Thread Export ===\n`; | |
| output += `URL: ${window.location.href}\n`; | |
| output += `Всего сообщений: ${posts.length}\n`; | |
| output += `Дата: ${new Date().toLocaleString('ru-RU')}\n\n`; | |
| posts.forEach((post, idx) => { | |
| const authorEl = post.querySelector('.user-popover'); | |
| const author = authorEl ? authorEl.textContent.trim() : 'Unknown'; | |
| const timeEl = post.querySelector('time.post__time'); | |
| const time = timeEl ? timeEl.textContent.trim() : ''; | |
| const textEl = post.querySelector('.post-message__text'); | |
| const text = textEl ? textEl.innerText.trim() : '[нет текста]'; | |
| const marker = idx === 0 ? '[НАЧАЛО ТРЕДА] ' : ''; | |
| output += `${marker}[${time}] ${author}:\n`; | |
| output += `${text}\n`; | |
| output += `${'-'.repeat(40)}\n\n`; | |
| }); | |
| navigator.clipboard.writeText(output).then(() => { | |
| // Визуальная обратная связь на всех кнопках копирования | |
| document.querySelectorAll('.mm-copy-btn').forEach(btn => { | |
| const originalHTML = btn.innerHTML; | |
| btn.innerHTML = checkIcon; | |
| btn.style.color = '#28a745'; | |
| setTimeout(() => { | |
| btn.innerHTML = copyIcon; | |
| btn.style.color = ''; | |
| }, 2000); | |
| }); | |
| showNotification(`Скопировано ${posts.length} сообщений`); | |
| }).catch(err => { | |
| console.error('Ошибка:', err); | |
| alert('Не удалось скопировать в буфер обмена'); | |
| }); | |
| } | |
| function showNotification(msg) { | |
| const div = document.createElement('div'); | |
| div.textContent = msg; | |
| div.style.cssText = ` | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background: #28a745; | |
| color: white; | |
| padding: 10px 16px; | |
| border-radius: 4px; | |
| font-family: sans-serif; | |
| font-size: 13px; | |
| z-index: 10000; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.2); | |
| `; | |
| document.body.appendChild(div); | |
| setTimeout(() => div.remove(), 2500); | |
| } | |
| function createCopyButton() { | |
| const btn = document.createElement('button'); | |
| btn.className = 'mm-copy-btn btn btn-icon btn-sm'; | |
| btn.type = 'button'; | |
| btn.setAttribute('aria-label', 'Копировать тред'); | |
| btn.title = 'Копировать тред в буфер обмена'; | |
| btn.innerHTML = copyIcon; | |
| btn.style.marginLeft = '4px'; | |
| btn.addEventListener('click', extractThread); | |
| return btn; | |
| } | |
| function addButtonToHeaders() { | |
| // Режим 1: Список тредов (ThreadPane) | |
| const threadPaneHeader = document.querySelector('.ThreadPane___header'); | |
| if (threadPaneHeader && !threadPaneHeader.querySelector('.mm-copy-btn')) { | |
| const menuWrapper = threadPaneHeader.querySelector('.MenuWrapper'); | |
| if (menuWrapper) { | |
| threadPaneHeader.insertBefore(createCopyButton(), menuWrapper); | |
| } | |
| } | |
| // Режим 2: Правая панель (sidebar--right__header) | |
| const sidebarHeader = document.querySelector('.sidebar--right__header'); | |
| if (sidebarHeader && !sidebarHeader.querySelector('.mm-copy-btn')) { | |
| const controls = sidebarHeader.querySelector('.controls'); | |
| if (controls) { | |
| // Вставляем перед кнопкой закрытия (rhsCloseButton) | |
| const closeBtn = document.getElementById('rhsCloseButton'); | |
| if (closeBtn) { | |
| controls.insertBefore(createCopyButton(), closeBtn); | |
| } else { | |
| // Или просто в конец controls, если кнопка закрытия не найдена | |
| controls.appendChild(createCopyButton()); | |
| } | |
| } | |
| } | |
| } | |
| // Проверяем каждую секунду (Mattermont - SPA, элементы появляются динамически) | |
| setInterval(addButtonToHeaders, 1000); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment