├── .gitignore ├── extension ├── icons │ ├── icon_128.png │ ├── icon_16.png │ ├── icon_32.png │ └── icon_48.png ├── background.js ├── popup.js ├── manifest.json ├── popup.html ├── style.css ├── content.js ├── jquery-ui.min.css └── jquery-3.7.1.min.js ├── LICENSE ├── CONTRIBUTING.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | extension/p.py 2 | .cursor/rules 3 | -------------------------------------------------------------------------------- /extension/icons/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saarthakkj/chat-navigator/HEAD/extension/icons/icon_128.png -------------------------------------------------------------------------------- /extension/icons/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saarthakkj/chat-navigator/HEAD/extension/icons/icon_16.png -------------------------------------------------------------------------------- /extension/icons/icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saarthakkj/chat-navigator/HEAD/extension/icons/icon_32.png -------------------------------------------------------------------------------- /extension/icons/icon_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Saarthakkj/chat-navigator/HEAD/extension/icons/icon_48.png -------------------------------------------------------------------------------- /extension/background.js: -------------------------------------------------------------------------------- 1 | // This file is intentionally left blank or for future background tasks not related to URL detection. 2 | console.log('[Background] Script loaded. Currently minimal, URL detection moved to content.js'); 3 | -------------------------------------------------------------------------------- /extension/popup.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | const themeSelector = document.getElementById('themeSelector'); 3 | const sidebar = document.getElementById('chat'); 4 | 5 | // Load saved theme and set initial state 6 | chrome.storage.sync.get('theme', function(data) { 7 | const savedTheme = data.theme || 'red'; // Default to red 8 | themeSelector.value = savedTheme; 9 | if (sidebar) { 10 | sidebar.className = 'sidebar theme-' + savedTheme; 11 | } 12 | }); 13 | 14 | // Theme switching 15 | themeSelector.addEventListener('change', function(e) { 16 | const selectedTheme = e.target.value; 17 | // Save the theme to storage 18 | chrome.storage.sync.set({theme: selectedTheme}, function() { 19 | console.log('Theme saved:', selectedTheme); 20 | }); 21 | // Update popup sidebar 22 | if (sidebar) { 23 | sidebar.className = 'sidebar theme-' + selectedTheme; 24 | } 25 | }); 26 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Chat Navigator 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Chat Navigtator", 4 | "version": "1.0", 5 | "description": "Helps you navigate through your chat history with ease.", 6 | 7 | "permissions": [ 8 | "tabs", 9 | "storage" 10 | ], 11 | 12 | "host_permissions": [ 13 | "https://*.google.com/*", 14 | "https://gemini.google.com/*", 15 | "https://grok.com/*" 16 | ], 17 | "content_scripts": [ 18 | { 19 | "matches": [ 20 | "https://chat.openai.com/*", 21 | "https://chatgpt.com/*", 22 | "https://claude.ai/*", 23 | "https://*.perplexity.ai/*", 24 | "https://t3.chat/*", 25 | "https://gemini.google.com/*", 26 | "https://grok.com/*" 27 | ], 28 | "css": ["style.css" , "jquery-ui.min.css"], 29 | "js": [ 30 | "jquery-3.7.1.min.js", 31 | "jquery-ui.min.js", 32 | "content.js" 33 | ], 34 | "run_at": "document_idle" 35 | } 36 | ], 37 | "action": { 38 | "default_popup": "popup.html", 39 | "default_icon": { 40 | "16": "icons/icon_16.png", 41 | "48": "icons/icon_32.png", 42 | "128": "icons/icon_128.png" 43 | }, 44 | "default_title": "My Page Modifier" 45 | }, 46 | 47 | "background": { 48 | "service_worker": "background.js" 49 | }, 50 | "icons": { 51 | "16": "icons/icon_16.png", 52 | "48": "icons/icon_32.png", 53 | "128": "icons/icon_128.png" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /extension/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Chat Navigator 7 | 8 | 9 | 21 |
34 |

35 | Chat Navigator 36 |

