├── .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