(currentNode, nextNode)
| 934 | textarea.style.position = 'fixed'; |
| 935 | textarea.style.opacity = '0'; |
| 936 | textarea.style.pointerEvents = 'none'; |
| 937 | document.body.appendChild(textarea); |
| 938 | textarea.select(); |
| 939 | const success = document.execCommand('copy'); |
| 940 | document.body.removeChild(textarea); |
| 941 | return success; |
| 942 | } catch (e) { |
| 943 | // Fallback to async Clipboard API |
| 944 | navigator.clipboard.writeText(text).catch(() => {}); |
| 945 | return true; |
| 946 | } |
| 947 | } |
| 948 | |
| 949 | handleCouncilTabSwitch(button) { |
| 950 | const messageEl = button.closest('[data-message-id]'); |
| 951 | const label = button.dataset.councilTabLabel; |
| 952 | if (!messageEl || !label) return; |
| 953 | |
| 954 | messageEl.querySelectorAll('.council-tab-btn').forEach((entry) => { |
| 955 | const isActive = entry === button; |
| 956 | entry.classList.toggle('council-tab-btn-active', isActive); |
| 957 | entry.setAttribute('aria-selected', isActive ? 'true' : 'false'); |
| 958 | }); |
| 959 | |
| 960 | messageEl.querySelectorAll('.council-response-panel').forEach((panel) => { |
| 961 | const isActive = panel.dataset.councilPanelLabel === label; |
| 962 | panel.classList.toggle('hidden', !isActive); |
| 963 | }); |
| 964 | } |
| 965 | |
| 966 | /** |
| 967 | * Gets visible text content from a message element in the DOM. |
| 968 | * @param {string} messageId - The message ID |
| 969 | * @returns {string|null} The text content or null |
| 970 | */ |
| 971 | getMessageTextFromDOM(messageId) { |
| 972 | const messageEl = document.querySelector(`[data-message-id="${messageId}"]`); |
| 973 | if (!messageEl) return null; |
no outgoing calls
no test coverage detected