| 1 | <?php |
|---|
| 2 | /** |
|---|
| 3 | * Plugin Name: Code Click-to-Copy by WPJohnny |
|---|
| 4 | * Plugin URI: https://wpjohnny.com/code-click-to-copy/ |
|---|
| 5 | * Description: Click anywhere on pre and code tags to automatically copy to clipboard. No aiming required - just click anywhere on the code block. |
|---|
| 6 | * Version: 1.0.1 |
|---|
| 7 | * Requires at least: 5.0 |
|---|
| 8 | * Tested up to: 6.4 |
|---|
| 9 | * Requires PHP: 7.0 |
|---|
| 10 | * Author: <a href="https://wpjohnny.com">WPJohnny</a> |
|---|
| 11 | * Author URI: https://wpjohnny.com |
|---|
| 12 | * License: GPLv2 or later |
|---|
| 13 | * License URI: https://www.gnu.org/licenses/gpl-2.0.html |
|---|
| 14 | * Text Domain: code-click-to-copy |
|---|
| 15 | * Donate link: https://www.paypal.me/wpjohnny |
|---|
| 16 | * Network: false |
|---|
| 17 | */ |
|---|
| 18 | |
|---|
| 19 | /** |
|---|
| 20 | * Load plugin textdomain. |
|---|
| 21 | */ |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | add_action( 'init', 'codeClickToCopyLoadTextdomain' ); |
|---|
| 26 | function codeClickToCopyLoadTextdomain() { |
|---|
| 27 | load_plugin_textdomain( 'code-click-to-copy', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); |
|---|
| 28 | } |
|---|
| 29 | |
|---|
| 30 | // Add admin menu |
|---|
| 31 | add_action('admin_menu', 'code_click_to_copy_admin_menu'); |
|---|
| 32 | function code_click_to_copy_admin_menu() { |
|---|
| 33 | add_submenu_page( |
|---|
| 34 | 'options-general.php', // Parent slug (Settings) |
|---|
| 35 | __('Code Click to Copy Settings', 'code-click-to-copy'), |
|---|
| 36 | 'Code Click to Copy', |
|---|
| 37 | 'manage_options', |
|---|
| 38 | 'code-click-to-copy', |
|---|
| 39 | 'code_click_to_copy_settings_page' |
|---|
| 40 | ); |
|---|
| 41 | } |
|---|
| 42 | |
|---|
| 43 | // Register settings |
|---|
| 44 | add_action('admin_init', 'code_click_to_copy_settings_init'); |
|---|
| 45 | add_action('admin_enqueue_scripts', 'enqueue_admin_scripts'); |
|---|
| 46 | |
|---|
| 47 | function code_click_to_copy_settings_init() { |
|---|
| 48 | register_setting('code_click_to_copy', 'code_click_to_copy_settings'); |
|---|
| 49 | |
|---|
| 50 | add_settings_section( |
|---|
| 51 | 'code_click_to_copy_section', |
|---|
| 52 | __('Tooltip Customizations', 'code-click-to-copy'), |
|---|
| 53 | 'code_click_to_copy_section_callback', |
|---|
| 54 | 'code-click-to-copy' |
|---|
| 55 | ); |
|---|
| 56 | |
|---|
| 57 | // 1. Tooltip Background Color |
|---|
| 58 | add_settings_field( |
|---|
| 59 | 'tooltip_background', |
|---|
| 60 | __('Tooltip Background Color', 'code-click-to-copy'), |
|---|
| 61 | 'tooltip_background_callback', |
|---|
| 62 | 'code-click-to-copy', |
|---|
| 63 | 'code_click_to_copy_section' |
|---|
| 64 | ); |
|---|
| 65 | |
|---|
| 66 | // 2. Tooltip Text Color |
|---|
| 67 | add_settings_field( |
|---|
| 68 | 'tooltip_text_color', |
|---|
| 69 | __('Tooltip Text Color', 'code-click-to-copy'), |
|---|
| 70 | 'tooltip_text_color_callback', |
|---|
| 71 | 'code-click-to-copy', |
|---|
| 72 | 'code_click_to_copy_section' |
|---|
| 73 | ); |
|---|
| 74 | |
|---|
| 75 | // 3. Tooltip Copy Text |
|---|
| 76 | add_settings_field( |
|---|
| 77 | 'click_to_copy_text', |
|---|
| 78 | __('Tooltip Copy Text', 'code-click-to-copy'), |
|---|
| 79 | 'click_to_copy_text_callback', |
|---|
| 80 | 'code-click-to-copy', |
|---|
| 81 | 'code_click_to_copy_section' |
|---|
| 82 | ); |
|---|
| 83 | |
|---|
| 84 | // 4. Tooltip Copied Text |
|---|
| 85 | add_settings_field( |
|---|
| 86 | 'copied_text', |
|---|
| 87 | __('Tooltip Copied Text', 'code-click-to-copy'), |
|---|
| 88 | 'copied_text_callback', |
|---|
| 89 | 'code-click-to-copy', |
|---|
| 90 | 'code_click_to_copy_section' |
|---|
| 91 | ); |
|---|
| 92 | |
|---|
| 93 | // 5. Tooltip Hover CSS Class |
|---|
| 94 | add_settings_field( |
|---|
| 95 | 'tooltip_custom_class', |
|---|
| 96 | __('Tooltip Hover CSS Class', 'code-click-to-copy'), |
|---|
| 97 | 'tooltip_custom_class_callback', |
|---|
| 98 | 'code-click-to-copy', |
|---|
| 99 | 'code_click_to_copy_section' |
|---|
| 100 | ); |
|---|
| 101 | |
|---|
| 102 | // 6. Tooltip Function CSS Class |
|---|
| 103 | add_settings_field( |
|---|
| 104 | 'custom_css_class', |
|---|
| 105 | __('Tooltip Function CSS Class', 'code-click-to-copy'), |
|---|
| 106 | 'custom_css_class_callback', |
|---|
| 107 | 'code-click-to-copy', |
|---|
| 108 | 'code_click_to_copy_section' |
|---|
| 109 | ); |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | function code_click_to_copy_section_callback() { |
|---|
| 113 | // Removed extra explanation text |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | function tooltip_background_callback() { |
|---|
| 117 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 118 | $background = isset($options['tooltip_background']) ? $options['tooltip_background'] : '#333333'; |
|---|
| 119 | // Convert 3-digit hex to 6-digit if needed |
|---|
| 120 | if (preg_match('/^#([0-9A-F])([0-9A-F])([0-9A-F])$/i', $background, $matches)) { |
|---|
| 121 | $background = '#' . $matches[1] . $matches[1] . $matches[2] . $matches[2] . $matches[3] . $matches[3]; |
|---|
| 122 | } |
|---|
| 123 | echo '<div style="display:flex;align-items:center;gap:10px;">'; |
|---|
| 124 | echo '<input type="color" name="code_click_to_copy_settings[tooltip_background]" value="' . esc_attr($background) . '" style="width:50px;height:30px;">'; |
|---|
| 125 | echo '<input type="text" class="hex-input" value="' . esc_attr($background) . '" style="width:100px;" placeholder="#000000">'; |
|---|
| 126 | echo ' <a href="#" class="reset-color" data-default="#333333">' . esc_html__('Reset', 'code-click-to-copy') . '</a>'; |
|---|
| 127 | echo '</div>'; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | function tooltip_text_color_callback() { |
|---|
| 131 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 132 | $text_color = isset($options['tooltip_text_color']) ? $options['tooltip_text_color'] : '#ffffff'; |
|---|
| 133 | // Convert 3-digit hex to 6-digit if needed |
|---|
| 134 | if (preg_match('/^#([0-9A-F])([0-9A-F])([0-9A-F])$/i', $text_color, $matches)) { |
|---|
| 135 | $text_color = '#' . $matches[1] . $matches[1] . $matches[2] . $matches[2] . $matches[3] . $matches[3]; |
|---|
| 136 | } |
|---|
| 137 | echo '<div style="display:flex;align-items:center;gap:10px;">'; |
|---|
| 138 | echo '<input type="color" name="code_click_to_copy_settings[tooltip_text_color]" value="' . esc_attr($text_color) . '" style="width:50px;height:30px;">'; |
|---|
| 139 | echo '<input type="text" class="hex-input" value="' . esc_attr($text_color) . '" style="width:100px;" placeholder="#000000">'; |
|---|
| 140 | echo ' <a href="#" class="reset-color" data-default="#ffffff">' . esc_html__('Reset', 'code-click-to-copy') . '</a>'; |
|---|
| 141 | echo '</div>'; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | function click_to_copy_text_callback() { |
|---|
| 145 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 146 | $val = isset($options['click_to_copy_text']) ? $options['click_to_copy_text'] : ''; |
|---|
| 147 | echo '<input type="text" name="code_click_to_copy_settings[click_to_copy_text]" value="' . esc_attr($val) . '" placeholder="' . esc_attr__('Click to Copy (default)', 'code-click-to-copy') . '" />'; |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | function copied_text_callback() { |
|---|
| 151 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 152 | $val = isset($options['copied_text']) ? $options['copied_text'] : ''; |
|---|
| 153 | echo '<input type="text" name="code_click_to_copy_settings[copied_text]" value="' . esc_attr($val) . '" placeholder="' . esc_attr__('Copied! (default)', 'code-click-to-copy') . '" />'; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | function tooltip_custom_class_callback() { |
|---|
| 157 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 158 | $val = isset($options['tooltip_custom_class']) ? $options['tooltip_custom_class'] : 'codeCopyTooltip'; |
|---|
| 159 | echo '<input type="text" name="code_click_to_copy_settings[tooltip_custom_class]" value="' . esc_attr($val) . '" placeholder="' . esc_attr__('e.g. my-tooltip-class', 'code-click-to-copy') . '" />'; |
|---|
| 160 | echo '<br><small style="color:#666;">' . sprintf(esc_html__('Use default %1$scodeCopyTooltip%2$s class, or restyle tooltip hover with your own.', 'code-click-to-copy'),'<code>','</code>') . '</small>'; |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | function custom_css_class_callback() { |
|---|
| 164 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 165 | if (isset($options['custom_css_class']) && trim($options['custom_css_class']) !== '') { |
|---|
| 166 | $custom_class = $options['custom_css_class']; |
|---|
| 167 | } else { |
|---|
| 168 | $custom_class = 'code, pre'; |
|---|
| 169 | } |
|---|
| 170 | echo '<input type="text" name="code_click_to_copy_settings[custom_css_class]" value="' . esc_attr($custom_class) . '" placeholder="' . esc_attr__('e.g. my-copy-class,another-class', 'code-click-to-copy') . '" />'; |
|---|
| 171 | echo '<br><small style="color:#666;">' . sprintf(esc_html__('Enter class names (without dot or spaces) to apply tooltip function, separate by comma if multiple. Can add to, or replace existing default class %1$scode%2$s, %1$spre%2$s.', 'code-click-to-copy'),'<code>','</code>') . '</small>'; |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | |
|---|
| 175 | |
|---|
| 176 | function code_click_to_copy_settings_page() { |
|---|
| 177 | if (!current_user_can('manage_options')) { |
|---|
| 178 | return; |
|---|
| 179 | } |
|---|
| 180 | ?> |
|---|
| 181 | <div class="wrap"> |
|---|
| 182 | <h1><?php echo esc_html(get_admin_page_title()); ?></h1> |
|---|
| 183 | <form action="options.php" method="post"> |
|---|
| 184 | <?php |
|---|
| 185 | settings_fields('code_click_to_copy'); |
|---|
| 186 | do_settings_sections('code-click-to-copy'); |
|---|
| 187 | submit_button(esc_html__('Save Settings', 'code-click-to-copy')); |
|---|
| 188 | ?> |
|---|
| 189 | </form> |
|---|
| 190 | <p style="margin-top:30px; color:#555;"> |
|---|
| 191 | <?php printf(esc_html__( 'Like this plugin? %1$sBuy me a beer%2$s or %3$sleave a 5-star review%2$s.', 'code-click-to-copy' ),'<a href="https://www.paypal.me/wpjohnny" target="_blank">','</a>','<a href="https://wordpress.org/support/plugin/code-click-to-copy/reviews/#new-post" target="_blank">'); ?> |
|---|
| 192 | </p> |
|---|
| 193 | </div> |
|---|
| 194 | <?php |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | add_action('wp_footer', 'codeCopyActivate'); |
|---|
| 198 | function codeCopyActivate(){ |
|---|
| 199 | // Only run on frontend, not in admin areas |
|---|
| 200 | if (is_admin()) { |
|---|
| 201 | return; |
|---|
| 202 | } |
|---|
| 203 | |
|---|
| 204 | $options = get_option('code_click_to_copy_settings'); |
|---|
| 205 | $clickToCopyStr = isset($options['click_to_copy_text']) && $options['click_to_copy_text'] !== '' ? $options['click_to_copy_text'] : __('Click to Copy', 'code-click-to-copy'); |
|---|
| 206 | $copiedMessage = isset($options['copied_text']) && $options['copied_text'] !== '' ? $options['copied_text'] : __('Copied!', 'code-click-to-copy'); |
|---|
| 207 | $tooltip_bg = isset($options['tooltip_background']) ? $options['tooltip_background'] : '#333333'; |
|---|
| 208 | $tooltip_text = isset($options['tooltip_text_color']) ? $options['tooltip_text_color'] : '#ffffff'; |
|---|
| 209 | if (isset($options['custom_css_class'])) { |
|---|
| 210 | $custom_class = $options['custom_css_class']; |
|---|
| 211 | } else { |
|---|
| 212 | $custom_class = 'code'; |
|---|
| 213 | } |
|---|
| 214 | $tooltip_custom_class = isset($options['tooltip_custom_class']) ? trim($options['tooltip_custom_class']) : 'codeCopyTooltip'; |
|---|
| 215 | ?> |
|---|
| 216 | |
|---|
| 217 | |
|---|
| 218 | |
|---|
| 219 | |
|---|
| 220 | <div class="codeCopyTooltip <?php echo esc_attr($tooltip_custom_class); ?>" style="display: inline-block; background: <?php echo esc_attr($tooltip_bg); ?>; color: <?php echo esc_attr($tooltip_text); ?>; padding: 0 8px; font-size: 14px; border-radius: 2px; border: 1px solid #111; position: absolute; display: none;"> |
|---|
| 221 | <?= $clickToCopyStr; ?></div> |
|---|
| 222 | <script type="text/javascript"> |
|---|
| 223 | function getElementPosition(el) { |
|---|
| 224 | var rect = el.getBoundingClientRect(), |
|---|
| 225 | scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, |
|---|
| 226 | scrollTop = window.pageYOffset || document.documentElement.scrollTop; |
|---|
| 227 | return { top: rect.top + scrollTop - 30, left: rect.left + scrollLeft } |
|---|
| 228 | } |
|---|
| 229 | |
|---|
| 230 | async function copyToClipboard(text) { |
|---|
| 231 | try { |
|---|
| 232 | console.log('Code Click to Copy: Attempting to copy text:', text.substring(0, 50) + '...'); |
|---|
| 233 | // Try modern Clipboard API first |
|---|
| 234 | if (navigator.clipboard && window.isSecureContext) { |
|---|
| 235 | console.log('Code Click to Copy: Using modern Clipboard API'); |
|---|
| 236 | await navigator.clipboard.writeText(text); |
|---|
| 237 | console.log('Code Click to Copy: Successfully copied with Clipboard API'); |
|---|
| 238 | return true; |
|---|
| 239 | } else { |
|---|
| 240 | console.log('Code Click to Copy: Using fallback execCommand method'); |
|---|
| 241 | // Fallback for older browsers or non-secure contexts |
|---|
| 242 | const textArea = document.createElement('textarea'); |
|---|
| 243 | textArea.value = text; |
|---|
| 244 | textArea.style.position = 'fixed'; |
|---|
| 245 | textArea.style.left = '-999999px'; |
|---|
| 246 | textArea.style.top = '-999999px'; |
|---|
| 247 | document.body.appendChild(textArea); |
|---|
| 248 | textArea.focus(); |
|---|
| 249 | textArea.select(); |
|---|
| 250 | |
|---|
| 251 | try { |
|---|
| 252 | document.execCommand('copy'); |
|---|
| 253 | document.body.removeChild(textArea); |
|---|
| 254 | console.log('Code Click to Copy: Successfully copied with execCommand'); |
|---|
| 255 | return true; |
|---|
| 256 | } catch (err) { |
|---|
| 257 | document.body.removeChild(textArea); |
|---|
| 258 | console.error('Code Click to Copy: execCommand failed:', err); |
|---|
| 259 | return false; |
|---|
| 260 | } |
|---|
| 261 | } |
|---|
| 262 | } catch (err) { |
|---|
| 263 | console.error('Code Click to Copy: Failed to copy: ', err); |
|---|
| 264 | return false; |
|---|
| 265 | } |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | function applyCodeCopy(element) { |
|---|
| 269 | element.style.cursor = 'pointer'; |
|---|
| 270 | element.style.position = 'relative'; |
|---|
| 271 | |
|---|
| 272 | element.addEventListener("click", async function(event) { |
|---|
| 273 | event.stopPropagation(); |
|---|
| 274 | const textToCopy = element.textContent || element.innerText; |
|---|
| 275 | |
|---|
| 276 | const success = await copyToClipboard(textToCopy); |
|---|
| 277 | |
|---|
| 278 | if (success) { |
|---|
| 279 | codeCopyTooltip.innerHTML = <?= json_encode($copiedMessage); ?>; |
|---|
| 280 | codeCopyTooltip.style.display = 'block'; |
|---|
| 281 | |
|---|
| 282 | // Hide tooltip after 2 seconds |
|---|
| 283 | setTimeout(() => { |
|---|
| 284 | codeCopyTooltip.style.display = 'none'; |
|---|
| 285 | }, 2000); |
|---|
| 286 | } else { |
|---|
| 287 | codeCopyTooltip.innerHTML = 'Failed to copy'; |
|---|
| 288 | codeCopyTooltip.style.display = 'block'; |
|---|
| 289 | |
|---|
| 290 | setTimeout(() => { |
|---|
| 291 | codeCopyTooltip.style.display = 'none'; |
|---|
| 292 | }, 2000); |
|---|
| 293 | } |
|---|
| 294 | }); |
|---|
| 295 | |
|---|
| 296 | element.addEventListener("mouseover", function(event) { |
|---|
| 297 | event.stopPropagation(); |
|---|
| 298 | var position = getElementPosition(element); |
|---|
| 299 | codeCopyTooltip.innerHTML = <?= json_encode($clickToCopyStr); ?>; |
|---|
| 300 | codeCopyTooltip.style.display = 'inline-block'; |
|---|
| 301 | codeCopyTooltip.style.top = position.top + 'px'; |
|---|
| 302 | codeCopyTooltip.style.left = position.left + 'px'; |
|---|
| 303 | }); |
|---|
| 304 | |
|---|
| 305 | element.addEventListener("mouseout", function(event) { |
|---|
| 306 | event.stopPropagation(); |
|---|
| 307 | codeCopyTooltip.style.display = 'none'; |
|---|
| 308 | }); |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | var codeCopyTooltip = document.querySelector('.<?php echo esc_js($tooltip_custom_class); ?>'); |
|---|
| 312 | |
|---|
| 313 | (function() { |
|---|
| 314 | var selector = '<?php echo esc_js($custom_class); ?>'; |
|---|
| 315 | if(selector.indexOf(',') !== -1) { |
|---|
| 316 | selector = selector.split(',').map(function(sel) { |
|---|
| 317 | sel = sel.trim(); |
|---|
| 318 | if (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(sel)) { |
|---|
| 319 | return sel; |
|---|
| 320 | } else if (sel.startsWith('.')) { |
|---|
| 321 | return sel; |
|---|
| 322 | } else { |
|---|
| 323 | return '.' + sel; |
|---|
| 324 | } |
|---|
| 325 | }).join(', '); |
|---|
| 326 | } else { |
|---|
| 327 | selector = selector.trim(); |
|---|
| 328 | if (!selector.startsWith('.') && !/^[a-zA-Z][a-zA-Z0-9-]*$/.test(selector)) { |
|---|
| 329 | selector = '.' + selector; |
|---|
| 330 | } |
|---|
| 331 | } |
|---|
| 332 | |
|---|
| 333 | // console.log('Code Click to Copy: Looking for elements with selector:', selector); |
|---|
| 334 | |
|---|
| 335 | // Wait for DOM to be ready |
|---|
| 336 | if (document.readyState === 'loading') { |
|---|
| 337 | document.addEventListener('DOMContentLoaded', function() { |
|---|
| 338 | var elements = document.querySelectorAll(selector); |
|---|
| 339 | // console.log('Code Click to Copy: Found', elements.length, 'elements on DOMContentLoaded'); |
|---|
| 340 | elements.forEach(function(element) { |
|---|
| 341 | applyCodeCopy(element); |
|---|
| 342 | }); |
|---|
| 343 | }); |
|---|
| 344 | } else { |
|---|
| 345 | var elements = document.querySelectorAll(selector); |
|---|
| 346 | // console.log('Code Click to Copy: Found', elements.length, 'elements immediately'); |
|---|
| 347 | elements.forEach(function(element) { |
|---|
| 348 | applyCodeCopy(element); |
|---|
| 349 | }); |
|---|
| 350 | } |
|---|
| 351 | |
|---|
| 352 | // Also handle dynamically added content |
|---|
| 353 | var observer = new MutationObserver(function(mutations) { |
|---|
| 354 | mutations.forEach(function(mutation) { |
|---|
| 355 | mutation.addedNodes.forEach(function(node) { |
|---|
| 356 | if (node.nodeType === 1) { // Element node |
|---|
| 357 | if (node.matches && node.matches(selector)) { |
|---|
| 358 | applyCodeCopy(node); |
|---|
| 359 | } |
|---|
| 360 | if (node.querySelectorAll) { |
|---|
| 361 | node.querySelectorAll(selector).forEach(function(element) { |
|---|
| 362 | applyCodeCopy(element); |
|---|
| 363 | }); |
|---|
| 364 | } |
|---|
| 365 | } |
|---|
| 366 | }); |
|---|
| 367 | }); |
|---|
| 368 | }); |
|---|
| 369 | |
|---|
| 370 | observer.observe(document.body, { |
|---|
| 371 | childList: true, |
|---|
| 372 | subtree: true |
|---|
| 373 | }); |
|---|
| 374 | })(); |
|---|
| 375 | </script> |
|---|
| 376 | <?php |
|---|
| 377 | }; |
|---|
| 378 | |
|---|
| 379 | function enqueue_admin_scripts($hook) { |
|---|
| 380 | if ('settings_page_code-click-to-copy' !== $hook) { |
|---|
| 381 | return; |
|---|
| 382 | } |
|---|
| 383 | wp_add_inline_script('jquery', ' |
|---|
| 384 | jQuery(document).ready(function($) { |
|---|
| 385 | // Function to convert 3-digit hex to 6-digit |
|---|
| 386 | function expandHex(hex) { |
|---|
| 387 | if (hex.match(/^#([0-9A-F])([0-9A-F])([0-9A-F])$/i)) { |
|---|
| 388 | return hex.replace(/^#([0-9A-F])([0-9A-F])([0-9A-F])$/i, "#$1$1$2$2$3$3"); |
|---|
| 389 | } |
|---|
| 390 | return hex; |
|---|
| 391 | } |
|---|
| 392 | |
|---|
| 393 | // Function to validate hex color |
|---|
| 394 | function isValidHex(hex) { |
|---|
| 395 | return /^#[0-9A-F]{6}$/i.test(hex) || /^#[0-9A-F]{3}$/i.test(hex); |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | // Sync color picker with HEX input |
|---|
| 399 | $("input[type=color]").on("input", function() { |
|---|
| 400 | var color = expandHex($(this).val()); |
|---|
| 401 | $(this).next(".hex-input").val(color); |
|---|
| 402 | }); |
|---|
| 403 | |
|---|
| 404 | // Sync HEX input with color picker |
|---|
| 405 | $(".hex-input").on("input", function() { |
|---|
| 406 | var color = $(this).val(); |
|---|
| 407 | if (isValidHex(color)) { |
|---|
| 408 | var expandedColor = expandHex(color); |
|---|
| 409 | $(this).prev("input[type=color]").val(expandedColor); |
|---|
| 410 | $(this).val(expandedColor); |
|---|
| 411 | } |
|---|
| 412 | }); |
|---|
| 413 | |
|---|
| 414 | // Reset functionality |
|---|
| 415 | $(".reset-color").on("click", function(e) { |
|---|
| 416 | e.preventDefault(); |
|---|
| 417 | var defaultColor = $(this).data("default"); |
|---|
| 418 | var colorInput = $(this).prevAll("input[type=color]"); |
|---|
| 419 | var hexInput = $(this).prevAll("input.hex-input"); |
|---|
| 420 | colorInput.val(defaultColor); |
|---|
| 421 | hexInput.val(defaultColor); |
|---|
| 422 | }); |
|---|
| 423 | }); |
|---|
| 424 | '); |
|---|
| 425 | } |
|---|
| 426 | |
|---|
| 427 | |
|---|
| 428 | |
|---|