37 | 38 | 50 | 79 |
80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Chat Navigator 2 | 3 | Thank you for your interest in contributing to Chat Navigator! This document provides guidelines and instructions for contributing to this project. 4 | 5 | ## Code of Conduct 6 | 7 | By participating in this project, you agree to maintain a respectful and inclusive environment for everyone. 8 | 9 | ## How to Contribute 10 | 11 | ### Reporting Bugs 12 | 13 | 1. Check if the bug has already been reported in the Issues section 14 | 2. If not, create a new issue with a clear and descriptive title 15 | 3. Include as much relevant information as possible: 16 | - Steps to reproduce the bug 17 | - Expected behavior 18 | - Actual behavior 19 | - Screenshots if applicable 20 | - Browser version and OS information 21 | 22 | ### Suggesting Features 23 | 24 | 1. Check if the feature has already been suggested in the Issues section 25 | 2. If not, create a new issue with a clear and descriptive title 26 | 3. Provide a detailed description of the feature 27 | 4. Explain why this feature would be useful 28 | 5. Include any relevant examples or mockups 29 | 30 | ### Pull Requests 31 | 32 | 1. Fork the repository 33 | 2. Create a new branch for your feature/fix: 34 | ```bash 35 | git checkout -b feature/amazing-feature 36 | ``` 37 | 3. Make your changes 38 | 4. Commit your changes with clear, descriptive commit messages: 39 | ```bash 40 | git commit -m 'Add some amazing feature' 41 | ``` 42 | 5. Push to your fork: 43 | ```bash 44 | git push origin feature/amazing-feature 45 | ``` 46 | 6. Open a Pull Request 47 | 48 | ### Development Setup 49 | 50 | 1. Clone the repository 51 | 2. Install dependencies (if any) 52 | 3. Make your changes 53 | 4. Test your changes thoroughly 54 | 5. Ensure your code follows the project's style guidelines 55 | 56 | ### Code Style 57 | 58 | - Follow the existing code style in the project 59 | - Use meaningful variable and function names 60 | - Add comments for complex logic 61 | - Keep functions small and focused 62 | - Write clear commit messages 63 | 64 | ### Testing 65 | 66 | - Test your changes across different browsers 67 | - Ensure the extension works on all supported platforms 68 | - Test edge cases and error scenarios 69 | - Update tests if you're modifying existing functionality 70 | 71 | ## Review Process 72 | 73 | 1. All pull requests will be reviewed by maintainers 74 | 2. We may request changes or improvements 75 | 3. Once approved, your changes will be merged into the main branch 76 | 77 | ## Questions? 78 | 79 | If you have any questions about contributing, feel free to open an issue or contact the maintainers. 80 | 81 | Thank you for contributing to Chat Navigator! -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chat Navigator 2 | 3 | ## Overview 4 | Chat Navigator is a browser extension designed to enhance the user experience of LLM chat applications by providing an interactive navigation sidebar. The extension automatically indexes conversation messages and enables quick navigation through long chat histories. 5 | 6 | ## Features 7 | - Real-time message indexing and navigation 8 | - Movable sidebar interface 9 | - Theme customization with multiple color schemes 10 | - Automatic detection of new messages 11 | - Direct message linking and navigation 12 | - Cross-platform compatibility with major LLM chat applications 13 | 14 | ## Technical Implementation 15 | - Built as a Chrome extension using Manifest V3 16 | - Utilizes MutationObserver for real-time message detection 17 | - Implements drag-and-drop functionality for sidebar positioning 18 | - Features a modular theme system with CSS variables 19 | - Persists user preferences using Chrome Storage API 20 | 21 | ## Supported Platforms 22 | - ChatGPT (chat.openai.com) 23 | - Perplexity AI (perplexity.ai) 24 | 25 | ## Installation 26 | 1. Clone the repository 27 | 2. Open Chrome and navigate to `chrome://extensions/` 28 | 3. Enable Developer mode 29 | 4. Click "Load unpacked" and select the extension directory 30 | 5. The extension will automatically activate on supported chat applications 31 | 32 | ## Usage 33 | 1. Visit any supported LLM chat application 34 | 2. The navigation sidebar will appear on the right side of the screen 35 | 3. Click any indexed message to navigate directly to that point in the conversation 36 | 4. Drag the sidebar to reposition it anywhere on the screen 37 | 5. Use the extension popup to customize the theme 38 | 39 | ## Development 40 | The extension consists of several key components: 41 | - `content.js`: Main extension logic and DOM manipulation 42 | - `popup.html/js`: Theme selection interface 43 | - `style.css`: Theme definitions and UI styling 44 | - `manifest.json`: Extension configuration and permissions 45 | 46 | ## Future Enhancements 47 | - Message search functionality 48 | - Custom message annotations 49 | - Support for additional chat platforms 50 | 51 | ## License 52 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 53 | 54 | ## Contributing 55 | Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change. 56 | 57 | 1. Fork the repository 58 | 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 59 | 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 60 | 4. Push to the branch (`git push origin feature/amazing-feature`) 61 | 5. Open a Pull Request 62 | 63 | Please make sure to update tests as appropriate and follow the existing code style. 64 | -------------------------------------------------------------------------------- /extension/style.css: -------------------------------------------------------------------------------- 1 | /* Base styles and CSS variables for theming */ 2 | :root { 3 | /* Default theme variables */ 4 | --primary-color: #52ff5e; 5 | --secondary-color: #ffcdd2; 6 | --text-color: #ffffff; 7 | --hover-color: rgba(255, 255, 255, 0.1); 8 | --shadow-color: rgba(0, 0, 0, 0.1); 9 | --primary-color-rgb: 82, 255, 94; 10 | } 11 | 12 | /* Theme classes with v0.dev-inspired adjustments */ 13 | .theme-red { 14 | --primary-color: #ff1744; /* Brighter, more vibrant red */ 15 | --secondary-color: #ff5252; 16 | --text-color: #ffffff; 17 | --primary-color-rgb: 255, 23, 68; 18 | } 19 | 20 | .theme-blue { 21 | --primary-color: #2979ff; /* Vibrant techno blue */ 22 | --secondary-color: #448aff; 23 | --text-color: #ffffff; 24 | --primary-color-rgb: 41, 121, 255; 25 | } 26 | 27 | .theme-pink { 28 | --primary-color: #f50057; /* Bold, neon-like pink */ 29 | --secondary-color: #ec407a; 30 | --text-color: #ffffff; 31 | --primary-color-rgb: 245, 0, 87; 32 | } 33 | 34 | .theme-white { 35 | --primary-color: #fafafa; /* Clean off-white */ 36 | --secondary-color: #eeeeee; 37 | --text-color: #212121; /* Dark text for contrast */ 38 | --primary-color-rgb: 250, 250, 250; 39 | } 40 | 41 | .theme-gray { 42 | --primary-color: #757575; /* Modern muted gray */ 43 | --secondary-color: #bdbdbd; 44 | --text-color: #ffffff; 45 | --primary-color-rgb: 117, 117, 117; 46 | } 47 | 48 | .theme-dark { 49 | --primary-color: #000000; /* Pure black for v0.dev dark vibe */ 50 | --secondary-color: #212121; 51 | --text-color: #e0e0e0; 52 | --primary-color-rgb: 0, 0, 0; 53 | } 54 | 55 | /* Navigator Bar Styles */ 56 | .navigator-bar { 57 | position: fixed; 58 | right: 10px; 59 | top: 20%; 60 | width: 8px; 61 | max-height: 60vh; 62 | background-color: var(--primary-color); 63 | border-radius: 4px; 64 | z-index: 9999; 65 | display: flex; 66 | flex-direction: column; 67 | gap: 4px; 68 | padding: 4px; 69 | box-shadow: 0 2px 10px var(--shadow-color); 70 | transition: all 0.3s ease-in-out; 71 | overflow: hidden; 72 | } 73 | 74 | /* Expanded state for navigator bar */ 75 | .navigator-bar.expanded { 76 | width: 220px; 77 | background-color: var(--primary-color); 78 | border-radius: 6px; 79 | padding: 8px 4px; 80 | } 81 | 82 | /* Header for the navigator bar */ 83 | .nav-header { 84 | display: none; 85 | padding: 4px 8px; 86 | margin-bottom: 8px; 87 | border-bottom: 1px solid var(--secondary-color); 88 | } 89 | 90 | .navigator-bar.expanded .nav-header { 91 | display: block; 92 | } 93 | 94 | .nav-title { 95 | color: var(--text-color); 96 | font-size: 14px; 97 | font-weight: bold; 98 | white-space: nowrap; 99 | } 100 | 101 | /* Nav items */ 102 | .nav-item { 103 | height: 8px; 104 | width: 100%; 105 | background-color: var(--secondary-color); 106 | border-radius: 2px; 107 | cursor: pointer; 108 | transition: all 0.2s ease; 109 | position: relative; 110 | margin: 2px 0; 111 | } 112 | 113 | .navigator-bar.expanded .nav-item { 114 | height: auto; 115 | background-color: transparent; 116 | display: flex; 117 | align-items: center; 118 | border-radius: 4px; 119 | padding: 6px 4px; 120 | } 121 | 122 | .navigator-bar.expanded .nav-item:hover, 123 | .navigator-bar.expanded .nav-item.active { 124 | background-color: var(--secondary-color); 125 | } 126 | 127 | .nav-item-content { 128 | display: flex; 129 | align-items: center; 130 | width: 100%; 131 | } 132 | 133 | .nav-item:hover { 134 | transform: scaleX(1.2); 135 | background-color: var(--text-color); 136 | } 137 | 138 | .navigator-bar.expanded .nav-item:hover { 139 | transform: none; 140 | background-color: var(--secondary-color); 141 | } 142 | 143 | /* Nav item text only shows on expanded */ 144 | .nav-item-text { 145 | display: none; 146 | color: var(--text-color); 147 | font-size: 12px; 148 | white-space: nowrap; 149 | overflow: hidden; 150 | text-overflow: ellipsis; 151 | margin-left: 4px; 152 | } 153 | 154 | .navigator-bar.expanded .nav-item-text { 155 | display: block; 156 | max-width: 200px; 157 | } 158 | 159 | /* Active state for nav items */ 160 | .nav-item.active { 161 | background-color: var(--text-color); 162 | } 163 | 164 | .navigator-bar.expanded .nav-item.active { 165 | background-color: var(--secondary-color); 166 | font-weight: bold; 167 | } 168 | 169 | .navigator-bar.expanded .nav-item.active .nav-item-text { 170 | font-weight: bold; 171 | } 172 | 173 | /* Expanded Sidebar Styles */ 174 | #chat.sidebar { 175 | width: max-content; 176 | min-width: 200px; 177 | min-height: max-content; 178 | max-height: 60vh; 179 | background-color: var(--primary-color); 180 | color: var(--text-color); 181 | position: fixed; 182 | z-index: 9999; 183 | box-shadow: 0 4px 12px var(--shadow-color); 184 | border-radius: 8px; 185 | overflow: auto; 186 | display: table; 187 | resize: both; /* Enables resizing in both directions */ 188 | border-collapse: separate; /* Changed from collapse to separate */ 189 | border-spacing: 0; 190 | font-size: 14px; 191 | transition: opacity 0.3s ease; 192 | } 193 | 194 | /* Table-specific styling with v0.dev touch */ 195 | #chat.sidebar table { 196 | width: 100%; 197 | border-collapse: collapse; 198 | background: rgba(255, 255, 255, 0.1); 199 | } 200 | 201 | #chat.sidebar tr:nth-child(even) td { 202 | background-color: rgba(255, 255, 255, 0.05); /* Zebra striping for readability */ 203 | } 204 | 205 | #chat.sidebar td { 206 | padding: 0.5em; 207 | border-bottom: 1px solid var(--secondary-color); 208 | } 209 | 210 | #chat.sidebar td a { 211 | color: var(--text-color); 212 | text-decoration: none; 213 | display: block; 214 | padding: 4px; 215 | border-radius: 4px; 216 | transition: background-color 0.2s ease; 217 | } 218 | 219 | #chat.sidebar td a:hover { 220 | background-color: var(--secondary-color); 221 | } 222 | 223 | /* Message tooltip */ 224 | .message-tooltip { 225 | position: fixed; 226 | max-width: 300px; 227 | padding: 10px; 228 | background-color: var(--primary-color); 229 | color: var(--text-color); 230 | border-radius: 6px; 231 | z-index: 10000; 232 | display: none; 233 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); 234 | font-size: 14px; 235 | max-height: 200px; 236 | overflow-y: auto; 237 | } 238 | 239 | /* Message highlight effect - improved */ 240 | .highlight-message { 241 | animation: highlight-pulse 2s ease-in-out; 242 | position: relative; 243 | outline: 2px solid var(--primary-color); 244 | box-shadow: 0 0 10px var(--primary-color); 245 | } 246 | 247 | @keyframes highlight-pulse { 248 | 0%, 100% { 249 | background-color: transparent; 250 | outline-color: transparent; 251 | } 252 | 50% { 253 | background-color: rgba(var(--primary-color-rgb, 255, 23, 68), 0.2); 254 | outline-color: var(--primary-color); 255 | } 256 | } 257 | 258 | .macos-controls { 259 | display: flex; 260 | gap: 0.5rem; 261 | padding: 0.5rem; 262 | } 263 | .macos-controls button { 264 | width: 0.75rem; 265 | height: 0.75rem; 266 | border-radius: 50%; 267 | display: inline-block; 268 | } 269 | .close { 270 | background: #ff5f56; 271 | } 272 | .minimize { 273 | background: #ffbd2e; 274 | } 275 | .maximize { 276 | background: #27c93f; 277 | } 278 | 279 | .minimized { 280 | height: 40px !important; /* Only header visible */ 281 | min-height: 0 !important; 282 | max-height: 40px !important; 283 | overflow: hidden; 284 | } 285 | 286 | .sidebar-header { 287 | max-height: 90px; 288 | padding: 8px; 289 | cursor: move; 290 | background-color: var(--secondary-color); 291 | border-radius: 8px 8px 0 0; 292 | user-select: none; /* Prevent text selection while dragging */ 293 | } 294 | 295 | #chat.sidebar.minimized tr:not(:first-child) { 296 | display: none; 297 | } 298 | -------------------------------------------------------------------------------- /extension/content.js: -------------------------------------------------------------------------------- 1 | //! TODO : 2 | //! 1. Fix the initial random animation [done] 3 | //! 2. Make it support all websites 4 | 5 | //? claudes-chat-element : *
/ 6 | 7 | console.log("[Content] content.js loaded"); 8 | 9 | // Global variable for chat sidebar and navigator bar 10 | let chat_sidebar; 11 | let navigator_bar; 12 | let currentChatConfig = null; 13 | let lastUrl = window.location.href; 14 | var index = 1; 15 | let messageIndexMap = new Map(); // Store message references by index 16 | 17 | // Define selectors for different chat applications directly in content.js 18 | const chatSelectors = { 19 | 'chatgpt.com': { 20 | type: 'openai', 21 | selectors: { 22 | chatContainer: 'article', // Parent of messages 23 | messageSelector: '.whitespace-pre-wrap' // Individual message elements 24 | } 25 | }, 26 | 'claude.ai': { 27 | type: 'claude', 28 | selectors: { 29 | chatContainer: 'font-user-message grid grid-cols-1 gap-2 py-0.5 text-[0.9375rem] leading-6', // More specific parent for Claude messages 30 | messageSelector: '.whitespace-pre-wrap break-words', // Messages from Claude 31 | } 32 | }, 33 | 'perplexity.ai': { 34 | type: 'perplexity', 35 | selectors: { 36 | chatContainer: 'main', 37 | messageSelector: 'div.prose' // General prose content for Perplexity 38 | } 39 | }, 40 | 'gemini.google.com': { 41 | type: 'gemini', 42 | selectors: { 43 | chatContainer: 'message-list', // Custom element or specific class for Gemini 44 | messageSelector: 'message-content' // Selector for actual message text 45 | } 46 | }, 47 | 'grok.com': { 48 | type: 'grok', 49 | selectors: { 50 | // These are guesses and might need refinement for Grok 51 | chatContainer: 'div[data-testid="conversation"] > div > div[style*="flex-direction: column;"]', 52 | messageSelector: 'div[data-testid^="message-"]' 53 | } 54 | }, 55 | 't3.chat': { 56 | type: 't3chat', 57 | selectors: { 58 | // These are guesses for T3 Chat 59 | chatContainer: '.chat-messages-container', 60 | messageSelector: '.message-bubble' 61 | } 62 | } 63 | }; 64 | 65 | // Function to determine which chat application is being used based on URL 66 | function determineChatAppConfig(url) { 67 | console.log('[Content] Determining chat app for URL:', url); 68 | if (!url) { 69 | console.warn('[Content] No URL provided to determineChatAppConfig'); 70 | return null; 71 | } 72 | for (const [domain, config] of Object.entries(chatSelectors)) { 73 | if (url.includes(domain)) { 74 | console.log('[Content] Found matching chat app:', config.type); 75 | return config; 76 | } 77 | } 78 | console.log('[Content] No matching chat app found for URL:', url); 79 | return null; 80 | } 81 | 82 | // Function to apply theme 83 | function applyTheme(theme) { 84 | if (navigator_bar) { 85 | navigator_bar.className = `navigator-bar theme-${theme}`; 86 | console.log("[Content] Theme applied to navigator bar:", theme); 87 | } 88 | 89 | if (chat_sidebar) { 90 | chat_sidebar.className = `sidebar theme-${theme}`; 91 | console.log("[Content] Theme applied to sidebar:", theme); 92 | } 93 | } 94 | 95 | async function waitforelement(selector) { 96 | console.log("[Content] Waiting for element with selector:", selector); 97 | try { 98 | return new Promise((resolve) => { 99 | const checkElements = () => { 100 | let ele = document.querySelector(selector); 101 | if (ele) { 102 | ele = ele.parentNode; 103 | console.log("[Content] Element found:", selector); 104 | resolve(ele); 105 | } else { 106 | console.log("[Content] {else} Element not found:", selector); 107 | setTimeout(checkElements, 500); 108 | } 109 | }; 110 | checkElements(); 111 | }); 112 | } catch (e) { 113 | console.error("[Content] Error executing waitforelements:", e); 114 | } 115 | } 116 | 117 | // Function to initialize chat navigation system 118 | async function initializeChatNavigation() { 119 | console.log("[Content] Initializing chat navigation for URL:", window.location.href); 120 | currentChatConfig = determineChatAppConfig(window.location.href); 121 | 122 | if (currentChatConfig) { 123 | console.log("[Content] Determined chat config:", currentChatConfig); 124 | await setupNavigator(); 125 | } else { 126 | console.warn("[Content] No chat configuration found for this URL. Navigation not initialized."); 127 | // Optionally, remove any existing elements 128 | if (navigator_bar) { 129 | navigator_bar.remove(); 130 | navigator_bar = null; 131 | } 132 | if (chat_sidebar) { 133 | chat_sidebar.remove(); 134 | chat_sidebar = null; 135 | } 136 | console.log("[Content] Removed existing navigation elements as no config for current URL."); 137 | } 138 | } 139 | 140 | // Function to setup the navigator bar and sidebar 141 | async function setupNavigator() { 142 | console.log("[Content] Setting up chat navigator with config:", currentChatConfig); 143 | if (!currentChatConfig || !currentChatConfig.selectors || !currentChatConfig.selectors.chatContainer) { 144 | console.warn("[Content] Invalid or incomplete chat config, skipping setup. Config:", currentChatConfig); 145 | return; 146 | } 147 | 148 | try { 149 | // Remove any existing elements 150 | if (document.querySelector("#chat-navigator-bar")) { 151 | document.querySelector("#chat-navigator-bar").remove(); 152 | } 153 | if (document.querySelector("#chat.sidebar")) { 154 | document.querySelector("#chat.sidebar").remove(); 155 | } 156 | 157 | console.log("[Content] {try} currentChatConfig.selectors.chatContainer:", currentChatConfig.selectors.chatContainer); 158 | const targetElementParent = await waitforelement(currentChatConfig.selectors.chatContainer); 159 | console.log("[Content] Found target element:", targetElementParent); 160 | 161 | // Clear index map 162 | messageIndexMap.clear(); 163 | index = 1; 164 | 165 | // Create navigator bar (collapsed state) 166 | navigator_bar = document.createElement("div"); 167 | navigator_bar.id = "chat-navigator-bar"; 168 | navigator_bar.className = 'navigator-bar'; 169 | 170 | // Add header to navigator bar 171 | const navHeader = document.createElement("div"); 172 | navHeader.className = "nav-header"; 173 | navHeader.innerHTML = `Chat Messages`; 174 | navigator_bar.appendChild(navHeader); 175 | 176 | // Create sidebar (expanded state - initially hidden) 177 | chat_sidebar = document.createElement("table"); 178 | chat_sidebar.id = "chat"; 179 | chat_sidebar.className = 'sidebar'; 180 | chat_sidebar.style.display = 'none'; // Hidden initially 181 | chat_sidebar.style.position = 'absolute'; 182 | 183 | // Create header row for dragging 184 | const headerRow = document.createElement("tr"); 185 | const headerCell = document.createElement("td"); 186 | headerCell.className = "sidebar-header"; 187 | 188 | // Add macOS controls inside header 189 | headerCell.innerHTML = ` 190 |
191 | 192 | 193 | 194 |
195 | `; 196 | 197 | headerCell.colSpan = 1; 198 | headerRow.appendChild(headerCell); 199 | chat_sidebar.appendChild(headerRow); 200 | 201 | // Make the sidebar draggable by its header 202 | dragElement(chat_sidebar); 203 | 204 | document.body.appendChild(navigator_bar); 205 | document.body.appendChild(chat_sidebar); 206 | 207 | // Hook up sidebar controls 208 | const closeBtn = chat_sidebar.querySelector(".close"); 209 | const minimizeBtn = chat_sidebar.querySelector(".minimize"); 210 | const maximizeBtn = chat_sidebar.querySelector(".maximize"); 211 | 212 | closeBtn.addEventListener("click", () => { 213 | chat_sidebar.style.display = "none"; 214 | console.log("[Content] Chat sidebar closed"); 215 | }); 216 | minimizeBtn.addEventListener("click", () => { 217 | chat_sidebar.classList.add("minimized"); 218 | console.log("[Content] Chat sidebar minimized"); 219 | }); 220 | maximizeBtn.addEventListener("click", () => { 221 | chat_sidebar.classList.remove("minimized"); 222 | console.log("[Content] Chat sidebar maximized"); 223 | }); 224 | 225 | // Setup jQuery resizable for sidebar 226 | $(function() { 227 | $("#chat").resizable({ 228 | handles: "n, e, s, w, ne, se, sw, nw", 229 | start: function() { 230 | resizeObserver.observe(chat_sidebar); 231 | }, 232 | stop: function() { 233 | resizeObserver.disconnect(); 234 | } 235 | }); 236 | }); 237 | 238 | // Create but don't connect the observer initially 239 | const resizeObserver = new ResizeObserver(() => { 240 | if (!chat_sidebar) return; 241 | const width = chat_sidebar.offsetWidth; 242 | const height = chat_sidebar.offsetHeight; 243 | const fontSize = Math.min(width, height) / 10; 244 | chat_sidebar.style.fontSize = `${fontSize}px`; 245 | }); 246 | 247 | // Apply theme 248 | chrome.storage.sync.get('theme', function(data) { 249 | const theme = data.theme || 'red'; 250 | applyTheme(theme); 251 | }); 252 | 253 | // Setup the hover behavior for navigator bar - show expanded text labels 254 | navigator_bar.addEventListener('mouseenter', () => { 255 | navigator_bar.classList.add('expanded'); 256 | 257 | // If user hovers the bar but doesn't have sidebar open yet, still position it 258 | const rect = navigator_bar.getBoundingClientRect(); 259 | chat_sidebar.style.top = `${rect.top}px`; 260 | chat_sidebar.style.left = `${rect.right + 10}px`; // Position to the right of the bar 261 | chat_sidebar.style.display = "table"; 262 | }); 263 | 264 | navigator_bar.addEventListener('mouseleave', (e) => { 265 | if (e.relatedTarget !== chat_sidebar && !chat_sidebar.contains(e.relatedTarget)) { 266 | navigator_bar.classList.remove('expanded'); 267 | setTimeout(() => { 268 | if (!chat_sidebar.matches(':hover')) { 269 | chat_sidebar.style.display = "none"; 270 | } 271 | }, 100); 272 | } 273 | }); 274 | 275 | // Allow sidebar to close when mouse leaves it 276 | chat_sidebar.addEventListener('mouseleave', (e) => { 277 | if (e.relatedTarget !== navigator_bar) { 278 | setTimeout(() => { 279 | if (!navigator_bar.matches(':hover')) { 280 | chat_sidebar.style.display = "none"; 281 | navigator_bar.classList.remove('expanded'); 282 | } 283 | }, 100); 284 | } 285 | }); 286 | 287 | // Handle existing chats 288 | const existingMessages = targetElementParent.querySelectorAll(currentChatConfig.selectors.messageSelector); 289 | console.log(`[Content] Processing ${existingMessages.length} existing chat messages using selector: ${currentChatConfig.selectors.messageSelector}`); 290 | 291 | existingMessages.forEach((messageNode) => { 292 | try { 293 | messageNode.id = `index-${index}`; 294 | messageIndexMap.set(index, messageNode); 295 | const shortText = messageNode.textContent.substring(0, 12).trim() + "..."; 296 | addMessageToSidebar(index, shortText, messageNode.id); 297 | addMessageToBar(index); 298 | index++; 299 | } catch (e) { 300 | console.error("[Content] Error processing existing message:", e, "Message content:", messageNode.innerHTML); 301 | } 302 | }); 303 | 304 | // Observe new chats within the chatContainer (targetElementParent) 305 | const observerConfig = { childList: true, subtree: true }; 306 | const obs = new MutationObserver(mutationCallback); 307 | try { 308 | obs.observe(targetElementParent, observerConfig); 309 | console.log("[Content] MutationObserver initialized for target element:", targetElementParent); 310 | } catch (e) { 311 | console.error("[Content] Observer initialization failed, error:", e); 312 | } 313 | } catch (error) { 314 | console.error("[Content] Error in setupNavigator:", error); 315 | } 316 | } 317 | 318 | // Function to add a message indicator to the navigator bar 319 | function addMessageToBar(messageIndex) { 320 | if (!navigator_bar) return; 321 | 322 | const barItem = document.createElement("div"); 323 | barItem.className = "nav-item"; 324 | barItem.dataset.index = messageIndex; 325 | 326 | // Create wrapper for better hover effects 327 | const barItemContent = document.createElement("div"); 328 | barItemContent.className = "nav-item-content"; 329 | 330 | // Get the message text for this item 331 | let messageText = "Message " + messageIndex; 332 | if (messageIndexMap.has(messageIndex)) { 333 | const messageNode = messageIndexMap.get(messageIndex); 334 | messageText = messageNode.textContent.substring(0, 30).trim(); 335 | if (messageNode.textContent.length > 30) { 336 | messageText += "..."; 337 | } 338 | } 339 | 340 | // Add the anchor text that will show on hover 341 | const anchorText = document.createElement("span"); 342 | anchorText.className = "nav-item-text"; 343 | anchorText.textContent = messageText; 344 | barItemContent.appendChild(anchorText); 345 | 346 | barItem.appendChild(barItemContent); 347 | 348 | // Add click event to scroll to the message 349 | barItem.addEventListener("click", () => { 350 | // Ensure sidebar is visible 351 | navigator_bar.classList.add('expanded'); 352 | chat_sidebar.style.display = "table"; 353 | 354 | const messageId = `index-${messageIndex}`; 355 | const messageElement = document.getElementById(messageId); 356 | if (messageElement) { 357 | messageElement.scrollIntoView({ behavior: "smooth", block: "center" }); 358 | 359 | // Add a brief highlight effect 360 | messageElement.classList.add("highlight-message"); 361 | setTimeout(() => { 362 | messageElement.classList.remove("highlight-message"); 363 | }, 2000); 364 | 365 | // Mark this nav item as active 366 | document.querySelectorAll('.nav-item').forEach(item => { 367 | item.classList.remove('active'); 368 | }); 369 | barItem.classList.add('active'); 370 | } 371 | }); 372 | 373 | navigator_bar.appendChild(barItem); 374 | } 375 | 376 | // Function to add a message to the sidebar table 377 | function addMessageToSidebar(messageIndex, rowData, id) { 378 | if (!chat_sidebar) return; 379 | 380 | const newRow = chat_sidebar.insertRow(); 381 | const cell = newRow.insertCell(); 382 | cell.innerHTML = `${messageIndex}. ${rowData}`; 383 | 384 | // Add hover behavior to show full text 385 | cell.addEventListener("mouseenter", () => { 386 | if (messageIndexMap.has(messageIndex)) { 387 | const fullMessage = messageIndexMap.get(messageIndex); 388 | const fullText = fullMessage.textContent.trim(); 389 | 390 | // Create or update tooltip 391 | let tooltip = document.getElementById("message-tooltip"); 392 | if (!tooltip) { 393 | tooltip = document.createElement("div"); 394 | tooltip.id = "message-tooltip"; 395 | tooltip.className = "message-tooltip"; 396 | document.body.appendChild(tooltip); 397 | } 398 | 399 | tooltip.textContent = fullText; 400 | 401 | // Position the tooltip 402 | const rect = cell.getBoundingClientRect(); 403 | tooltip.style.top = `${rect.top}px`; 404 | tooltip.style.left = `${rect.right + 10}px`; 405 | tooltip.style.display = "block"; 406 | } 407 | }); 408 | 409 | cell.addEventListener("mouseleave", () => { 410 | const tooltip = document.getElementById("message-tooltip"); 411 | if (tooltip) { 412 | tooltip.style.display = "none"; 413 | } 414 | }); 415 | 416 | console.log("[Content] Added new sidebar row:", rowData); 417 | } 418 | 419 | // Function to handle URL changes 420 | function checkUrlChange() { 421 | const currentUrl = window.location.href; 422 | if (currentUrl !== lastUrl) { 423 | console.log('[Content] URL changed from', lastUrl, 'to', currentUrl); 424 | lastUrl = currentUrl; 425 | // Re-initialize the navigation for the new URL 426 | initializeChatNavigation(); 427 | } 428 | } 429 | 430 | // Start checking for URL changes 431 | setInterval(checkUrlChange, 1000); 432 | 433 | // Listen for theme changes from storage 434 | chrome.storage.onChanged.addListener(function(changes, namespace) { 435 | if (changes.theme) { 436 | console.log("[Content] Theme change detected:", changes.theme.newValue); 437 | applyTheme(changes.theme.newValue); 438 | } 439 | }); 440 | 441 | // Callback for MutationObserver 442 | function mutationCallback(mutationList, observer) { 443 | if (!currentChatConfig || !currentChatConfig.selectors || !currentChatConfig.selectors.messageSelector) { 444 | return; 445 | } 446 | 447 | for (const mutation of mutationList) { 448 | if (mutation.type === 'childList') { 449 | mutation.addedNodes.forEach(node => { 450 | // Check if the added node itself is a message or contains messages 451 | if (node.nodeType === Node.ELEMENT_NODE) { 452 | const messages = []; 453 | if (node.matches(currentChatConfig.selectors.messageSelector)) { 454 | messages.push(node); 455 | } 456 | // Also check children if the added node is a container 457 | messages.push(...node.querySelectorAll(currentChatConfig.selectors.messageSelector)); 458 | 459 | messages.forEach(messageNode => { 460 | if (!messageNode.id) { // Process only if not already processed 461 | try { 462 | messageNode.id = `index-${index}`; 463 | messageIndexMap.set(index, messageNode); 464 | const shortText = messageNode.textContent.substring(0, 12).trim() + "..."; 465 | addMessageToSidebar(index, shortText, messageNode.id); 466 | addMessageToBar(index); 467 | index++; 468 | console.log("[Content] Added new chat message via MutationObserver:", messageNode.id); 469 | } catch (e) { 470 | console.error("[Content] Error processing new message via MutationObserver:", e, "Message content:", messageNode.innerHTML); 471 | } 472 | } 473 | }); 474 | } 475 | }); 476 | } 477 | } 478 | } 479 | 480 | function dragElement(elmnt) { 481 | var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; 482 | const header = elmnt.querySelector('.sidebar-header'); 483 | 484 | if (header) { 485 | header.onmousedown = dragMouseDown; 486 | } else { 487 | elmnt.onmousedown = dragMouseDown; 488 | } 489 | 490 | function dragMouseDown(e) { 491 | e = e || window.event; 492 | e.preventDefault(); 493 | // get the mouse cursor position at startup: 494 | pos3 = e.clientX; 495 | pos4 = e.clientY; 496 | document.onmouseup = closeDragElement; 497 | // call a function whenever the cursor moves: 498 | document.onmousemove = elementDrag; 499 | } 500 | 501 | function elementDrag(e) { 502 | e = e || window.event; 503 | e.preventDefault(); 504 | // calculate the new cursor position: 505 | pos1 = pos3 - e.clientX; 506 | pos2 = pos4 - e.clientY; 507 | pos3 = e.clientX; 508 | pos4 = e.clientY; 509 | elmnt.style.top = (elmnt.offsetTop - pos2) + "px"; 510 | elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; 511 | } 512 | 513 | function closeDragElement() { 514 | document.onmouseup = null; 515 | document.onmousemove = null; 516 | } 517 | } 518 | 519 | // Initial load: determine config and setup navigation 520 | (async () => { 521 | await initializeChatNavigation(); 522 | })(); 523 | 524 | 525 | -------------------------------------------------------------------------------- /extension/jquery-ui.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.14.1 - 2024-10-30 2 | * https://jqueryui.com 3 | * Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css 4 | * To view and modify this theme, visit https://jqueryui.com/themeroller/?ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&fwDefault=normal&cornerRadius=3px&bgColorHeader=e9e9e9&bgTextureHeader=flat&borderColorHeader=dddddd&fcHeader=333333&iconColorHeader=444444&bgColorContent=ffffff&bgTextureContent=flat&borderColorContent=dddddd&fcContent=333333&iconColorContent=444444&bgColorDefault=f6f6f6&bgTextureDefault=flat&borderColorDefault=c5c5c5&fcDefault=454545&iconColorDefault=777777&bgColorHover=ededed&bgTextureHover=flat&borderColorHover=cccccc&fcHover=2b2b2b&iconColorHover=555555&bgColorActive=007fff&bgTextureActive=flat&borderColorActive=003eff&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=fffa90&bgTextureHighlight=flat&borderColorHighlight=dad55e&fcHighlight=777620&iconColorHighlight=777620&bgColorError=fddfdf&bgTextureError=flat&borderColorError=f1a899&fcError=5f3f3f&iconColorError=cc0000&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=666666&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=5px&offsetTopShadow=0px&offsetLeftShadow=0px&cornerRadiusShadow=8px 5 | * Copyright OpenJS Foundation and other contributors; Licensed MIT */ 6 | 7 | /* Layout helpers 8 | ----------------------------------*/ 9 | .ui-helper-hidden { 10 | display: none; 11 | } 12 | .ui-helper-hidden-accessible { 13 | border: 0; 14 | clip: rect(0 0 0 0); 15 | height: 1px; 16 | margin: -1px; 17 | overflow: hidden; 18 | padding: 0; 19 | position: absolute; 20 | width: 1px; 21 | } 22 | .ui-helper-reset { 23 | margin: 0; 24 | padding: 0; 25 | border: 0; 26 | outline: 0; 27 | line-height: 1.3; 28 | text-decoration: none; 29 | font-size: 100%; 30 | list-style: none; 31 | } 32 | .ui-helper-clearfix:before, 33 | .ui-helper-clearfix:after { 34 | content: ""; 35 | display: table; 36 | border-collapse: collapse; 37 | } 38 | .ui-helper-clearfix:after { 39 | clear: both; 40 | } 41 | .ui-helper-zfix { 42 | width: 100%; 43 | height: 100%; 44 | top: 0; 45 | left: 0; 46 | position: absolute; 47 | opacity: 0; 48 | } 49 | 50 | .ui-front { 51 | z-index: 100; 52 | } 53 | 54 | 55 | /* Interaction Cues 56 | ----------------------------------*/ 57 | .ui-state-disabled { 58 | cursor: default !important; 59 | pointer-events: none; 60 | } 61 | 62 | 63 | /* Icons 64 | ----------------------------------*/ 65 | .ui-icon { 66 | display: inline-block; 67 | vertical-align: middle; 68 | margin-top: -.25em; 69 | position: relative; 70 | text-indent: -99999px; 71 | overflow: hidden; 72 | background-repeat: no-repeat; 73 | } 74 | 75 | .ui-widget-icon-block { 76 | left: 50%; 77 | margin-left: -8px; 78 | display: block; 79 | } 80 | 81 | /* Misc visuals 82 | ----------------------------------*/ 83 | 84 | /* Overlays */ 85 | .ui-widget-overlay { 86 | position: fixed; 87 | top: 0; 88 | left: 0; 89 | width: 100%; 90 | height: 100%; 91 | } 92 | .ui-accordion .ui-accordion-header { 93 | display: block; 94 | cursor: pointer; 95 | position: relative; 96 | margin: 2px 0 0 0; 97 | padding: .5em .5em .5em .7em; 98 | font-size: 100%; 99 | } 100 | .ui-accordion .ui-accordion-content { 101 | padding: 1em 2.2em; 102 | border-top: 0; 103 | overflow: auto; 104 | } 105 | .ui-autocomplete { 106 | position: absolute; 107 | top: 0; 108 | left: 0; 109 | cursor: default; 110 | } 111 | .ui-menu { 112 | list-style: none; 113 | padding: 0; 114 | margin: 0; 115 | display: block; 116 | outline: 0; 117 | } 118 | .ui-menu .ui-menu { 119 | position: absolute; 120 | } 121 | .ui-menu .ui-menu-item { 122 | margin: 0; 123 | cursor: pointer; 124 | } 125 | .ui-menu .ui-menu-item-wrapper { 126 | position: relative; 127 | padding: 3px 1em 3px .4em; 128 | } 129 | .ui-menu .ui-menu-divider { 130 | margin: 5px 0; 131 | height: 0; 132 | font-size: 0; 133 | line-height: 0; 134 | border-width: 1px 0 0 0; 135 | } 136 | .ui-menu .ui-state-focus, 137 | .ui-menu .ui-state-active { 138 | margin: -1px; 139 | } 140 | 141 | /* icon support */ 142 | .ui-menu-icons { 143 | position: relative; 144 | } 145 | .ui-menu-icons .ui-menu-item-wrapper { 146 | padding-left: 2em; 147 | } 148 | 149 | /* left-aligned */ 150 | .ui-menu .ui-icon { 151 | position: absolute; 152 | top: 0; 153 | bottom: 0; 154 | left: .2em; 155 | margin: auto 0; 156 | } 157 | 158 | /* right-aligned */ 159 | .ui-menu .ui-menu-icon { 160 | left: auto; 161 | right: 0; 162 | } 163 | .ui-button { 164 | padding: .4em 1em; 165 | display: inline-block; 166 | position: relative; 167 | line-height: normal; 168 | margin-right: .1em; 169 | cursor: pointer; 170 | vertical-align: middle; 171 | text-align: center; 172 | -webkit-user-select: none; 173 | user-select: none; 174 | } 175 | 176 | .ui-button, 177 | .ui-button:link, 178 | .ui-button:visited, 179 | .ui-button:hover, 180 | .ui-button:active { 181 | text-decoration: none; 182 | } 183 | 184 | /* to make room for the icon, a width needs to be set here */ 185 | .ui-button-icon-only { 186 | width: 2em; 187 | box-sizing: border-box; 188 | text-indent: -9999px; 189 | white-space: nowrap; 190 | } 191 | 192 | /* no icon support for input elements */ 193 | input.ui-button.ui-button-icon-only { 194 | text-indent: 0; 195 | } 196 | 197 | /* button icon element(s) */ 198 | .ui-button-icon-only .ui-icon { 199 | position: absolute; 200 | top: 50%; 201 | left: 50%; 202 | margin-top: -8px; 203 | margin-left: -8px; 204 | } 205 | 206 | .ui-button.ui-icon-notext .ui-icon { 207 | padding: 0; 208 | width: 2.1em; 209 | height: 2.1em; 210 | text-indent: -9999px; 211 | white-space: nowrap; 212 | 213 | } 214 | 215 | input.ui-button.ui-icon-notext .ui-icon { 216 | width: auto; 217 | height: auto; 218 | text-indent: 0; 219 | white-space: normal; 220 | padding: .4em 1em; 221 | } 222 | 223 | /* workarounds */ 224 | /* Support: Firefox 5 - 125+ */ 225 | input.ui-button::-moz-focus-inner, 226 | button.ui-button::-moz-focus-inner { 227 | border: 0; 228 | padding: 0; 229 | } 230 | .ui-controlgroup { 231 | vertical-align: middle; 232 | display: inline-block; 233 | } 234 | .ui-controlgroup > .ui-controlgroup-item { 235 | float: left; 236 | margin-left: 0; 237 | margin-right: 0; 238 | } 239 | .ui-controlgroup > .ui-controlgroup-item:focus, 240 | .ui-controlgroup > .ui-controlgroup-item.ui-visual-focus { 241 | z-index: 9999; 242 | } 243 | .ui-controlgroup-vertical > .ui-controlgroup-item { 244 | display: block; 245 | float: none; 246 | width: 100%; 247 | margin-top: 0; 248 | margin-bottom: 0; 249 | text-align: left; 250 | } 251 | .ui-controlgroup-vertical .ui-controlgroup-item { 252 | box-sizing: border-box; 253 | } 254 | .ui-controlgroup .ui-controlgroup-label { 255 | padding: .4em 1em; 256 | } 257 | .ui-controlgroup .ui-controlgroup-label span { 258 | font-size: 80%; 259 | } 260 | .ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item { 261 | border-left: none; 262 | } 263 | .ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item { 264 | border-top: none; 265 | } 266 | .ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content { 267 | border-right: none; 268 | } 269 | .ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content { 270 | border-bottom: none; 271 | } 272 | 273 | /* Spinner specific style fixes */ 274 | .ui-controlgroup-vertical .ui-spinner-input { 275 | width: calc( 100% - 2.4em ); 276 | } 277 | .ui-controlgroup-vertical .ui-spinner .ui-spinner-up { 278 | border-top-style: solid; 279 | } 280 | 281 | .ui-checkboxradio-label .ui-icon-background { 282 | box-shadow: inset 1px 1px 1px #ccc; 283 | border-radius: .12em; 284 | border: none; 285 | } 286 | .ui-checkboxradio-radio-label .ui-icon-background { 287 | width: 16px; 288 | height: 16px; 289 | border-radius: 1em; 290 | overflow: visible; 291 | border: none; 292 | } 293 | .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, 294 | .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { 295 | background-image: none; 296 | width: 8px; 297 | height: 8px; 298 | border-width: 4px; 299 | border-style: solid; 300 | } 301 | .ui-checkboxradio-disabled { 302 | pointer-events: none; 303 | } 304 | .ui-datepicker { 305 | width: 17em; 306 | padding: .2em .2em 0; 307 | display: none; 308 | } 309 | .ui-datepicker .ui-datepicker-header { 310 | position: relative; 311 | padding: .2em 0; 312 | } 313 | .ui-datepicker .ui-datepicker-prev, 314 | .ui-datepicker .ui-datepicker-next { 315 | position: absolute; 316 | top: 2px; 317 | width: 1.8em; 318 | height: 1.8em; 319 | } 320 | .ui-datepicker .ui-datepicker-prev-hover, 321 | .ui-datepicker .ui-datepicker-next-hover { 322 | top: 1px; 323 | } 324 | .ui-datepicker .ui-datepicker-prev { 325 | left: 2px; 326 | } 327 | .ui-datepicker .ui-datepicker-next { 328 | right: 2px; 329 | } 330 | .ui-datepicker .ui-datepicker-prev-hover { 331 | left: 1px; 332 | } 333 | .ui-datepicker .ui-datepicker-next-hover { 334 | right: 1px; 335 | } 336 | .ui-datepicker .ui-datepicker-prev span, 337 | .ui-datepicker .ui-datepicker-next span { 338 | display: block; 339 | position: absolute; 340 | left: 50%; 341 | margin-left: -8px; 342 | top: 50%; 343 | margin-top: -8px; 344 | } 345 | .ui-datepicker .ui-datepicker-title { 346 | margin: 0 2.3em; 347 | line-height: 1.8em; 348 | text-align: center; 349 | } 350 | .ui-datepicker .ui-datepicker-title select { 351 | font-size: 1em; 352 | margin: 1px 0; 353 | } 354 | .ui-datepicker select.ui-datepicker-month, 355 | .ui-datepicker select.ui-datepicker-year { 356 | width: 45%; 357 | } 358 | .ui-datepicker table { 359 | width: 100%; 360 | font-size: .9em; 361 | border-collapse: collapse; 362 | margin: 0 0 .4em; 363 | } 364 | .ui-datepicker th { 365 | padding: .7em .3em; 366 | text-align: center; 367 | font-weight: bold; 368 | border: 0; 369 | } 370 | .ui-datepicker td { 371 | border: 0; 372 | padding: 1px; 373 | } 374 | .ui-datepicker td span, 375 | .ui-datepicker td a { 376 | display: block; 377 | padding: .2em; 378 | text-align: right; 379 | text-decoration: none; 380 | } 381 | .ui-datepicker .ui-datepicker-buttonpane { 382 | background-image: none; 383 | margin: .7em 0 0 0; 384 | padding: 0 .2em; 385 | border-left: 0; 386 | border-right: 0; 387 | border-bottom: 0; 388 | } 389 | .ui-datepicker .ui-datepicker-buttonpane button { 390 | float: right; 391 | margin: .5em .2em .4em; 392 | cursor: pointer; 393 | padding: .2em .6em .3em .6em; 394 | width: auto; 395 | overflow: visible; 396 | } 397 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { 398 | float: left; 399 | } 400 | 401 | /* with multiple calendars */ 402 | .ui-datepicker.ui-datepicker-multi { 403 | width: auto; 404 | } 405 | .ui-datepicker-multi .ui-datepicker-group { 406 | float: left; 407 | } 408 | .ui-datepicker-multi .ui-datepicker-group table { 409 | width: 95%; 410 | margin: 0 auto .4em; 411 | } 412 | .ui-datepicker-multi-2 .ui-datepicker-group { 413 | width: 50%; 414 | } 415 | .ui-datepicker-multi-3 .ui-datepicker-group { 416 | width: 33.3%; 417 | } 418 | .ui-datepicker-multi-4 .ui-datepicker-group { 419 | width: 25%; 420 | } 421 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, 422 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { 423 | border-left-width: 0; 424 | } 425 | .ui-datepicker-multi .ui-datepicker-buttonpane { 426 | clear: left; 427 | } 428 | .ui-datepicker-row-break { 429 | clear: both; 430 | width: 100%; 431 | font-size: 0; 432 | } 433 | 434 | /* RTL support */ 435 | .ui-datepicker-rtl { 436 | direction: rtl; 437 | } 438 | .ui-datepicker-rtl .ui-datepicker-prev { 439 | right: 2px; 440 | left: auto; 441 | } 442 | .ui-datepicker-rtl .ui-datepicker-next { 443 | left: 2px; 444 | right: auto; 445 | } 446 | .ui-datepicker-rtl .ui-datepicker-prev:hover { 447 | right: 1px; 448 | left: auto; 449 | } 450 | .ui-datepicker-rtl .ui-datepicker-next:hover { 451 | left: 1px; 452 | right: auto; 453 | } 454 | .ui-datepicker-rtl .ui-datepicker-buttonpane { 455 | clear: right; 456 | } 457 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { 458 | float: left; 459 | } 460 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, 461 | .ui-datepicker-rtl .ui-datepicker-group { 462 | float: right; 463 | } 464 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, 465 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { 466 | border-right-width: 0; 467 | border-left-width: 1px; 468 | } 469 | 470 | /* Icons */ 471 | .ui-datepicker .ui-icon { 472 | display: block; 473 | text-indent: -99999px; 474 | overflow: hidden; 475 | background-repeat: no-repeat; 476 | left: .5em; 477 | top: .3em; 478 | } 479 | .ui-dialog { 480 | position: absolute; 481 | top: 0; 482 | left: 0; 483 | padding: .2em; 484 | outline: 0; 485 | } 486 | .ui-dialog .ui-dialog-titlebar { 487 | padding: .4em 1em; 488 | position: relative; 489 | } 490 | .ui-dialog .ui-dialog-title { 491 | float: left; 492 | margin: .1em 0; 493 | white-space: nowrap; 494 | width: 90%; 495 | overflow: hidden; 496 | text-overflow: ellipsis; 497 | } 498 | .ui-dialog .ui-dialog-titlebar-close { 499 | position: absolute; 500 | right: .3em; 501 | top: 50%; 502 | width: 20px; 503 | margin: -10px 0 0 0; 504 | padding: 1px; 505 | height: 20px; 506 | } 507 | .ui-dialog .ui-dialog-content { 508 | position: relative; 509 | border: 0; 510 | padding: .5em 1em; 511 | background: none; 512 | overflow: auto; 513 | } 514 | .ui-dialog .ui-dialog-buttonpane { 515 | text-align: left; 516 | border-width: 1px 0 0 0; 517 | background-image: none; 518 | margin-top: .5em; 519 | padding: .3em 1em .5em .4em; 520 | } 521 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { 522 | float: right; 523 | } 524 | .ui-dialog .ui-dialog-buttonpane button { 525 | margin: .5em .4em .5em 0; 526 | cursor: pointer; 527 | } 528 | .ui-dialog .ui-resizable-n { 529 | height: 2px; 530 | top: 0; 531 | } 532 | .ui-dialog .ui-resizable-e { 533 | width: 2px; 534 | right: 0; 535 | } 536 | .ui-dialog .ui-resizable-s { 537 | height: 2px; 538 | bottom: 0; 539 | } 540 | .ui-dialog .ui-resizable-w { 541 | width: 2px; 542 | left: 0; 543 | } 544 | .ui-dialog .ui-resizable-se, 545 | .ui-dialog .ui-resizable-sw, 546 | .ui-dialog .ui-resizable-ne, 547 | .ui-dialog .ui-resizable-nw { 548 | width: 7px; 549 | height: 7px; 550 | } 551 | .ui-dialog .ui-resizable-se { 552 | right: 0; 553 | bottom: 0; 554 | } 555 | .ui-dialog .ui-resizable-sw { 556 | left: 0; 557 | bottom: 0; 558 | } 559 | .ui-dialog .ui-resizable-ne { 560 | right: 0; 561 | top: 0; 562 | } 563 | .ui-dialog .ui-resizable-nw { 564 | left: 0; 565 | top: 0; 566 | } 567 | .ui-draggable .ui-dialog-titlebar { 568 | cursor: move; 569 | } 570 | .ui-draggable-handle { 571 | touch-action: none; 572 | } 573 | .ui-resizable { 574 | position: relative; 575 | } 576 | .ui-resizable-handle { 577 | position: absolute; 578 | font-size: 0.1px; 579 | display: block; 580 | touch-action: none; 581 | } 582 | .ui-resizable-disabled .ui-resizable-handle, 583 | .ui-resizable-autohide .ui-resizable-handle { 584 | display: none; 585 | } 586 | .ui-resizable-n { 587 | cursor: n-resize; 588 | height: 7px; 589 | width: 100%; 590 | top: -5px; 591 | left: 0; 592 | } 593 | .ui-resizable-s { 594 | cursor: s-resize; 595 | height: 7px; 596 | width: 100%; 597 | bottom: -5px; 598 | left: 0; 599 | } 600 | .ui-resizable-e { 601 | cursor: e-resize; 602 | width: 7px; 603 | right: -5px; 604 | top: 0; 605 | height: 100%; 606 | } 607 | .ui-resizable-w { 608 | cursor: w-resize; 609 | width: 7px; 610 | left: -5px; 611 | top: 0; 612 | height: 100%; 613 | } 614 | .ui-resizable-se { 615 | cursor: se-resize; 616 | width: 12px; 617 | height: 12px; 618 | right: 1px; 619 | bottom: 1px; 620 | } 621 | .ui-resizable-sw { 622 | cursor: sw-resize; 623 | width: 9px; 624 | height: 9px; 625 | left: -5px; 626 | bottom: -5px; 627 | } 628 | .ui-resizable-nw { 629 | cursor: nw-resize; 630 | width: 9px; 631 | height: 9px; 632 | left: -5px; 633 | top: -5px; 634 | } 635 | .ui-resizable-ne { 636 | cursor: ne-resize; 637 | width: 9px; 638 | height: 9px; 639 | right: -5px; 640 | top: -5px; 641 | } 642 | .ui-progressbar { 643 | height: 2em; 644 | text-align: left; 645 | overflow: hidden; 646 | } 647 | .ui-progressbar .ui-progressbar-value { 648 | margin: -1px; 649 | height: 100%; 650 | } 651 | .ui-progressbar .ui-progressbar-overlay { 652 | background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw=="); 653 | height: 100%; 654 | opacity: 0.25; 655 | } 656 | .ui-progressbar-indeterminate .ui-progressbar-value { 657 | background-image: none; 658 | } 659 | .ui-selectable { 660 | touch-action: none; 661 | } 662 | .ui-selectable-helper { 663 | position: absolute; 664 | z-index: 100; 665 | border: 1px dotted black; 666 | } 667 | .ui-selectmenu-menu { 668 | padding: 0; 669 | margin: 0; 670 | position: absolute; 671 | top: 0; 672 | left: 0; 673 | display: none; 674 | } 675 | .ui-selectmenu-menu .ui-menu { 676 | overflow: auto; 677 | overflow-x: hidden; 678 | padding-bottom: 1px; 679 | } 680 | .ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup { 681 | font-size: 1em; 682 | font-weight: bold; 683 | line-height: 1.5; 684 | padding: 2px 0.4em; 685 | margin: 0.5em 0 0 0; 686 | height: auto; 687 | border: 0; 688 | } 689 | .ui-selectmenu-open { 690 | display: block; 691 | } 692 | .ui-selectmenu-text { 693 | display: block; 694 | margin-right: 20px; 695 | overflow: hidden; 696 | text-overflow: ellipsis; 697 | } 698 | .ui-selectmenu-button.ui-button { 699 | text-align: left; 700 | white-space: nowrap; 701 | width: 14em; 702 | } 703 | .ui-selectmenu-icon.ui-icon { 704 | float: right; 705 | margin-top: 0; 706 | } 707 | .ui-slider { 708 | position: relative; 709 | text-align: left; 710 | } 711 | .ui-slider .ui-slider-handle { 712 | position: absolute; 713 | z-index: 2; 714 | width: 1.2em; 715 | height: 1.2em; 716 | cursor: pointer; 717 | touch-action: none; 718 | } 719 | .ui-slider .ui-slider-range { 720 | position: absolute; 721 | z-index: 1; 722 | font-size: .7em; 723 | display: block; 724 | border: 0; 725 | background-position: 0 0; 726 | } 727 | 728 | .ui-slider-horizontal { 729 | height: .8em; 730 | } 731 | .ui-slider-horizontal .ui-slider-handle { 732 | top: -.3em; 733 | margin-left: -.6em; 734 | } 735 | .ui-slider-horizontal .ui-slider-range { 736 | top: 0; 737 | height: 100%; 738 | } 739 | .ui-slider-horizontal .ui-slider-range-min { 740 | left: 0; 741 | } 742 | .ui-slider-horizontal .ui-slider-range-max { 743 | right: 0; 744 | } 745 | 746 | .ui-slider-vertical { 747 | width: .8em; 748 | height: 100px; 749 | } 750 | .ui-slider-vertical .ui-slider-handle { 751 | left: -.3em; 752 | margin-left: 0; 753 | margin-bottom: -.6em; 754 | } 755 | .ui-slider-vertical .ui-slider-range { 756 | left: 0; 757 | width: 100%; 758 | } 759 | .ui-slider-vertical .ui-slider-range-min { 760 | bottom: 0; 761 | } 762 | .ui-slider-vertical .ui-slider-range-max { 763 | top: 0; 764 | } 765 | .ui-sortable-handle { 766 | touch-action: none; 767 | } 768 | .ui-spinner { 769 | position: relative; 770 | display: inline-block; 771 | overflow: hidden; 772 | padding: 0; 773 | vertical-align: middle; 774 | } 775 | .ui-spinner-input { 776 | border: none; 777 | background: none; 778 | color: inherit; 779 | padding: .222em 0; 780 | margin: .2em 0; 781 | vertical-align: middle; 782 | margin-left: .4em; 783 | margin-right: 2em; 784 | } 785 | .ui-spinner-button { 786 | width: 1.6em; 787 | height: 50%; 788 | font-size: .5em; 789 | padding: 0; 790 | margin: 0; 791 | text-align: center; 792 | position: absolute; 793 | cursor: default; 794 | display: block; 795 | overflow: hidden; 796 | right: 0; 797 | } 798 | /* more specificity required here to override default borders */ 799 | .ui-spinner a.ui-spinner-button { 800 | border-top-style: none; 801 | border-bottom-style: none; 802 | border-right-style: none; 803 | } 804 | .ui-spinner-up { 805 | top: 0; 806 | } 807 | .ui-spinner-down { 808 | bottom: 0; 809 | } 810 | .ui-tabs { 811 | position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ 812 | padding: .2em; 813 | } 814 | .ui-tabs .ui-tabs-nav { 815 | margin: 0; 816 | padding: .2em .2em 0; 817 | } 818 | .ui-tabs .ui-tabs-nav li { 819 | list-style: none; 820 | float: left; 821 | position: relative; 822 | top: 0; 823 | margin: 1px .2em 0 0; 824 | border-bottom-width: 0; 825 | padding: 0; 826 | white-space: nowrap; 827 | } 828 | .ui-tabs .ui-tabs-nav .ui-tabs-anchor { 829 | float: left; 830 | padding: .5em 1em; 831 | text-decoration: none; 832 | } 833 | .ui-tabs .ui-tabs-nav li.ui-tabs-active { 834 | margin-bottom: -1px; 835 | padding-bottom: 1px; 836 | } 837 | .ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, 838 | .ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, 839 | .ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor { 840 | cursor: text; 841 | } 842 | .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor { 843 | cursor: pointer; 844 | } 845 | .ui-tabs .ui-tabs-panel { 846 | display: block; 847 | border-width: 0; 848 | padding: 1em 1.4em; 849 | background: none; 850 | } 851 | .ui-tooltip { 852 | padding: 8px; 853 | position: absolute; 854 | z-index: 9999; 855 | max-width: 300px; 856 | } 857 | body .ui-tooltip { 858 | border-width: 2px; 859 | } 860 | /* Component containers 861 | ----------------------------------*/ 862 | .ui-widget { 863 | font-family: Arial,Helvetica,sans-serif; 864 | font-size: 1em; 865 | } 866 | .ui-widget .ui-widget { 867 | font-size: 1em; 868 | } 869 | .ui-widget input, 870 | .ui-widget select, 871 | .ui-widget textarea, 872 | .ui-widget button { 873 | font-family: Arial,Helvetica,sans-serif; 874 | font-size: 1em; 875 | } 876 | .ui-widget.ui-widget-content { 877 | border: 1px solid #c5c5c5; 878 | } 879 | .ui-widget-content { 880 | border: 1px solid #dddddd; 881 | background: #ffffff; 882 | color: #333333; 883 | } 884 | .ui-widget-content a { 885 | color: #333333; 886 | } 887 | .ui-widget-header { 888 | border: 1px solid #dddddd; 889 | background: #e9e9e9; 890 | color: #333333; 891 | font-weight: bold; 892 | } 893 | .ui-widget-header a { 894 | color: #333333; 895 | } 896 | 897 | /* Interaction states 898 | ----------------------------------*/ 899 | .ui-state-default, 900 | .ui-widget-content .ui-state-default, 901 | .ui-widget-header .ui-state-default, 902 | .ui-button, 903 | 904 | /* We use html here because we need a greater specificity to make sure disabled 905 | works properly when clicked or hovered */ 906 | html .ui-button.ui-state-disabled:hover, 907 | html .ui-button.ui-state-disabled:active { 908 | border: 1px solid #c5c5c5; 909 | background: #f6f6f6; 910 | font-weight: normal; 911 | color: #454545; 912 | } 913 | .ui-state-default a, 914 | .ui-state-default a:link, 915 | .ui-state-default a:visited, 916 | a.ui-button, 917 | a:link.ui-button, 918 | a:visited.ui-button, 919 | .ui-button { 920 | color: #454545; 921 | text-decoration: none; 922 | } 923 | .ui-state-hover, 924 | .ui-widget-content .ui-state-hover, 925 | .ui-widget-header .ui-state-hover, 926 | .ui-state-focus, 927 | .ui-widget-content .ui-state-focus, 928 | .ui-widget-header .ui-state-focus, 929 | .ui-button:hover, 930 | .ui-button:focus { 931 | border: 1px solid #cccccc; 932 | background: #ededed; 933 | font-weight: normal; 934 | color: #2b2b2b; 935 | } 936 | .ui-state-hover a, 937 | .ui-state-hover a:hover, 938 | .ui-state-hover a:link, 939 | .ui-state-hover a:visited, 940 | .ui-state-focus a, 941 | .ui-state-focus a:hover, 942 | .ui-state-focus a:link, 943 | .ui-state-focus a:visited, 944 | a.ui-button:hover, 945 | a.ui-button:focus { 946 | color: #2b2b2b; 947 | text-decoration: none; 948 | } 949 | 950 | .ui-visual-focus { 951 | box-shadow: 0 0 3px 1px rgb(94, 158, 214); 952 | } 953 | .ui-state-active, 954 | .ui-widget-content .ui-state-active, 955 | .ui-widget-header .ui-state-active, 956 | a.ui-button:active, 957 | .ui-button:active, 958 | .ui-button.ui-state-active:hover { 959 | border: 1px solid #003eff; 960 | background: #007fff; 961 | font-weight: normal; 962 | color: #ffffff; 963 | } 964 | .ui-icon-background, 965 | .ui-state-active .ui-icon-background { 966 | border: #003eff; 967 | background-color: #ffffff; 968 | } 969 | .ui-state-active a, 970 | .ui-state-active a:link, 971 | .ui-state-active a:visited { 972 | color: #ffffff; 973 | text-decoration: none; 974 | } 975 | 976 | /* Interaction Cues 977 | ----------------------------------*/ 978 | .ui-state-highlight, 979 | .ui-widget-content .ui-state-highlight, 980 | .ui-widget-header .ui-state-highlight { 981 | border: 1px solid #dad55e; 982 | background: #fffa90; 983 | color: #777620; 984 | } 985 | .ui-state-checked { 986 | border: 1px solid #dad55e; 987 | background: #fffa90; 988 | } 989 | .ui-state-highlight a, 990 | .ui-widget-content .ui-state-highlight a, 991 | .ui-widget-header .ui-state-highlight a { 992 | color: #777620; 993 | } 994 | .ui-state-error, 995 | .ui-widget-content .ui-state-error, 996 | .ui-widget-header .ui-state-error { 997 | border: 1px solid #f1a899; 998 | background: #fddfdf; 999 | color: #5f3f3f; 1000 | } 1001 | .ui-state-error a, 1002 | .ui-widget-content .ui-state-error a, 1003 | .ui-widget-header .ui-state-error a { 1004 | color: #5f3f3f; 1005 | } 1006 | .ui-state-error-text, 1007 | .ui-widget-content .ui-state-error-text, 1008 | .ui-widget-header .ui-state-error-text { 1009 | color: #5f3f3f; 1010 | } 1011 | .ui-priority-primary, 1012 | .ui-widget-content .ui-priority-primary, 1013 | .ui-widget-header .ui-priority-primary { 1014 | font-weight: bold; 1015 | } 1016 | .ui-priority-secondary, 1017 | .ui-widget-content .ui-priority-secondary, 1018 | .ui-widget-header .ui-priority-secondary { 1019 | opacity: .7; 1020 | font-weight: normal; 1021 | } 1022 | .ui-state-disabled, 1023 | .ui-widget-content .ui-state-disabled, 1024 | .ui-widget-header .ui-state-disabled { 1025 | opacity: .35; 1026 | background-image: none; 1027 | } 1028 | 1029 | /* Icons 1030 | ----------------------------------*/ 1031 | 1032 | /* states and images */ 1033 | .ui-icon { 1034 | width: 16px; 1035 | height: 16px; 1036 | } 1037 | .ui-icon, 1038 | .ui-widget-content .ui-icon { 1039 | background-image: url("images/ui-icons_444444_256x240.png"); 1040 | } 1041 | .ui-widget-header .ui-icon { 1042 | background-image: url("images/ui-icons_444444_256x240.png"); 1043 | } 1044 | .ui-state-hover .ui-icon, 1045 | .ui-state-focus .ui-icon, 1046 | .ui-button:hover .ui-icon, 1047 | .ui-button:focus .ui-icon { 1048 | background-image: url("images/ui-icons_555555_256x240.png"); 1049 | } 1050 | .ui-state-active .ui-icon, 1051 | .ui-button:active .ui-icon { 1052 | background-image: url("images/ui-icons_ffffff_256x240.png"); 1053 | } 1054 | .ui-state-highlight .ui-icon, 1055 | .ui-button .ui-state-highlight.ui-icon { 1056 | background-image: url("images/ui-icons_777620_256x240.png"); 1057 | } 1058 | .ui-state-error .ui-icon, 1059 | .ui-state-error-text .ui-icon { 1060 | background-image: url("images/ui-icons_cc0000_256x240.png"); 1061 | } 1062 | .ui-button .ui-icon { 1063 | background-image: url("images/ui-icons_777777_256x240.png"); 1064 | } 1065 | 1066 | /* positioning */ 1067 | /* Three classes needed to override `.ui-button:hover .ui-icon` */ 1068 | .ui-icon-blank.ui-icon-blank.ui-icon-blank { 1069 | background-image: none; 1070 | } 1071 | .ui-icon-caret-1-n { background-position: 0 0; } 1072 | .ui-icon-caret-1-ne { background-position: -16px 0; } 1073 | .ui-icon-caret-1-e { background-position: -32px 0; } 1074 | .ui-icon-caret-1-se { background-position: -48px 0; } 1075 | .ui-icon-caret-1-s { background-position: -65px 0; } 1076 | .ui-icon-caret-1-sw { background-position: -80px 0; } 1077 | .ui-icon-caret-1-w { background-position: -96px 0; } 1078 | .ui-icon-caret-1-nw { background-position: -112px 0; } 1079 | .ui-icon-caret-2-n-s { background-position: -128px 0; } 1080 | .ui-icon-caret-2-e-w { background-position: -144px 0; } 1081 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 1082 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 1083 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 1084 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 1085 | .ui-icon-triangle-1-s { background-position: -65px -16px; } 1086 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 1087 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 1088 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 1089 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 1090 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 1091 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 1092 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 1093 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 1094 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 1095 | .ui-icon-arrow-1-s { background-position: -65px -32px; } 1096 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 1097 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 1098 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 1099 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 1100 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 1101 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 1102 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 1103 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 1104 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 1105 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 1106 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 1107 | .ui-icon-arrowthick-1-n { background-position: 1px -48px; } 1108 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 1109 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 1110 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 1111 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 1112 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 1113 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 1114 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 1115 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 1116 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 1117 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 1118 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 1119 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 1120 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 1121 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 1122 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 1123 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 1124 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 1125 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 1126 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 1127 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 1128 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 1129 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 1130 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 1131 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 1132 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 1133 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 1134 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 1135 | .ui-icon-arrow-4 { background-position: 0 -80px; } 1136 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 1137 | .ui-icon-extlink { background-position: -32px -80px; } 1138 | .ui-icon-newwin { background-position: -48px -80px; } 1139 | .ui-icon-refresh { background-position: -64px -80px; } 1140 | .ui-icon-shuffle { background-position: -80px -80px; } 1141 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 1142 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 1143 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 1144 | .ui-icon-folder-open { background-position: -16px -96px; } 1145 | .ui-icon-document { background-position: -32px -96px; } 1146 | .ui-icon-document-b { background-position: -48px -96px; } 1147 | .ui-icon-note { background-position: -64px -96px; } 1148 | .ui-icon-mail-closed { background-position: -80px -96px; } 1149 | .ui-icon-mail-open { background-position: -96px -96px; } 1150 | .ui-icon-suitcase { background-position: -112px -96px; } 1151 | .ui-icon-comment { background-position: -128px -96px; } 1152 | .ui-icon-person { background-position: -144px -96px; } 1153 | .ui-icon-print { background-position: -160px -96px; } 1154 | .ui-icon-trash { background-position: -176px -96px; } 1155 | .ui-icon-locked { background-position: -192px -96px; } 1156 | .ui-icon-unlocked { background-position: -208px -96px; } 1157 | .ui-icon-bookmark { background-position: -224px -96px; } 1158 | .ui-icon-tag { background-position: -240px -96px; } 1159 | .ui-icon-home { background-position: 0 -112px; } 1160 | .ui-icon-flag { background-position: -16px -112px; } 1161 | .ui-icon-calendar { background-position: -32px -112px; } 1162 | .ui-icon-cart { background-position: -48px -112px; } 1163 | .ui-icon-pencil { background-position: -64px -112px; } 1164 | .ui-icon-clock { background-position: -80px -112px; } 1165 | .ui-icon-disk { background-position: -96px -112px; } 1166 | .ui-icon-calculator { background-position: -112px -112px; } 1167 | .ui-icon-zoomin { background-position: -128px -112px; } 1168 | .ui-icon-zoomout { background-position: -144px -112px; } 1169 | .ui-icon-search { background-position: -160px -112px; } 1170 | .ui-icon-wrench { background-position: -176px -112px; } 1171 | .ui-icon-gear { background-position: -192px -112px; } 1172 | .ui-icon-heart { background-position: -208px -112px; } 1173 | .ui-icon-star { background-position: -224px -112px; } 1174 | .ui-icon-link { background-position: -240px -112px; } 1175 | .ui-icon-cancel { background-position: 0 -128px; } 1176 | .ui-icon-plus { background-position: -16px -128px; } 1177 | .ui-icon-plusthick { background-position: -32px -128px; } 1178 | .ui-icon-minus { background-position: -48px -128px; } 1179 | .ui-icon-minusthick { background-position: -64px -128px; } 1180 | .ui-icon-close { background-position: -80px -128px; } 1181 | .ui-icon-closethick { background-position: -96px -128px; } 1182 | .ui-icon-key { background-position: -112px -128px; } 1183 | .ui-icon-lightbulb { background-position: -128px -128px; } 1184 | .ui-icon-scissors { background-position: -144px -128px; } 1185 | .ui-icon-clipboard { background-position: -160px -128px; } 1186 | .ui-icon-copy { background-position: -176px -128px; } 1187 | .ui-icon-contact { background-position: -192px -128px; } 1188 | .ui-icon-image { background-position: -208px -128px; } 1189 | .ui-icon-video { background-position: -224px -128px; } 1190 | .ui-icon-script { background-position: -240px -128px; } 1191 | .ui-icon-alert { background-position: 0 -144px; } 1192 | .ui-icon-info { background-position: -16px -144px; } 1193 | .ui-icon-notice { background-position: -32px -144px; } 1194 | .ui-icon-help { background-position: -48px -144px; } 1195 | .ui-icon-check { background-position: -64px -144px; } 1196 | .ui-icon-bullet { background-position: -80px -144px; } 1197 | .ui-icon-radio-on { background-position: -96px -144px; } 1198 | .ui-icon-radio-off { background-position: -112px -144px; } 1199 | .ui-icon-pin-w { background-position: -128px -144px; } 1200 | .ui-icon-pin-s { background-position: -144px -144px; } 1201 | .ui-icon-play { background-position: 0 -160px; } 1202 | .ui-icon-pause { background-position: -16px -160px; } 1203 | .ui-icon-seek-next { background-position: -32px -160px; } 1204 | .ui-icon-seek-prev { background-position: -48px -160px; } 1205 | .ui-icon-seek-end { background-position: -64px -160px; } 1206 | .ui-icon-seek-start { background-position: -80px -160px; } 1207 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 1208 | .ui-icon-seek-first { background-position: -80px -160px; } 1209 | .ui-icon-stop { background-position: -96px -160px; } 1210 | .ui-icon-eject { background-position: -112px -160px; } 1211 | .ui-icon-volume-off { background-position: -128px -160px; } 1212 | .ui-icon-volume-on { background-position: -144px -160px; } 1213 | .ui-icon-power { background-position: 0 -176px; } 1214 | .ui-icon-signal-diag { background-position: -16px -176px; } 1215 | .ui-icon-signal { background-position: -32px -176px; } 1216 | .ui-icon-battery-0 { background-position: -48px -176px; } 1217 | .ui-icon-battery-1 { background-position: -64px -176px; } 1218 | .ui-icon-battery-2 { background-position: -80px -176px; } 1219 | .ui-icon-battery-3 { background-position: -96px -176px; } 1220 | .ui-icon-circle-plus { background-position: 0 -192px; } 1221 | .ui-icon-circle-minus { background-position: -16px -192px; } 1222 | .ui-icon-circle-close { background-position: -32px -192px; } 1223 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 1224 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 1225 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 1226 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 1227 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 1228 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 1229 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 1230 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 1231 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 1232 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 1233 | .ui-icon-circle-check { background-position: -208px -192px; } 1234 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 1235 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 1236 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 1237 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 1238 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 1239 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 1240 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 1241 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 1242 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 1243 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 1244 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 1245 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 1246 | 1247 | 1248 | /* Misc visuals 1249 | ----------------------------------*/ 1250 | 1251 | /* Corner radius */ 1252 | .ui-corner-all, 1253 | .ui-corner-top, 1254 | .ui-corner-left, 1255 | .ui-corner-tl { 1256 | border-top-left-radius: 3px; 1257 | } 1258 | .ui-corner-all, 1259 | .ui-corner-top, 1260 | .ui-corner-right, 1261 | .ui-corner-tr { 1262 | border-top-right-radius: 3px; 1263 | } 1264 | .ui-corner-all, 1265 | .ui-corner-bottom, 1266 | .ui-corner-left, 1267 | .ui-corner-bl { 1268 | border-bottom-left-radius: 3px; 1269 | } 1270 | .ui-corner-all, 1271 | .ui-corner-bottom, 1272 | .ui-corner-right, 1273 | .ui-corner-br { 1274 | border-bottom-right-radius: 3px; 1275 | } 1276 | 1277 | /* Overlays */ 1278 | .ui-widget-overlay { 1279 | background: #aaaaaa; 1280 | opacity: .3; 1281 | } 1282 | .ui-widget-shadow { 1283 | box-shadow: 0px 0px 5px #666666; 1284 | } -------------------------------------------------------------------------------- /extension/jquery-3.7.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ 2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0