// ==UserScript== // @name AI Conversation Navigator // @namespace https://greasyfork.org // @version 11.5 // @description Floating navigator for your prompts in conversations with bookmark feature. Applied for ChatGPT, Gemini, Aistudio, NotebookLM, Grok, Claude, Mistral, Deepseek, Kimi, Qwen, Z.ai, Chatglm, Ernie, Meta, Perplexity, Poe, Deepai, Huggingface, Manus, Longcat, Chatboxai, Lmarena, Quillbot, Canva, Genspark, Character, Spacefrontiers, Scienceos, Evidencehunt, Playground (allen), Paperfigureqa (allen), Scira, Scispace, Exa.ai, Consensus, Openevidence, Math-gpt. // @author Bui Quoc Dung // @match https://chatgpt.com/* // @match https://gemini.google.com/* // @match https://aistudio.google.com/* // @match https://notebooklm.google.com/* // @match https://grok.com/* // @match https://claude.ai/* // @match https://www.kimi.com/* // @match https://chat.mistral.ai/* // @match https://www.perplexity.ai/* // @match https://www.meta.ai/* // @match https://poe.com/* // @match https://deepai.org/* // @match https://huggingface.co/chat/* // @match https://chat.deepseek.com/* // @match https://chat.qwen.ai/* // @match https://manus.im/* // @match https://chat.z.ai/* // @match https://longcat.chat/* // @match https://chatglm.cn/* // @match https://ernie.baidu.com/* // @match https://web.chatboxai.app/* // @match https://lmarena.ai/* // @match https://quillbot.com/* // @match https://www.canva.com/* // @match https://www.genspark.ai/* // @match https://character.ai/* // @match https://spacefrontiers.org/* // @match https://app.scienceos.ai/* // @match https://evidencehunt.com/* // @match https://playground.allenai.org/* // @match https://paperfigureqa.allen.ai/* // @match https://scira.ai/* // @match https://exa.ai/* // @match https://consensus.app/* // @match https://www.openevidence.com/* // @match https://math-gpt.org/* // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== (function () { 'use strict'; const NAV_WIDTH = 250; const DEBOUNCE_TIME = 500; const AISTUDIO_DEBOUNCE_TIME = 200; let activeMessageIndex = -1; let lastUrl = window.location.href; let lastPromptsContent = ""; let cachedPrompts = []; let urlCheckInterval = null; let injectedStyleId = 'nav-shift-styles'; let bookmarkedMessages = new Set(); let conversationObserver = null; let isClosedByUser = false; window.navigatorUpdateTimeout = null; function injectStyles() { GM_addStyle(` #message-nav { position: fixed; top: 0; right: 0; bottom: 0; width: ${NAV_WIDTH}px; overflow-y: auto; z-index: 9999; font-family: Calibri, sans-serif; font-size: 17px; color: CanvasText; text-align: left; border-left: 1px solid color-mix(in srgb, CanvasText 15%, transparent); } #nav-header { display: flex; align-items: center; justify-content: center; position: sticky; top: 0; z-index: 10; padding: 12px 10px 12px 10px; background-color: Canvas; border-bottom: 1px solid color-mix(in srgb, CanvasText 15%, transparent); } #nav-buttons-group { display: flex; gap: 0; align-items: center; } .nav-control-btn { background: none; border: none; cursor: pointer; font-size: 16px; color: inherit; padding: 2px 5px; } #nav-btn-close { position: absolute; top: 0; right: 0; background: none; border: none; cursor: pointer; font-size: 15px; color: inherit; border: 1px solid color-mix(in srgb, CanvasText 10%, transparent); display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 4px; } #nav-message-counter { padding: 0; min-width: 40px; text-align: center; font-size: 15px; font-weight: normal; user-select: none; color: color-mix(in srgb, CanvasText 80%, transparent); } #message-nav-content { padding: 5px; } #nav-list { padding: 0; margin: 0; list-style: none; } .nav-list-item { cursor: pointer; padding: 5px 0 5px 5px; font-weight: normal; transition: font-weight 0.1s ease; } .nav-list-item.active { font-weight: bold !important; background-color: color-mix(in srgb, CanvasText 10%, transparent); } @keyframes nav-blink-animation { 0% { opacity: 1; } 50% { opacity: 0.1; } 100% { opacity: 1; } } .nav-blink-active { animation: nav-blink-animation 0.5s ease-in-out 3; } .nav-item-number { display: inline; cursor: pointer; user-select: none; } .nav-item-number.bookmarked { background-color: #fff59d !important; color: black !important; padding: 2px 4px; border-radius: 3px; } .nav-version-controls { display: inline-flex; align-items: center; margin-left: 5px; gap: 2px; border-radius: 10px; padding: 2px; border: 1px solid color-mix(in srgb, CanvasText 20%, transparent); } .nav-version-btn { background: none; border: none; cursor: pointer; font-size: 12px; padding: 1px 4px; border-radius: 3px; color: inherit; line-height: 1; } .nav-version-btn:hover { background-color: color-mix(in srgb, CanvasText 10%, transparent); } .nav-version-btn:disabled { opacity: 0.3; cursor: not-allowed; } .nav-version-text { font-size: 12px; color: color-mix(in srgb, CanvasText 70%, transparent); margin: 0 2px; } .nav-bookmarks-container { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; padding: 4px 10px; background-color: Canvas; border-bottom: 1px solid color-mix(in srgb, CanvasText 10%, transparent); min-height: 34px; box-sizing: border-box; width: 100%; flex-shrink: 0; position: sticky; z-index: 9; } .nav-bookmark-item { background-color: #fff59d; color: black; padding: 3px 6px; border-radius: 3px; cursor: pointer; font-size: 15px; user-select: none; transition: background-color 0.2s; } .nav-bookmark-item:hover { background-color: #fff176; } .nav-bookmark-item.active { font-weight: bold; background-color: #ffeb3b; } `); const allUserSelectors = Object.values(SITE_CONFIGS) .map(config => config.userMessage) .filter(selector => typeof selector === 'string' && selector.length > 0) .join(', '); if (allUserSelectors) { GM_addStyle(`${allUserSelectors} { scroll-margin-top: 10px !important; }`); } } function getAIStudioData() { const prompts = []; const scrollButtons = document.querySelectorAll('ms-prompt-scrollbar button[id^="scrollbar-item-"]'); scrollButtons.forEach(btn => { const isUser = btn.querySelector('.prompt-scrollbar-dot'); if (isUser) { let text = btn.getAttribute('aria-label'); if (!text && (btn.querySelector('img') || btn.querySelector('mat-icon'))) { text = "[Img]"; } if (text) { prompts.push({ element: btn, text: text.trim() }); } } }); return prompts; } function getVersionInfo(container, vc) { if (!container || !vc) return null; const versionText = container.querySelector(vc.versionTextSelector); if (!versionText) return null; const text = versionText.textContent.trim(); const match = text.match(/(\d+)\s*\/\s*(\d+)/); if (!match) return null; const currentVersion = parseInt(match[1]); const totalVersions = parseInt(match[2]); const prevButton = container.querySelector(vc.prevButtonSelector); const nextButton = container.querySelector(vc.nextButtonSelector); return { currentVersion, totalVersions, prevButton, nextButton, hasMultipleVersions: totalVersions > 1 }; } const SITE_CONFIGS = { chatgpt: { domain: 'chatgpt.com', userMessage: 'div[data-message-author-role="user"]', userMessageFile: '.p-2.w-60', userMessageText: '.user-message-bubble-color', userMessageImage: 'img', shiftTarget: '[data-scroll-root]', versionControl: { containerSelector: '.z-0.flex.justify-end', versionTextSelector: '.tabular-nums', prevButtonSelector: 'button[aria-label*="Previous response"]', nextButtonSelector: 'button[aria-label*="Next response"]' } }, gemini: { domain: 'gemini.google.com', userMessage: '.user-query-container .user-query-container .user-query-container', userMessageFile: '.file-preview-container', userMessageText: '.query-text', userMessageImage: '.preview-image', shiftTarget: 'chat-app, .boqOnegoogleliteOgbOneGoogleBar, top-bar-actions', }, aistudio: { domain: 'aistudio.google.com', customFinder: getAIStudioData, useClick: true, shiftTarget: '.layout-wrapper', fastUpdate: true, debounceTime: AISTUDIO_DEBOUNCE_TIME, }, notebooklm: { domain: 'notebooklm.google.com', userMessage: 'chat-message .from-user-container', shiftTarget: 'notebook, .boqOnegoogleliteOgbOneGoogleBar', }, grok: { domain: 'grok.com', userMessage: '.relative.group.flex.flex-col.justify-center.items-end .message-bubble', shiftTarget: 'main', versionControl: { containerSelector: '.relative.group.flex.flex-col.justify-center.items-end .action-buttons', versionTextSelector: '[class="px-0.5"]', prevButtonSelector: 'button[aria-label="Previous message"]', nextButtonSelector: 'button[aria-label="Next message"]' } }, claude: { domain: 'claude.ai', userMessage: '.mb-1.mt-6.group', userMessageFile: '[data-testid="file-thumbnail"] p', userMessageImage: '[data-testid*="."]', userMessageText: '[data-testid="user-message"]', shiftTarget: '#main-content', versionControl: { containerSelector: '.mb-1.mt-6.group', versionTextSelector: '.self-center.select-none', prevButtonSelector: 'button[aria-label="Previous"]', nextButtonSelector: 'button[aria-label="Next"]' } }, mistral: { domain: 'chat.mistral.ai', userMessage: 'div[data-message-author-role="user"] div[dir="auto"]', shiftTarget: 'main.bg-sidebar-subtle', versionControl: { containerSelector: 'div[data-message-author-role="user"]', versionTextSelector: '[class*="text-muted"][class*="dark:text-muted"]', prevButtonSelector: 'button[aria-label*="Previous version"]', nextButtonSelector: 'button[aria-label*="Next version"]' } }, deepseek: { domain: 'chat.deepseek.com', userMessage: '._9663006 .fbb737a4', shiftTarget: '._8f60047, ._189b4a0, ._2be88ba', versionControl: { containerSelector: '._9663006', versionTextSelector: '.dd7e4fda', prevButtonSelector: '.e7367035:first-of-type', nextButtonSelector: '.e7367035:last-of-type' } }, kimi: { domain: 'www.kimi.com', userMessage: '.user-content', shiftTarget: '.has-sidebar', }, glm: { domain: 'chat.z.ai', userMessage: '.chat-user .flex.justify-end.pb-1', shiftTarget:'#chat-container', versionControl: { containerSelector: '.chat-user .flex.justify-end.text-gray-600', versionTextSelector: '.self-center.text-sm.font-semibold.tracking-widest', prevButtonSelector: '.self-center.p-1.rounded-md.transition:first-of-type', nextButtonSelector: '.self-center.p-1.rounded-md.transition:last-of-type' } }, qwen: { domain: 'chat.qwen.ai', userMessage: '.chat-user-message', shiftTarget: '.desktop-layout-content', versionControl: { containerSelector: '.user-message-footer.ant-flex', versionTextSelector: '.qwen-chat-ui-packages-siblings-text', prevButtonSelector: '.anticon.qwen-chat-ui-packages-siblings-active-icon:first-of-type', nextButtonSelector: '.anticon.qwen-chat-ui-packages-siblings-active-icon:last-of-type' } }, chatglm: { domain: 'chatglm.cn', userMessage: '.question-txt.dots', shiftTarget: '.detail-container', }, ernie: { domain: 'ernie.baidu.com', userMessage: '#question_text_id', shiftTarget: '#root', reverse: true, }, meta: { domain: 'meta.ai', userMessage: '.x78zum5.x15zctf7', shiftTarget: '.xph554m.x73z65k', }, perplexity: { domain: 'perplexity.ai', userMessage: 'div.group\\/title', shiftTarget: '#root', }, poe: { domain: 'poe.com', userMessage: '[class*="ChatMessagesView_tupleGroupContainer"] > div > div:first-child', shiftTarget: '[class*="CanvasSidebarLayout_chat-column"]' }, deepai: { domain: 'deepai.org', userMessage: '.chatbox', shiftTarget: '.chat-layout-container, .new-chat-button-container, .persistent-compose-area, .nav-items' }, huggingface: { domain: 'huggingface.co', userMessage: '.disabled.w-full.appearance-none', shiftTarget: '.relative.min-h-0.min-w-0' }, manus: { domain: 'manus.im', userMessage: '.flex.relative.flex-col.gap-2.items-end', shiftTarget: '.simplebar-content' }, longcat: { domain: 'longcat.chat', userMessage: '.user-message', shiftTarget: '.content', }, chatboxai: { domain: 'web.chatboxai.app', userMessage: '.user-msg', shiftTarget: '.h-full.w-full.MuiBox-root' }, lmarena: { domain: 'lmarena.ai', userMessage: '.justify-end.gap-2', shiftTarget: '#chat-area', reverse: true }, quillbot: { domain: 'quillbot.com', userMessage: 'div.MuiGrid-root.MuiGrid-container > div.MuiGrid-root > p.MuiTypography-root.MuiTypography-bodyMedium.MuiTypography-paragraph', shiftTarget: '#root-client' }, canva: { domain: 'www.canva.com', userMessage: '#_r_1_ .uV9Uzw .Ka9auQ p', shiftTarget: '#root' }, genspark: { domain: 'www.genspark.ai', userMessage: '.conversation-item-desc.user', shiftTarget: '.n-config-provider' }, character: { domain: 'character.ai', userMessage: '.w-full .bg-surface-elevation-3.opacity-90', shiftTarget: '#__next, #chat-header-background', reverse: true }, spacefrontiers: { domain: 'spacefrontiers.org', userMessage: '.inline.whitespace-pre-line', shiftTarget: '#app' }, scienceos: { domain: 'app.scienceos.ai', userMessage: 'div[data-prompt]', shiftTarget: 'div[data-strategy]' }, evidencehunt: { domain: 'evidencehunt.com', userMessage: '.chat__message:has(.message__user-image) .message__content p', shiftTarget: '.v-main' }, playground: { domain: 'playground.allenai.org', userMessage: 'div[class*="chat-message"]:nth-of-type(even)', shiftTarget: '.MuiPaper-outlined' }, paperfigure: { domain: 'paperfigureqa.allen.ai', userMessage: '#chat-scroll-container > div > div:nth-of-type(odd) .MuiPaper-root', shiftTarget: '#root' }, scira: { domain: 'scira.ai', userMessage: '.max-w-full .relative', shiftTarget: '.sm\\:max-w-2xl' }, exa: { domain: 'exa.ai', userMessage: 'div[data-test-id="UserMessage"]', shiftTarget: 'div[data-test-id="ChatPresentation"]' }, consensus: { domain: 'consensus.app', userMessage: '.flex.flex-col.pt-6.w-full.max-w-page h2', shiftTarget: '#__next' }, openevidence: { domain: 'openevidence.com', userMessage: '.brandable--query-bar--container form', shiftTarget: '#__next, .brandable--query-bar--container.hide-on-print.follow-up' }, mathgpt: { domain: 'math-gpt.org', userMessage: '.w-full.flex.items-end.flex-col.pb-8.relative', shiftTarget: '.overflow-x-hidden, .px-2.flex.flex-col.gap-1' }, }; function getCurrentConfig() { const hostname = window.location.hostname; for (const key in SITE_CONFIGS) { if (hostname.includes(SITE_CONFIGS[key].domain)) { return SITE_CONFIGS[key]; } } return null; } const CURRENT_SITE = getCurrentConfig(); if (!CURRENT_SITE) return; function hasUserMessages() { if (CURRENT_SITE.customFinder) { const prompts = CURRENT_SITE.customFinder(); return prompts && prompts.length > 0; } if (!CURRENT_SITE.userMessage) return false; const elements = document.querySelectorAll(CURRENT_SITE.userMessage); return elements && elements.length > 0; } const getShiftStyle = (width, selector = '') => { if (!selector) return ''; const selectors = selector.split(','); const prefixedSelector = selectors.map(s => `body.navigator-expanded ${s.trim()}`).join(', '); return ` ${selector} { transition: margin-right 0.3s ease, max-width 0.3s ease, margin-left 0.3s ease; } ${prefixedSelector} { margin-left: 0 !important; margin-right: ${width}px !important; max-width: calc(100% - ${width}px) !important; } `; }; function updateShiftStyles(shouldInject) { let existingStyle = document.getElementById(injectedStyleId); if (shouldInject && !existingStyle) { const currentWidth = CURRENT_SITE.width || NAV_WIDTH; let cssContent = ''; if (CURRENT_SITE.shiftTarget) { cssContent += getShiftStyle(currentWidth, CURRENT_SITE.shiftTarget); } if (cssContent) { const styleElement = document.createElement('style'); styleElement.id = injectedStyleId; styleElement.textContent = cssContent; document.head.appendChild(styleElement); } } else if (!shouldInject && existingStyle) { existingStyle.remove(); } } function updateBodyClassForLayout() { const container = document.getElementById('message-nav'); if (!container || container.style.display === 'none') { document.body.classList.remove('navigator-expanded'); return; } document.body.classList.add('navigator-expanded'); } function toggleBookmark(index) { if (bookmarkedMessages.has(index)) { bookmarkedMessages.delete(index); } else { bookmarkedMessages.add(index); } updateBookmarkVisuals(); updateBookmarksHeader(); } function updateBookmarkVisuals() { const content = document.getElementById('message-nav-content'); if (!content) return; const list = content.querySelector('#nav-list'); if (!list) return; const items = list.querySelectorAll('.nav-list-item'); items.forEach((item, idx) => { const numberContainer = item.querySelector('.nav-item-number'); if (numberContainer) { const index = idx + 1; if (bookmarkedMessages.has(index)) { numberContainer.textContent = `${index}`; numberContainer.classList.add('bookmarked'); } else { numberContainer.textContent = `${index}.`; numberContainer.classList.remove('bookmarked'); } } }); } function updateBookmarksHeader() { let bookmarksContainer = document.getElementById('nav-bookmarks-header'); const header = document.getElementById('nav-header'); if (!header) return; if (bookmarkedMessages.size === 0 || cachedPrompts.length < 6) { if (bookmarksContainer) { bookmarksContainer.remove(); } return; } if (!bookmarksContainer) { bookmarksContainer = document.createElement('div'); bookmarksContainer.id = 'nav-bookmarks-header'; bookmarksContainer.className = 'nav-bookmarks-container'; bookmarksContainer.style.top = header.offsetHeight + 'px'; header.parentNode.insertBefore(bookmarksContainer, header.nextSibling); } while (bookmarksContainer.firstChild) { bookmarksContainer.removeChild(bookmarksContainer.firstChild); } const sortedBookmarks = Array.from(bookmarkedMessages).sort((a, b) => a - b); sortedBookmarks.forEach(index => { const bookmarkItem = document.createElement('span'); bookmarkItem.className = 'nav-bookmark-item'; bookmarkItem.textContent = index; if (index === activeMessageIndex) { bookmarkItem.classList.add('active'); } bookmarkItem.addEventListener('click', () => { navigateToMessage(index); }); bookmarksContainer.appendChild(bookmarkItem); }); } function updateMessageCounter() { const counterSpan = document.getElementById('nav-message-counter'); if (counterSpan) { const current = activeMessageIndex > 0 ? activeMessageIndex : (cachedPrompts.length > 0 ? 1 : 0); const total = cachedPrompts.length; counterSpan.textContent = `${current}/${total}`; } } function navigateToMessage(messageIndex) { const targetElement = findPromptElementByIndex(messageIndex - 1); if (!targetElement) return; const list = document.getElementById('nav-list'); if (list) { list.querySelectorAll('.nav-list-item').forEach(li => li.classList.remove('active')); const targetItem = list.children[messageIndex - 1]; if (targetItem) { targetItem.classList.add('active'); targetItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } } activeMessageIndex = messageIndex; updateMessageCounter(); updateBookmarksHeader(); if (CURRENT_SITE.useClick) { targetElement.click(); } else { targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); } const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { targetElement.classList.add('nav-blink-active'); setTimeout(() => targetElement.classList.remove('nav-blink-active'), 2000); observer.unobserve(targetElement); } }); }, { threshold: 0.5 }); observer.observe(targetElement); } function createContainer() { let container = document.getElementById('message-nav'); if (!container) { container = document.createElement('div'); container.id = 'message-nav'; const header = document.createElement('div'); header.id = 'nav-header'; const navButtonsContainer = document.createElement('div'); navButtonsContainer.id = 'nav-buttons-group'; const firstBtn = document.createElement('button'); firstBtn.id = 'nav-btn-first'; firstBtn.className = 'nav-control-btn'; firstBtn.textContent = '|◀'; firstBtn.title = 'Go to first message'; firstBtn.addEventListener('click', (e) => { e.stopPropagation(); if (cachedPrompts.length > 0) { navigateToMessage(1); } }); const prevBtn = document.createElement('button'); prevBtn.id = 'nav-btn-prev'; prevBtn.className = 'nav-control-btn'; prevBtn.textContent = '◀'; prevBtn.title = 'Go to previous message'; prevBtn.addEventListener('click', (e) => { e.stopPropagation(); if (cachedPrompts.length > 0 && activeMessageIndex > 1) { navigateToMessage(activeMessageIndex - 1); } }); const messageCounter = document.createElement('span'); messageCounter.id = 'nav-message-counter'; const nextBtn = document.createElement('button'); nextBtn.id = 'nav-btn-next'; nextBtn.className = 'nav-control-btn'; nextBtn.textContent = '▶'; nextBtn.title = 'Go to next message'; nextBtn.addEventListener('click', (e) => { e.stopPropagation(); if (cachedPrompts.length > 0 && activeMessageIndex < cachedPrompts.length) { navigateToMessage(activeMessageIndex + 1); } }); const lastBtn = document.createElement('button'); lastBtn.id = 'nav-btn-last'; lastBtn.className = 'nav-control-btn'; lastBtn.textContent = '▶|'; lastBtn.title = 'Go to last message'; lastBtn.addEventListener('click', (e) => { e.stopPropagation(); if (cachedPrompts.length > 0) { navigateToMessage(cachedPrompts.length); } }); navButtonsContainer.appendChild(firstBtn); navButtonsContainer.appendChild(prevBtn); navButtonsContainer.appendChild(messageCounter); navButtonsContainer.appendChild(nextBtn); navButtonsContainer.appendChild(lastBtn); const closeBtn = document.createElement('button'); closeBtn.id = 'nav-btn-close'; closeBtn.textContent = '✕'; header.appendChild(navButtonsContainer); header.appendChild(closeBtn); const content = document.createElement('div'); content.id = 'message-nav-content'; container.appendChild(header); container.appendChild(content); document.body.appendChild(container); closeBtn.addEventListener('click', (e) => { e.stopPropagation(); container.style.display = 'none'; isClosedByUser = true; updateBodyClassForLayout(); }); updateBodyClassForLayout(); } return container; } function findUserPrompts() { if (CURRENT_SITE.customFinder) return CURRENT_SITE.customFinder(); let prompts = []; if (!CURRENT_SITE.userMessage) return prompts; const userElements = Array.from(document.querySelectorAll(CURRENT_SITE.userMessage)); let containerElements = []; if (CURRENT_SITE.versionControl && CURRENT_SITE.versionControl.containerSelector) { containerElements = Array.from(document.querySelectorAll(CURRENT_SITE.versionControl.containerSelector)); } if (CURRENT_SITE.reverse) { userElements.reverse(); containerElements.reverse(); } userElements.forEach((element, index) => { let text = ""; if (CURRENT_SITE.userMessageFile && CURRENT_SITE.userMessageText && CURRENT_SITE.userMessageImage) { const fileEl = element.querySelector(CURRENT_SITE.userMessageFile); const msgEl = element.querySelector(CURRENT_SITE.userMessageText); const imageEl = element.querySelector(CURRENT_SITE.userMessageImage); const fileText = fileEl ? fileEl.textContent.trim() : ""; const msgText = msgEl ? msgEl.textContent.trim() : ""; const hasImage = !!imageEl; if (msgText) { if (fileText && hasImage) { text = `[File+Img] ${msgText}`; } else if (fileText) { text = `[File] ${msgText}`; } else if (hasImage) { text = `[Img] ${msgText}`; } else { text = msgText; } } else { if (fileText && hasImage) { text = `[File+Img] ${fileText}`; } else if (fileText) { text = `[File] ${fileText}`; } else if (hasImage) { text = "[Img]"; } else { text = "[File]"; } } } else { text = element.textContent.trim(); if (!text && (element.querySelector('img') || element.querySelector('canvas') || element.querySelector('svg'))) { text = "[Img]"; } } if (text) { const promptData = { element, text }; if (CURRENT_SITE.versionControl && containerElements[index]) { const versionInfo = getVersionInfo(containerElements[index], CURRENT_SITE.versionControl); if (versionInfo) { promptData.versionInfo = versionInfo; } } prompts.push(promptData); } }); return prompts; } function findPromptElementByIndex(targetIndex) { if (CURRENT_SITE.customFinder) { const prompts = CURRENT_SITE.customFinder(); return prompts[targetIndex] ? prompts[targetIndex].element : null; } if (!CURRENT_SITE.userMessage) return null; const elements = Array.from(document.querySelectorAll(CURRENT_SITE.userMessage)); if (CURRENT_SITE.reverse) elements.reverse(); return elements[targetIndex] || null; } function createListItem(prompt, index) { const listItem = document.createElement('li'); listItem.className = 'nav-list-item'; if (index === activeMessageIndex) listItem.classList.add('active'); const preview = prompt.text.length > 80 ? prompt.text.slice(0, 80) + '...' : prompt.text; const numberContainer = document.createElement('span'); numberContainer.className = 'nav-item-number'; if (bookmarkedMessages.has(index)) { numberContainer.textContent = `${index}`; numberContainer.classList.add('bookmarked'); } else { numberContainer.textContent = `${index}.`; } numberContainer.addEventListener('click', (e) => { e.stopPropagation(); toggleBookmark(index); }); const textSpan = document.createElement('span'); textSpan.textContent = ` ${preview}`; listItem.appendChild(numberContainer); listItem.appendChild(textSpan); if (prompt.versionInfo && prompt.versionInfo.hasMultipleVersions) { const versionControls = document.createElement('span'); versionControls.className = 'nav-version-controls'; const prevVersionBtn = document.createElement('button'); prevVersionBtn.className = 'nav-version-btn'; prevVersionBtn.textContent = '◀'; prevVersionBtn.title = 'Previous version'; prevVersionBtn.disabled = !prompt.versionInfo.prevButton || prompt.versionInfo.prevButton.disabled; prevVersionBtn.addEventListener('click', (e) => { e.stopPropagation(); if (prompt.versionInfo.prevButton && !prompt.versionInfo.prevButton.disabled) { prompt.versionInfo.prevButton.click(); setTimeout(() => updateMessageList(true), 300); } }); const versionText = document.createElement('span'); versionText.className = 'nav-version-text'; versionText.textContent = `${prompt.versionInfo.currentVersion}/${prompt.versionInfo.totalVersions}`; const nextVersionBtn = document.createElement('button'); nextVersionBtn.className = 'nav-version-btn'; nextVersionBtn.textContent = '▶'; nextVersionBtn.title = 'Next version'; nextVersionBtn.disabled = !prompt.versionInfo.nextButton || prompt.versionInfo.nextButton.disabled; nextVersionBtn.addEventListener('click', (e) => { e.stopPropagation(); if (prompt.versionInfo.nextButton && !prompt.versionInfo.nextButton.disabled) { prompt.versionInfo.nextButton.click(); setTimeout(() => updateMessageList(true), 300); } }); versionControls.appendChild(prevVersionBtn); versionControls.appendChild(versionText); versionControls.appendChild(nextVersionBtn); listItem.appendChild(versionControls); } textSpan.addEventListener('click', () => { navigateToMessage(index); }); return listItem; } function updateMessageList(forceUpdate = false) { const currentUrl = window.location.href; let container = document.getElementById('message-nav'); if (currentUrl !== lastUrl) { lastUrl = currentUrl; lastPromptsContent = ""; activeMessageIndex = -1; cachedPrompts = []; bookmarkedMessages.clear(); isClosedByUser = false; forceUpdate = true; } const shouldShow = hasUserMessages(); updateShiftStyles(shouldShow); if (!shouldShow || isClosedByUser) { if (container) container.style.display = 'none'; document.body.classList.remove('navigator-expanded'); updateBodyClassForLayout(); return; } const activeContainer = createContainer(); activeContainer.style.display = 'block'; updateBodyClassForLayout(); const content = document.getElementById('message-nav-content'); if (!content) return; let list = document.getElementById('nav-list'); if (!list) { list = document.createElement('ul'); list.id = 'nav-list'; content.appendChild(list); } const prompts = findUserPrompts(); const currentPromptsContent = prompts.map(p => p.text).join('|'); if (!forceUpdate && currentPromptsContent === lastPromptsContent) return; lastPromptsContent = currentPromptsContent; cachedPrompts = prompts; while (list.firstChild) list.removeChild(list.firstChild); prompts.forEach((prompt, index) => { const listItem = createListItem(prompt, index + 1); list.appendChild(listItem); }); updateMessageCounter(); updateBookmarksHeader(); } function startUrlWatcher() { if (!CURRENT_SITE.fastUpdate) return; if (urlCheckInterval) clearInterval(urlCheckInterval); urlCheckInterval = setInterval(() => { const currentUrl = window.location.href; if (currentUrl !== lastUrl) updateMessageList(true); }, 300); } function observeConversation() { if (conversationObserver) conversationObserver.disconnect(); const debounceTime = CURRENT_SITE.debounceTime || DEBOUNCE_TIME; conversationObserver = new MutationObserver(() => { clearTimeout(window.navigatorUpdateTimeout); window.navigatorUpdateTimeout = setTimeout(() => updateMessageList(), debounceTime); }); conversationObserver.observe(document.body, { childList: true, subtree: true }); window.addEventListener('popstate', () => { lastPromptsContent = ""; cachedPrompts = []; updateMessageList(true); }); const originalPushState = history.pushState; history.pushState = function() { originalPushState.apply(this, arguments); lastPromptsContent = ""; cachedPrompts = []; setTimeout(() => updateMessageList(true), 100); }; } injectStyles(); setTimeout(() => { updateMessageList(true); startUrlWatcher(); }, 1000); observeConversation(); })();