| 2130 | 2130 | `, |
| 2131 | 2131 | })); |
| 2132 | 2132 | |
| 2133 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2134 | + name: 'goto-floor', |
| 2135 | + aliases: ['floor', 'jump', 'scrollto'], |
| 2136 | + callback: async (_, index) => { |
| 2137 | + const floorIndex = Number(index); |
| 2138 | + |
| 2139 | + // Validate input |
| 2140 | + if (isNaN(floorIndex) || floorIndex < 0 || (typeof chat !== 'undefined' && floorIndex >= chat.length)) { |
| 2141 | + const maxIndex = (typeof chat !== 'undefined' ? chat.length - 1 : 'unknown'); |
| 2142 | + toastr.warning(`Invalid message index: ${index}. Please enter a number between 0 and ${maxIndex}.`); |
| 2143 | + console.warn(`WARN: Invalid message index provided for /goto-floor: ${index}. Max index: ${maxIndex}`); |
| 2144 | + return ''; |
| 2145 | + } |
| 2146 | + |
| 2147 | + const messageElement = document.querySelector(`[mesid="${floorIndex}"]`); |
| 2148 | + |
| 2149 | + if (messageElement) { |
| 2150 | + const headerElement = messageElement.querySelector('.mes_header') || |
| 2151 | + messageElement.querySelector('.mes_meta') || |
| 2152 | + messageElement.querySelector('.mes_name_area') || |
| 2153 | + messageElement.querySelector('.mes_name'); |
| 2154 | + |
| 2155 | + const elementToScroll = headerElement || messageElement; // Prefer header, fallback to whole message |
| 2156 | + const blockPosition = headerElement ? 'center' : 'start'; // Center header, else start of message |
| 2157 | + |
| 2158 | + elementToScroll.scrollIntoView({ behavior: 'smooth', block: blockPosition }); |
| 2159 | + console.log(`INFO: Scrolled ${headerElement ? 'header of' : ''} message ${floorIndex} into view (block: ${blockPosition}).`); |
| 2160 | + |
| 2161 | + // --- Highlight with smooth animation --- |
| 2162 | + messageElement.classList.add('highlight-scroll'); |
| 2163 | + setTimeout(() => { |
| 2164 | + // Add a class to fade out, then remove the highlight class after fade |
| 2165 | + messageElement.classList.add('highlight-scroll-fadeout'); |
| 2166 | + // Wait for fadeout transition to complete before removing the base class |
| 2167 | + // Match this duration to the transition duration in CSS |
| 2168 | + setTimeout(() => { |
| 2169 | + messageElement.classList.remove('highlight-scroll', 'highlight-scroll-fadeout'); |
| 2170 | + }, 500); // Matches the 0.5s transition duration |
| 2171 | + }, 1500); // Start fade out after 1.5 seconds |
| 2172 | + |
| 2173 | + } else { |
| 2174 | + toastr.warning(`Could not find element for message ${floorIndex} (using [mesid="${floorIndex}"]). It might not be rendered yet. Try scrolling up or use /chat-render all.`); |
| 2175 | + console.warn(`WARN: Element not found for message index ${floorIndex} using querySelector [mesid="${floorIndex}"] in /goto-floor.`); |
| 2176 | + const chatContainer = document.getElementById('chat'); |
| 2177 | + if (chatContainer) { |
| 2178 | + chatContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
| 2179 | + } |
| 2180 | + } |
| 2181 | + return ''; |
| 2182 | + }, |
| 2183 | + unnamedArgumentList: [ |
| 2184 | + SlashCommandArgument.fromProps({ |
| 2185 | + description: 'The message index (0-based) to scroll to.', |
| 2186 | + typeList: [ARGUMENT_TYPE.NUMBER], |
| 2187 | + isRequired: true, |
| 2188 | + enumProvider: commonEnumProviders.messages(), |
| 2189 | + }), |
| 2190 | + ], |
| 2191 | + helpString: ` |
| 2192 | + <div> |
| 2193 | + Scrolls the chat view to the specified message index. Uses the <code>[mesid]</code> attribute for locating the message element. Index starts at 0. |
| 2194 | + It attempts to center the character's name/header area within the message block. Highlights the message using the theme's 'matchedText' color with a smooth animation. |
| 2195 | + </div> |
| 2196 | + <div> |
| 2197 | + <strong>Example:</strong> <pre><code>/goto-floor 10</code></pre> Scrolls to the 11th message (mesid=10). |
| 2198 | + </div> |
| 2199 | + <div> |
| 2200 | + Note: Due to virtual scrolling, very old messages might need loading first. |
| 2201 | + </div> |
| 2202 | + `, |
| 2203 | + })); |
| 2204 | + |
| 2205 | + // --- Improved CSS for highlight --- |
| 2206 | + const styleId = 'goto-floor-highlight-style'; |
| 2207 | + if (!document.getElementById(styleId)) { |
| 2208 | + const style = document.createElement('style'); |
| 2209 | + style.id = styleId; |
| 2210 | + style.textContent = ` |
| 2211 | + /* Base state for elements that *can* be highlighted */ |
| 2212 | + /* Ensures transition applies smoothly in both directions */ |
| 2213 | + .mes, .mes_block { |
| 2214 | + transition: background-color 0.5s ease-in-out, box-shadow 0.5s ease-in-out; |
| 2215 | + /* Add position relative if not already present, needed for potential pseudo-elements */ |
| 2216 | + position: relative; |
| 2217 | + } |
| 2218 | + |
| 2219 | + /* --- Highlighting Style --- */ |
| 2220 | + .mes.highlight-scroll, |
| 2221 | + .mes_block.highlight-scroll { |
| 2222 | + /* Use theme color for shadow, fallback to gold */ |
| 2223 | + box-shadow: 0 0 10px var(--ac-style-color-matchedText, #FFD700) !important; |
| 2224 | + z-index: 5; /* Ensure highlight is visually prominent */ |
| 2225 | + } |
| 2226 | + |
| 2227 | + /* Modern browsers: Use color-mix for transparent background */ |
| 2228 | + @supports (background-color: color-mix(in srgb, white 50%, black)) { |
| 2229 | + .mes.highlight-scroll, |
| 2230 | + .mes_block.highlight-scroll { |
| 2231 | + /* Mix theme color with transparent for background */ |
| 2232 | + background-color: color-mix(in srgb, var(--ac-style-color-matchedText, #FFD700) 35%, transparent) !important; |
| 2233 | + } |
| 2234 | + } |
| 2235 | + |
| 2236 | + /* Fallback for older browsers: Use a fixed semi-transparent background */ |
| 2237 | + @supports not (background-color: color-mix(in srgb, white 50%, black)) { |
| 2238 | + .mes.highlight-scroll, |
| 2239 | + .mes_block.highlight-scroll { |
| 2240 | + background-color: rgba(255, 215, 0, 0.35) !important; /* Fallback semi-transparent gold */ |
| 2241 | + } |
| 2242 | + } |
| 2243 | + |
| 2244 | + /* --- Fade-out Control --- */ |
| 2245 | + /* When fading out, explicitly transition back to transparent/none */ |
| 2246 | + .mes.highlight-scroll-fadeout, |
| 2247 | + .mes_block.highlight-scroll-fadeout { |
| 2248 | + background-color: transparent !important; |
| 2249 | + box-shadow: none !important; |
| 2250 | + } |
| 2251 | + `; |
| 2252 | + document.head.appendChild(style); |
| 2253 | + } |
| 2133 | 2254 | registerVariableCommands(); |
| 2134 | 2255 | } |
| 2135 | 2256 | |