diff --git a/assets/admin.css b/assets/admin.css index 4304974..e427ff0 100644 --- a/assets/admin.css +++ b/assets/admin.css @@ -16,17 +16,38 @@ .wptag-header-info p { margin: 0; color: #666; + font-size: 14px; + line-height: 1.5; } .wptag-header-actions { display: flex; gap: 10px; + flex-shrink: 0; +} + +.wptag-header-actions .button { + display: flex; + align-items: center; + gap: 6px; } .nav-tab-wrapper { margin-bottom: 0; } +.nav-tab { + display: flex; + align-items: center; + gap: 6px; +} + +.nav-tab .dashicons { + font-size: 16px; + width: 16px; + height: 16px; +} + .nav-tab .count { background: #72aee6; color: #fff; @@ -47,17 +68,36 @@ border-top: none; padding: 20px; border-radius: 0 0 4px 4px; + min-height: 400px; } .wptag-no-services { text-align: center; - padding: 40px 20px; + padding: 60px 20px; color: #666; } +.wptag-no-services-icon { + margin-bottom: 20px; +} + +.wptag-no-services-icon .dashicons { + font-size: 64px; + width: 64px; + height: 64px; + color: #ccc; +} + +.wptag-no-services h3 { + margin: 0 0 10px 0; + color: #333; + font-size: 18px; +} + .wptag-no-services p { - font-size: 16px; + font-size: 14px; margin: 0; + line-height: 1.6; } .wptag-services-grid { @@ -73,14 +113,33 @@ border-radius: 8px; overflow: hidden; transition: all 0.3s ease; + position: relative; } .wptag-service-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.1); + transform: translateY(-1px); +} + +.wptag-service-card.enabled { + border-color: #46b450; +} + +.wptag-service-card.enabled .wptag-service-header { + background: linear-gradient(135deg, #46b450 0%, #5cbf60 100%); + color: #fff; +} + +.wptag-service-card.enabled .wptag-service-icon .dashicons { + color: #fff; +} + +.wptag-service-card.enabled .wptag-service-title h3 { + color: #fff; } .wptag-service-card.disabled { - opacity: 0.6; + opacity: 0.7; } .wptag-service-card.disabled .wptag-service-content { @@ -90,13 +149,15 @@ .wptag-service-header { display: flex; align-items: center; - padding: 20px; + padding: 15px 20px; background: #fff; border-bottom: 1px solid #e1e1e1; + transition: all 0.3s ease; } .wptag-service-icon { margin-right: 15px; + flex-shrink: 0; } .wptag-service-icon .dashicons { @@ -107,14 +168,6 @@ transition: color 0.3s ease; } -.wptag-service-card:hover .wptag-service-icon .dashicons { - color: #2271b1; -} - -.wptag-service-item:hover .wptag-service-icon .dashicons { - color: #2271b1; -} - .wptag-service-title { flex: 1; display: flex; @@ -127,6 +180,7 @@ font-size: 16px; font-weight: 600; color: #23282d; + transition: color 0.3s ease; } .wptag-switch { @@ -164,37 +218,147 @@ background-color: white; transition: .4s; border-radius: 50%; + box-shadow: 0 2px 4px rgba(0,0,0,0.2); } input:checked + .wptag-slider { background-color: #2271b1; } +input:checked + .wptag-slider:before { + transform: translateX(26px); +} + +input:focus + .wptag-slider { + box-shadow: 0 0 1px #2271b1; +} + .wptag-slider.disabled { pointer-events: none; opacity: 0.5; } +.wptag-service-content { + padding: 20px; +} + +.wptag-form-row { + margin-bottom: 20px; +} + +.wptag-form-label { + display: block; + margin-bottom: 8px; + font-weight: 400; + color: #23282d; + font-size: 12px; +} + +.wptag-form-label .required { + color: #dc3232; + margin-left: 2px; +} + +.wptag-radio-group { + display: flex; + gap: 25px; + background: #f8f9fa; + padding: 12px 16px; + border-radius: 6px; + border: 1px solid #e1e1e1; +} + +.wptag-radio-group label { + display: flex; + align-items: center; + font-weight: 400; + font-size: 12px; + cursor: pointer; + color: #555; + transition: color 0.2s ease; +} + +.wptag-radio-group label:hover { + color: #2271b1; +} + +.wptag-radio-group input[type="radio"] { + margin-right: 8px; + margin-top: 0; +} + +.wptag-input-group { + display: flex; + gap: 10px; + align-items: flex-start; +} + +.wptag-input, +.wptag-textarea, +.wptag-select { + flex: 1; + padding: 10px 12px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 14px; + transition: all 0.3s ease; + background: #fff; +} + +.wptag-input:focus, +.wptag-textarea:focus, +.wptag-select:focus { + border-color: #2271b1; + outline: none; + box-shadow: 0 0 0 1px #2271b1; +} + +.wptag-input:disabled, +.wptag-textarea:disabled, +.wptag-select:disabled { + background-color: #f0f0f0; + color: #666; + cursor: not-allowed; +} + +.wptag-input-small { + max-width: 100px; + flex: none; +} + .wptag-code-editor-wrapper { position: relative; border: 1px solid #ddd; - border-radius: 4px; + border-radius: 6px; background: #f8f9fa; - margin-bottom: 10px; + overflow: hidden; +} + +.wptag-code-editor-wrapper::before { + content: 'JavaScript Supported'; + position: absolute; + top: 6px; + left: 10px; + background: #28a745; + color: white; + font-size: 10px; + padding: 2px 6px; + border-radius: 3px; + z-index: 2; + font-weight: 500; + letter-spacing: 0.5px; } .wptag-code-editor { width: 100%; - padding: 15px; + padding: 26px 16px 16px 16px; border: none; - border-radius: 4px; - font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; font-size: 13px; - line-height: 1.5; + line-height: 1.6; background: #fff; color: #333; resize: none; - overflow-y: auto; min-height: 120px; max-height: 400px; box-sizing: border-box; @@ -203,8 +367,7 @@ input:checked + .wptag-slider { .wptag-code-editor:focus { outline: none; - border-color: #2271b1; - box-shadow: 0 0 0 1px #2271b1; + box-shadow: inset 0 0 0 1px #2271b1; } .wptag-code-editor:disabled { @@ -215,11 +378,11 @@ input:checked + .wptag-slider { .wptag-code-editor-toolbar { position: absolute; - top: 8px; - right: 8px; + top: 26px; + right: 10px; display: flex; - gap: 5px; - opacity: 0.7; + gap: 6px; + opacity: 0; transition: opacity 0.3s ease; } @@ -228,36 +391,120 @@ input:checked + .wptag-slider { } .wptag-code-editor-toolbar .button { - padding: 4px 8px; + padding: 6px 10px; min-height: auto; - background: rgba(255, 255, 255, 0.9); + background: rgba(255, 255, 255, 0.95); border: 1px solid #ddd; border-radius: 3px; font-size: 12px; + backdrop-filter: blur(10px); + transition: all 0.2s ease; } .wptag-code-editor-toolbar .button:hover { background: #f0f0f0; + transform: translateY(-1px); +} + +.wptag-validation-result { + margin-top: 10px; + padding: 8px 12px; + border-radius: 4px; + font-size: 13px; + font-weight: 500; + display: none; +} + +.wptag-validation-result.valid { + background: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; + display: block; +} + +.wptag-validation-result.invalid { + background: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + display: block; +} + +.wptag-validation-result.loading { + background: #d1ecf1; + color: #0c5460; + border: 1px solid #bee5eb; + display: block; +} + +.wptag-field-help { + margin-top: 6px; +} + +.wptag-field-help small { + color: #666; + font-size: 12px; + line-height: 1.4; + display: block; + margin-bottom: 4px; +} + +.wptag-field-help small:last-child { + margin-bottom: 0; +} + +.wptag-field-help a { + color: #b2b2b2; + text-decoration: none; + font-weight: 400; +} + +.wptag-field-help a:hover { + color: #135e96; + text-decoration: underline; +} + +.wptag-field-help a:after { + content: " ↗"; + margin-right: 2px; +} + +.wptag-template-fields, +.wptag-custom-fields { + transition: all 0.3s ease; +} + +.wptag-advanced-settings { + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid #e1e1e1; + display: none; +} + +.wptag-advanced-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + gap: 15px; } .wptag-advanced-toggle { border-top: 1px solid #e1e1e1; padding-top: 15px; - margin-top: 15px; + margin-top: 20px; } .wptag-toggle-advanced { display: flex; align-items: center; - gap: 5px; + gap: 6px; color: #666; text-decoration: none; - font-size: 13px; - padding: 5px 0; + font-size: 12px; + padding: 8px 0; border: none; background: none; cursor: pointer; transition: color 0.2s ease; + font-weight: 400; } .wptag-toggle-advanced:hover { @@ -274,137 +521,21 @@ input:checked + .wptag-slider { font-size: 16px; width: 16px; height: 16px; - transition: transform 0.2s ease; -} - -.wptag-advanced-settings { - margin-top: 15px; - padding-top: 15px; - border-top: 1px solid #e1e1e1; -} - -.wptag-service-card.disabled .wptag-code-editor-wrapper { - opacity: 0.6; - pointer-events: none; -} - -.wptag-service-card.disabled .wptag-code-editor-toolbar { - opacity: 0.5; - pointer-events: none; -} - -.wptag-service-card.disabled .wptag-toggle-advanced { - opacity: 0.6; - pointer-events: none; -} - -.wptag-service-content { - padding: 20px; -} - -.wptag-form-row { - margin-bottom: 20px; -} - -.wptag-form-label { - display: block; - margin-bottom: 5px; - font-weight: 600; - color: #23282d; -} - -.wptag-radio-group { - display: flex; - gap: 20px; -} - -.wptag-radio-group label { - display: flex; - align-items: center; - font-weight: normal; - cursor: pointer; -} - -.wptag-radio-group input[type="radio"] { - margin-right: 8px; -} - -.wptag-input-group { - display: flex; - gap: 10px; - align-items: flex-start; -} - -.wptag-input, -.wptag-textarea, -.wptag-select { - flex: 1; - padding: 8px 12px; - border: 1px solid #ddd; - border-radius: 4px; - font-size: 14px; - transition: border-color 0.3s ease; -} - -.wptag-input:focus, -.wptag-textarea:focus, -.wptag-select:focus { - border-color: #2271b1; - outline: none; - box-shadow: 0 0 0 1px #2271b1; -} - -.wptag-input-small { - max-width: 100px; -} - -.wptag-textarea { - font-family: Consolas, Monaco, monospace; - font-size: 13px; - min-height: 120px; - resize: vertical; -} - -.wptag-validation-result { - margin-top: 8px; - font-size: 13px; - font-weight: 600; -} - -.wptag-validation-result.valid { - color: #46b450; -} - -.wptag-validation-result.invalid { - color: #dc3232; -} - -.wptag-validation-result.loading { - color: #0073aa; -} - -.wptag-template-fields, -.wptag-custom-fields { - transition: all 0.3s ease; -} - -.wptag-advanced-settings { - margin-top: 15px; - padding-top: 15px; - border-top: 1px solid #e1e1e1; - display: none; - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: 15px; + transition: transform 0.3s ease; } .wptag-form-actions { text-align: right; padding-top: 20px; border-top: 1px solid #ddd; + margin-top: 30px; } .wptag-validate-btn, .wptag-preview-btn { + display: flex; + align-items: center; + gap: 6px; background: #0073aa; color: #fff; border: none; @@ -412,18 +543,22 @@ input:checked + .wptag-slider { border-radius: 4px; cursor: pointer; font-size: 13px; - transition: background-color 0.3s ease; + font-weight: 500; + transition: all 0.3s ease; + flex-shrink: 0; } .wptag-validate-btn:hover, .wptag-preview-btn:hover { background: #005a87; + transform: translateY(-1px); } .wptag-validate-btn:disabled, .wptag-preview-btn:disabled { background: #ccc; cursor: not-allowed; + transform: none; } .wptag-preview-btn { @@ -449,14 +584,72 @@ input:checked + .wptag-slider { border-radius: 4px; } -.wptag-services-header p { +.wptag-services-info p { margin: 0; color: #666; + font-size: 14px; +} + +.wptag-services-info p small { + color: #28a745; + font-weight: 500; +} + +.wptag-services-info p small strong { + color: #155724; + background: #d4edda; + padding: 2px 4px; + border-radius: 3px; +} + +.wptag-field-help details { + margin-top: 8px; +} + +.wptag-field-help summary { + cursor: pointer; + font-size: 11px; + color: #666; + user-select: none; +} + +.wptag-field-help summary:hover { + color: #2271b1; +} + +.wptag-field-help pre { + background: #f8f9fa; + padding: 8px; + border-radius: 4px; + font-size: 11px; + margin-top: 4px; + overflow-x: auto; + border: 1px solid #e1e1e1; +} + +body.wp-admin script[src*="googletagmanager"], +body.wp-admin script[src*="google-analytics"], +body.wp-admin script[src*="facebook"], +body.wp-admin script[src*="clarity.ms"], +body.wp-admin script[src*="hotjar"], +body.wp-admin script[src*="tiktok"], +body.wp-admin script[src*="linkedin"], +body.wp-admin script[src*="twitter"], +body.wp-admin script[src*="pinterest"], +body.wp-admin script[src*="snapchat"] { + display: none !important; +} + +body.wp-admin noscript img[src*="facebook"], +body.wp-admin noscript img[src*="linkedin"], +body.wp-admin noscript img[src*="pinterest"] { + display: none !important; } .wptag-services-actions { display: flex; gap: 10px; + flex-shrink: 0; } .wptag-service-category { @@ -470,6 +663,9 @@ input:checked + .wptag-slider { font-weight: 600; border-bottom: 2px solid #2271b1; padding-bottom: 10px; + display: flex; + align-items: center; + gap: 10px; } .wptag-service-item { @@ -486,6 +682,12 @@ input:checked + .wptag-slider { .wptag-service-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.1); + transform: translateY(-1px); +} + +.wptag-service-item.enabled { + border-color: #46b450; + background: linear-gradient(135deg, #f8fff8 0%, #f0f9f0 100%); } .wptag-service-item.disabled { @@ -507,39 +709,83 @@ input:checked + .wptag-slider { .wptag-service-details p { margin: 0; - color: #666; - font-size: 14px; + color: #b2b2b2; + font-size: 12px; + line-height: 1.4; } -#wptag-preview-modal { +.wptag-service-details p:not(:last-child) { + margin-bottom: 8px; +} + +.wptag-service-details p small a { + color: #2271b1; + text-decoration: none; + font-weight: 500; +} + +.wptag-service-details p small a:hover { + color: #135e96; + text-decoration: underline; +} + +.wptag-service-details p small a:before { + content: "📚 "; + margin-right: 2px; +} + +.wptag-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; - background: rgba(0,0,0,0.5); z-index: 100000; display: flex; align-items: center; justify-content: center; } +.wptag-modal-backdrop { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.6); + backdrop-filter: blur(3px); +} + .wptag-modal-content { background: #fff; border-radius: 8px; - max-width: 80%; + max-width: 90%; max-height: 80%; overflow: hidden; display: flex; flex-direction: column; - box-shadow: 0 10px 40px rgba(0,0,0,0.3); + box-shadow: 0 20px 60px rgba(0,0,0,0.3); + position: relative; + z-index: 1; + animation: modalSlideIn 0.3s ease; +} + +@keyframes modalSlideIn { + from { + opacity: 0; + transform: scale(0.9) translateY(-20px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } } .wptag-modal-header { display: flex; justify-content: space-between; align-items: center; - padding: 20px; + padding: 20px 24px; border-bottom: 1px solid #e1e1e1; background: #f9f9f9; } @@ -548,6 +794,7 @@ input:checked + .wptag-slider { margin: 0; font-size: 18px; color: #23282d; + font-weight: 600; } .wptag-modal-close { @@ -557,8 +804,8 @@ input:checked + .wptag-slider { cursor: pointer; color: #666; padding: 0; - width: 30px; - height: 30px; + width: 32px; + height: 32px; display: flex; align-items: center; justify-content: center; @@ -572,92 +819,30 @@ input:checked + .wptag-slider { } .wptag-modal-body { - padding: 20px; + padding: 24px; overflow: auto; + flex: 1; } #wptag-preview-code { background: #f4f4f4; border: 1px solid #ddd; - border-radius: 4px; - padding: 15px; - font-family: Consolas, Monaco, monospace; + border-radius: 6px; + padding: 20px; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; font-size: 13px; - line-height: 1.5; + line-height: 1.6; white-space: pre-wrap; word-wrap: break-word; margin: 0; min-height: 200px; color: #333; -} - -@media screen and (max-width: 1200px) { - .wptag-services-grid { - grid-template-columns: 1fr; - } -} - -@media screen and (max-width: 782px) { - .wptag-header { - flex-direction: column; - gap: 15px; - } - - .wptag-header-actions { - width: 100%; - justify-content: center; - } - - .wptag-services-header { - flex-direction: column; - gap: 15px; - } - - .wptag-services-actions { - width: 100%; - justify-content: center; - } - - .wptag-input-group { - flex-direction: column; - } - - .wptag-input-group button { - align-self: flex-start; - } - - .wptag-advanced-settings { - grid-template-columns: 1fr; - } - - .wptag-radio-group { - flex-direction: column; - gap: 10px; - } - - .wptag-modal-content { - max-width: 95%; - max-height: 95%; - } - - .wptag-service-item { - flex-direction: column; - gap: 15px; - } - - .wptag-service-info { - text-align: center; - } - - .wptag-service-toggle { - align-self: center; - } + max-height: 500px; + overflow: auto; } .wptag-loading { position: relative; - opacity: 0.6; - pointer-events: none; } .wptag-loading::after { @@ -672,6 +857,7 @@ input:checked + .wptag-slider { border-radius: 50%; animation: spin 1s linear infinite; transform: translate(-50%, -50%); + z-index: 1; } @keyframes spin { @@ -679,28 +865,41 @@ input:checked + .wptag-slider { 100% { transform: translate(-50%, -50%) rotate(360deg); } } -.wptag-text-center { - text-align: center; +.wptag-button-loading { + opacity: 0.7; + pointer-events: none; } -.wptag-text-muted { - color: #666; +.wptag-button-loading::after { + content: ''; + display: inline-block; + width: 12px; + height: 12px; + margin-left: 8px; + border: 2px solid transparent; + border-top-color: currentColor; + border-radius: 50%; + animation: spin 1s linear infinite; } -.wptag-mb-0 { - margin-bottom: 0; -} - -.wptag-mt-20 { - margin-top: 20px; -} - -.wptag-hidden { - display: none; +#wptag-save-btn.wptag-button-loading { + opacity: 0.7; } .notice { margin: 5px 0 15px 0; + animation: noticeSlideIn 0.3s ease; +} + +@keyframes noticeSlideIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } } .notice.notice-success { @@ -709,4 +908,115 @@ input:checked + .wptag-slider { .notice.notice-error { border-left-color: #dc3232; +} + +@media screen and (max-width: 1200px) { + .wptag-services-grid { + grid-template-columns: 1fr; + } + + .wptag-advanced-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media screen and (max-width: 782px) { + .wptag-header { + flex-direction: column; + gap: 15px; + text-align: center; + } + + .wptag-header-actions { + width: 100%; + justify-content: center; + flex-wrap: wrap; + } + + .wptag-services-header { + flex-direction: column; + gap: 15px; + text-align: center; + } + + .wptag-services-actions { + width: 100%; + justify-content: center; + } + + .wptag-input-group { + flex-direction: column; + gap: 8px; + } + + .wptag-input-group button { + align-self: flex-start; + width: auto; + } + + .wptag-advanced-grid { + grid-template-columns: 1fr; + } + + .wptag-radio-group { + flex-direction: column; + gap: 12px; + } + + .wptag-modal-content { + max-width: 95%; + max-height: 95%; + margin: 20px; + } + + .wptag-service-item { + flex-direction: column; + gap: 15px; + text-align: center; + } + + .wptag-service-info { + justify-content: center; + text-align: center; + } + + .wptag-service-toggle { + align-self: center; + } + + .nav-tab { + font-size: 13px; + padding: 8px 12px; + } + + .wptag-services-grid { + gap: 15px; + } +} + +@media screen and (max-width: 480px) { + .wptag-header-actions { + flex-direction: column; + width: 100%; + } + + .wptag-header-actions .button { + justify-content: center; + } + + .wptag-services-actions { + flex-direction: column; + width: 100%; + } + + .wptag-modal-content { + max-width: 100%; + max-height: 100%; + margin: 0; + border-radius: 0; + } + + .nav-tab .count { + display: none; + } } \ No newline at end of file diff --git a/assets/admin.js b/assets/admin.js index 35a59fa..cee4303 100644 --- a/assets/admin.js +++ b/assets/admin.js @@ -1,11 +1,41 @@ jQuery(document).ready(function($) { + if (typeof window.gtag !== 'undefined') { + delete window.gtag; + } + if (typeof window.fbq !== 'undefined') { + delete window.fbq; + } + if (typeof window.dataLayer !== 'undefined') { + delete window.dataLayer; + } + + window.gtag = function() { + console.log('WPTag: gtag() calls are disabled in admin area'); + }; + window.fbq = function() { + console.log('WPTag: fbq() calls are disabled in admin area'); + }; + WPTagAdmin.init(); + + $(window).on('load', function() { + setTimeout(function() { + WPTagAdmin.initializing = false; + WPTagAdmin.changeTrackingEnabled = true; + }, 500); + }); }); var WPTagAdmin = { + formChanged: false, + changeTrackingEnabled: false, + initializing: true, + init: function() { var $ = jQuery; + var self = this; + this.handleServiceToggle(); this.handleCodeTypeToggle(); this.handleValidation(); @@ -18,39 +48,72 @@ var WPTagAdmin = { this.handleTabSwitching(); this.handleAdvancedToggle(); this.handleCodeEditor(); + this.initTooltips(); + + setTimeout(function() { + self.initializing = false; + self.handleFormChangeTracking(); + }, 1000); }, handleServiceToggle: function() { var $ = jQuery; + var self = this; + $('.wptag-service-card input[name*="[enabled]"]').on('change', function() { var $card = $(this).closest('.wptag-service-card'); var isEnabled = $(this).is(':checked'); + self.changeTrackingEnabled = false; + if (isEnabled) { - $card.removeClass('disabled'); + $card.removeClass('disabled').addClass('enabled'); $card.find('.wptag-service-content input, .wptag-service-content select, .wptag-service-content textarea, .wptag-service-content button').prop('disabled', false); } else { - $card.addClass('disabled'); + $card.removeClass('enabled').addClass('disabled'); $card.find('.wptag-service-content input, .wptag-service-content select, .wptag-service-content textarea, .wptag-service-content button').prop('disabled', true); + $card.find('.wptag-validation-result').hide(); } + + setTimeout(function() { + self.changeTrackingEnabled = true; + if (!self.initializing) { + self.formChanged = true; + } + }, 100); }); - $('.wptag-service-card input[name*="[enabled]"]').trigger('change'); + $('.wptag-service-card input[name*="[enabled]"]').each(function() { + $(this).trigger('change'); + }); }, handleCodeTypeToggle: function() { var $ = jQuery; + var self = this; + $('input[name*="[use_template]"]').on('change', function() { var $card = $(this).closest('.wptag-service-card'); var useTemplate = $(this).val() === '1' && $(this).is(':checked'); + self.changeTrackingEnabled = false; + if (useTemplate) { - $card.find('.wptag-template-fields').show(); - $card.find('.wptag-custom-fields').hide(); + $card.find('.wptag-template-fields').slideDown(300); + $card.find('.wptag-custom-fields').slideUp(300); } else { - $card.find('.wptag-template-fields').hide(); - $card.find('.wptag-custom-fields').show(); + $card.find('.wptag-template-fields').slideUp(300); + $card.find('.wptag-custom-fields').slideDown(300); } + + $card.find('.wptag-validation-result').hide(); + + setTimeout(function() { + self.changeTrackingEnabled = true; + if (!self.initializing) { + self.formChanged = true; + } + }, 100); }); $('input[name*="[use_template]"]:checked').trigger('change'); @@ -58,18 +121,31 @@ var WPTagAdmin = { handleValidation: function() { var $ = jQuery; - $('.wptag-validate-btn').on('click', function() { + + $('.wptag-validate-btn').on('click', function(e) { + e.preventDefault(); + var $btn = $(this); var $card = $btn.closest('.wptag-service-card'); var service = $card.data('service'); var $result = $card.find('.wptag-validation-result'); var useTemplate = $card.find('input[name*="[use_template]"]:checked').val() === '1'; - var idValue = $card.find('input[type="text"]').first().val(); - var customCode = $card.find('textarea').val(); + var idValue = $card.find('input[type="text"]').first().val().trim(); + var customCode = $card.find('textarea').val().trim(); - $btn.prop('disabled', true).text(wptagAdmin.strings.validating); - $result.removeClass('valid invalid').addClass('loading').text(wptagAdmin.strings.validating); + if (useTemplate && !idValue) { + WPTagAdmin.showValidationResult($result, 'invalid', 'Please enter an ID value first'); + return; + } + + if (!useTemplate && !customCode) { + WPTagAdmin.showValidationResult($result, 'invalid', 'Please enter custom code first'); + return; + } + + $btn.addClass('wptag-button-loading').prop('disabled', true); + WPTagAdmin.showValidationResult($result, 'loading', wptagAdmin.strings.validating); $.ajax({ url: wptagAdmin.ajax_url, @@ -84,42 +160,54 @@ var WPTagAdmin = { }, success: function(response) { if (response.success) { - $result.removeClass('loading invalid').addClass('valid') - .text('✓ ' + response.data.message); + WPTagAdmin.showValidationResult($result, 'valid', '✓ ' + response.data.message); } else { - $result.removeClass('loading valid').addClass('invalid') - .text('✗ ' + response.data.message); + WPTagAdmin.showValidationResult($result, 'invalid', '✗ ' + response.data.message); } }, - error: function() { - $result.removeClass('loading valid').addClass('invalid') - .text('✗ Validation failed'); + error: function(xhr, status, error) { + console.error('Validation error:', error); + WPTagAdmin.showValidationResult($result, 'invalid', '✗ Validation failed. Please try again.'); }, complete: function() { - $btn.prop('disabled', false).text('Validate'); + $btn.removeClass('wptag-button-loading').prop('disabled', false); } }); }); $('input[type="text"], textarea').on('input', function() { - $(this).closest('.wptag-service-card').find('.wptag-validation-result').text(''); + $(this).closest('.wptag-service-card').find('.wptag-validation-result').hide(); + if (WPTagAdmin.changeTrackingEnabled && !WPTagAdmin.initializing) { + WPTagAdmin.formChanged = true; + } }); }, + showValidationResult: function($result, type, message) { + $result.removeClass('valid invalid loading') + .addClass(type) + .text(message) + .show(); + }, + handlePreview: function() { var $ = jQuery; - $('.wptag-preview-btn').on('click', function() { + + $('.wptag-preview-btn').on('click', function(e) { + e.preventDefault(); + var $btn = $(this); var $card = $btn.closest('.wptag-service-card'); var service = $card.data('service'); - var idValue = $card.find('input[type="text"]').first().val(); + var idValue = $card.find('input[type="text"]').first().val().trim(); - if (!idValue.trim()) { + if (!idValue) { alert('Please enter an ID value to preview'); + $card.find('input[type="text"]').first().focus(); return; } - $btn.prop('disabled', true).text(wptagAdmin.strings.loading); + $btn.addClass('wptag-button-loading').prop('disabled', true); $.ajax({ url: wptagAdmin.ajax_url, @@ -132,17 +220,20 @@ var WPTagAdmin = { }, success: function(response) { if (response.success) { - $('#wptag-preview-code').text(response.data.preview); - $('#wptag-preview-modal').show(); + var previewCode = response.data.preview; + $('#wptag-preview-code').text(previewCode); + $('#wptag-preview-modal').fadeIn(300); + $('body').addClass('modal-open'); } else { - alert('Error: ' + response.data.message); + WPTagAdmin.showNotice('error', 'Preview Error: ' + response.data.message); } }, - error: function() { - alert('Failed to generate preview'); + error: function(xhr, status, error) { + console.error('Preview error:', error); + WPTagAdmin.showNotice('error', 'Failed to generate preview. Please try again.'); }, complete: function() { - $btn.prop('disabled', false).text(wptagAdmin.strings.preview); + $btn.removeClass('wptag-button-loading').prop('disabled', false); } }); }); @@ -150,10 +241,12 @@ var WPTagAdmin = { handleExportImport: function() { var $ = jQuery; - $('#wptag-export-btn').on('click', function() { + + $('#wptag-export-btn').on('click', function(e) { + e.preventDefault(); + var $btn = $(this); - var originalText = $btn.text(); - $btn.prop('disabled', true).text(wptagAdmin.strings.loading); + $btn.addClass('wptag-button-loading').prop('disabled', true); $.ajax({ url: wptagAdmin.ajax_url, @@ -167,19 +260,21 @@ var WPTagAdmin = { WPTagAdmin.downloadFile(response.data.data, response.data.filename); WPTagAdmin.showNotice('success', wptagAdmin.strings.export_success); } else { - alert('Export failed: ' + response.data.message); + WPTagAdmin.showNotice('error', 'Export failed: ' + response.data.message); } }, - error: function() { - alert('Export failed'); + error: function(xhr, status, error) { + console.error('Export error:', error); + WPTagAdmin.showNotice('error', 'Export failed. Please try again.'); }, complete: function() { - $btn.prop('disabled', false).text(originalText); + $btn.removeClass('wptag-button-loading').prop('disabled', false); } }); }); - $('#wptag-import-btn').on('click', function() { + $('#wptag-import-btn').on('click', function(e) { + e.preventDefault(); $('#wptag-import-file').click(); }); @@ -187,7 +282,14 @@ var WPTagAdmin = { var file = this.files[0]; if (!file) return; + if (!file.name.endsWith('.json')) { + WPTagAdmin.showNotice('error', 'Please select a valid JSON file.'); + this.value = ''; + return; + } + if (!confirm(wptagAdmin.strings.confirm_import)) { + this.value = ''; return; } @@ -206,34 +308,43 @@ var WPTagAdmin = { success: function(response) { if (response.success) { WPTagAdmin.showNotice('success', wptagAdmin.strings.import_success); + WPTagAdmin.formChanged = false; + WPTagAdmin.initializing = true; setTimeout(function() { location.reload(); - }, 1000); + }, 1500); } else { - alert('Import failed: ' + response.data.message); + WPTagAdmin.showNotice('error', 'Import failed: ' + response.data.message); } }, - error: function() { - alert('Import failed'); + error: function(xhr, status, error) { + console.error('Import error:', error); + WPTagAdmin.showNotice('error', 'Import failed. Please try again.'); } }); }; - reader.readAsText(file); + reader.onerror = function() { + WPTagAdmin.showNotice('error', 'Failed to read the file.'); + }; + + reader.readAsText(file); this.value = ''; }); }, handleReset: function() { var $ = jQuery; - $('#wptag-reset-btn').on('click', function() { + + $('#wptag-reset-btn').on('click', function(e) { + e.preventDefault(); + if (!confirm(wptagAdmin.strings.confirm_reset)) { return; } var $btn = $(this); - var originalText = $btn.text(); - $btn.prop('disabled', true).text(wptagAdmin.strings.loading); + $btn.addClass('wptag-button-loading').prop('disabled', true); $.ajax({ url: wptagAdmin.ajax_url, @@ -245,18 +356,21 @@ var WPTagAdmin = { success: function(response) { if (response.success) { WPTagAdmin.showNotice('success', wptagAdmin.strings.reset_success); + WPTagAdmin.formChanged = false; + WPTagAdmin.initializing = true; setTimeout(function() { location.reload(); - }, 1000); + }, 1500); } else { - alert('Reset failed: ' + response.data.message); + WPTagAdmin.showNotice('error', 'Reset failed: ' + response.data.message); } }, - error: function() { - alert('Reset failed'); + error: function(xhr, status, error) { + console.error('Reset error:', error); + WPTagAdmin.showNotice('error', 'Reset failed. Please try again.'); }, complete: function() { - $btn.prop('disabled', false).text(originalText); + $btn.removeClass('wptag-button-loading').prop('disabled', false); } }); }); @@ -264,14 +378,26 @@ var WPTagAdmin = { handleServicesManagement: function() { var $ = jQuery; - $('#wptag-enable-all').on('click', function() { - $('input[name="enabled_services[]"]').prop('checked', true); - $('.wptag-service-item').removeClass('disabled'); + var self = this; + + $('#wptag-enable-all').on('click', function(e) { + e.preventDefault(); + self.changeTrackingEnabled = false; + $('input[name="enabled_services[]"]').prop('checked', true).trigger('change'); + setTimeout(function() { + self.changeTrackingEnabled = true; + self.formChanged = true; + }, 100); }); - $('#wptag-disable-all').on('click', function() { - $('input[name="enabled_services[]"]').prop('checked', false); - $('.wptag-service-item').addClass('disabled'); + $('#wptag-disable-all').on('click', function(e) { + e.preventDefault(); + self.changeTrackingEnabled = false; + $('input[name="enabled_services[]"]').prop('checked', false).trigger('change'); + setTimeout(function() { + self.changeTrackingEnabled = true; + self.formChanged = true; + }, 100); }); $('.wptag-service-item input[type="checkbox"]').on('change', function() { @@ -279,9 +405,13 @@ var WPTagAdmin = { var isChecked = $(this).is(':checked'); if (isChecked) { - $item.removeClass('disabled'); + $item.removeClass('disabled').addClass('enabled'); } else { - $item.addClass('disabled'); + $item.removeClass('enabled').addClass('disabled'); + } + + if (self.changeTrackingEnabled && !self.initializing) { + self.formChanged = true; } }); @@ -290,9 +420,10 @@ var WPTagAdmin = { handleModal: function() { var $ = jQuery; - $('.wptag-modal-close, #wptag-preview-modal').on('click', function(e) { + + $('.wptag-modal-close, .wptag-modal-backdrop').on('click', function(e) { if (e.target === this) { - $('#wptag-preview-modal').hide(); + WPTagAdmin.closeModal(); } }); @@ -302,39 +433,43 @@ var WPTagAdmin = { $(document).on('keydown', function(e) { if (e.keyCode === 27 && $('#wptag-preview-modal').is(':visible')) { - $('#wptag-preview-modal').hide(); + WPTagAdmin.closeModal(); } }); }, + closeModal: function() { + var $ = jQuery; + $('#wptag-preview-modal').fadeOut(300, function() { + $('body').removeClass('modal-open'); + }); + }, + handleFormSubmission: function() { var $ = jQuery; + var self = this; + $('.wptag-settings-form').on('submit', function(e) { var hasErrors = false; + var $form = $(this); - $('.wptag-service-card').each(function() { + $('.wptag-service-card.enabled').each(function() { var $card = $(this); - var isEnabled = $card.find('input[name*="[enabled]"]').is(':checked'); - - if (!isEnabled) { - return; - } - var useTemplate = $card.find('input[name*="[use_template]"]:checked').val() === '1'; if (useTemplate) { - var idInput = $card.find('input[type="text"]').first(); - if (idInput.val().trim() === '') { - alert('Please enter an ID for enabled services or disable them.'); - idInput.focus(); + var $idInput = $card.find('input[type="text"]').first(); + if ($idInput.val().trim() === '') { + WPTagAdmin.showNotice('error', 'Please enter an ID for all enabled services or disable them.'); + $idInput.focus(); hasErrors = true; return false; } } else { - var customCodeTextarea = $card.find('textarea'); - if (customCodeTextarea.val().trim() === '') { - alert('Please enter custom code for enabled services or disable them.'); - customCodeTextarea.focus(); + var $customCodeTextarea = $card.find('textarea'); + if ($customCodeTextarea.val().trim() === '') { + WPTagAdmin.showNotice('error', 'Please enter custom code for all enabled services or disable them.'); + $customCodeTextarea.focus(); hasErrors = true; return false; } @@ -346,51 +481,69 @@ var WPTagAdmin = { return false; } - $(this).find('input[type="submit"]').prop('disabled', true).val('Saving...'); + var $saveBtn = $form.find('#wptag-save-btn'); + $saveBtn.addClass('wptag-button-loading').prop('disabled', true).val('Saving...'); + self.formChanged = false; + }); + + $('#wptag-services-form').on('submit', function() { + var $saveBtn = $(this).find('input[type="submit"]'); + $saveBtn.addClass('wptag-button-loading').prop('disabled', true).val('Saving...'); + WPTagAdmin.formChanged = false; }); }, handleTabSwitching: function() { var $ = jQuery; + var self = this; + $('.nav-tab').on('click', function(e) { - var href = $(this).attr('href'); - if (href && href.indexOf('tab=') !== -1) { - var tab = href.split('tab=')[1]; - var currentUrl = window.location.href.split('?')[0]; - var newUrl = currentUrl + '?page=wptag-settings&tab=' + tab; - window.location.href = newUrl; + if (self.formChanged && !self.initializing) { + var confirmed = confirm('You have unsaved changes. Do you want to continue without saving?'); + if (!confirmed) { + e.preventDefault(); + return false; + } else { + self.formChanged = false; + } } }); }, handleAdvancedToggle: function() { var $ = jQuery; + $('.wptag-toggle-advanced').on('click', function(e) { e.preventDefault(); + var $btn = $(this); var $card = $btn.closest('.wptag-service-card'); var $advanced = $card.find('.wptag-advanced-settings'); var $icon = $btn.find('.dashicons'); if ($advanced.is(':visible')) { - $advanced.slideUp(); + $advanced.slideUp(300); $icon.removeClass('dashicons-arrow-up-alt2').addClass('dashicons-arrow-down-alt2'); - $btn.html('Advanced Settings'); + $btn.html('' + wptagAdmin.strings.advanced_settings); } else { - $advanced.slideDown(); + $advanced.slideDown(300); $icon.removeClass('dashicons-arrow-down-alt2').addClass('dashicons-arrow-up-alt2'); - $btn.html('Hide Advanced Settings'); + $btn.html('' + wptagAdmin.strings.hide_advanced); } }); }, handleCodeEditor: function() { var $ = jQuery; + $('.wptag-code-editor').each(function() { var $editor = $(this); $editor.on('input', function() { WPTagAdmin.updateEditorHeight(this); + if (WPTagAdmin.changeTrackingEnabled && !WPTagAdmin.initializing) { + WPTagAdmin.formChanged = true; + } }); $editor.on('keydown', function(e) { @@ -407,7 +560,9 @@ var WPTagAdmin = { WPTagAdmin.updateEditorHeight(this); }); - $('.wptag-format-code').on('click', function() { + $('.wptag-format-code').on('click', function(e) { + e.preventDefault(); + var $btn = $(this); var $editor = $btn.closest('.wptag-code-editor-wrapper').find('.wptag-code-editor'); var code = $editor.val(); @@ -417,25 +572,88 @@ var WPTagAdmin = { var formatted = WPTagAdmin.formatCode(code); $editor.val(formatted); WPTagAdmin.updateEditorHeight($editor[0]); + if (WPTagAdmin.changeTrackingEnabled && !WPTagAdmin.initializing) { + WPTagAdmin.formChanged = true; + } + WPTagAdmin.showNotice('success', 'Code formatted successfully.'); } catch (e) { console.log('Code formatting failed:', e); + WPTagAdmin.showNotice('error', 'Code formatting failed. Please check your code syntax.'); } } }); - $('.wptag-clear-code').on('click', function() { + $('.wptag-clear-code').on('click', function(e) { + e.preventDefault(); + if (confirm('Are you sure you want to clear the code?')) { var $btn = $(this); var $editor = $btn.closest('.wptag-code-editor-wrapper').find('.wptag-code-editor'); - $editor.val(''); + $editor.val('').focus(); WPTagAdmin.updateEditorHeight($editor[0]); + if (WPTagAdmin.changeTrackingEnabled && !WPTagAdmin.initializing) { + WPTagAdmin.formChanged = true; + } } }); }, + handleFormChangeTracking: function() { + var $ = jQuery; + var self = this; + + self.changeTrackingEnabled = true; + + $(document).on('input keyup', 'input[type="text"], textarea', function() { + if ($(this).closest('.wptag-admin').length > 0 && self.changeTrackingEnabled && !self.initializing) { + self.formChanged = true; + } + }); + + $(document).on('change', 'select, input[type="radio"], input[type="checkbox"]:not([name*="enabled_services"]):not([name*="[enabled]"]):not([name*="[use_template]"])', function() { + if ($(this).closest('.wptag-admin').length > 0 && self.changeTrackingEnabled && !self.initializing) { + self.formChanged = true; + } + }); + + window.addEventListener('beforeunload', function(e) { + if (self.formChanged && !self.initializing) { + e.preventDefault(); + e.returnValue = 'You have unsaved changes. Are you sure you want to leave?'; + return e.returnValue; + } + }); + }, + + initTooltips: function() { + var $ = jQuery; + + $('[title]').each(function() { + var $el = $(this); + var title = $el.attr('title'); + + $el.removeAttr('title').on('mouseenter', function() { + $('
' + title + '
') + .appendTo('body') + .fadeIn(200); + }).on('mouseleave', function() { + $('.wptag-tooltip').remove(); + }).on('mousemove', function(e) { + $('.wptag-tooltip').css({ + top: e.pageY + 10, + left: e.pageX + 10 + }); + }); + }); + }, + updateEditorHeight: function(editor) { + var $ = jQuery; + var $editor = $(editor); + editor.style.height = 'auto'; - editor.style.height = Math.max(editor.scrollHeight, 120) + 'px'; + var newHeight = Math.max(editor.scrollHeight, 120); + editor.style.height = newHeight + 'px'; }, formatCode: function(code) { @@ -444,11 +662,30 @@ var WPTagAdmin = { .replace(/>\n<') .replace(/^\s+|\s+$/g, '') .split('\n') - .map(function(line) { - return line.trim(); + .map(function(line, index, array) { + line = line.trim(); + if (line.length === 0) return ''; + + var indent = 0; + for (var i = 0; i < index; i++) { + var prevLine = array[i].trim(); + if (prevLine.match(/<[^\/][^>]*[^\/]>$/)) { + indent += 2; + } + if (prevLine.match(/<\/[^>]+>$/)) { + indent -= 2; + } + } + + if (line.match(/^<\/[^>]+>$/)) { + indent -= 2; + } + + indent = Math.max(0, indent); + return ' '.repeat(indent) + line; }) .filter(function(line) { - return line.length > 0; + return line.trim().length > 0; }) .join('\n'); } catch (e) { @@ -458,33 +695,54 @@ var WPTagAdmin = { }, downloadFile: function(data, filename) { - var blob = new Blob([data], { type: 'application/json' }); - var url = window.URL.createObjectURL(blob); - var a = document.createElement('a'); - a.href = url; - a.download = filename; - a.style.display = 'none'; - document.body.appendChild(a); - a.click(); - window.URL.revokeObjectURL(url); - document.body.removeChild(a); + try { + var blob = new Blob([data], { type: 'application/json' }); + + if (window.navigator && window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveOrOpenBlob(blob, filename); + return; + } + + var url = window.URL.createObjectURL(blob); + var a = document.createElement('a'); + a.href = url; + a.download = filename; + a.style.display = 'none'; + document.body.appendChild(a); + a.click(); + + setTimeout(function() { + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + }, 100); + } catch (e) { + console.error('Download failed:', e); + WPTagAdmin.showNotice('error', 'Download failed. Please try again.'); + } }, showNotice: function(type, message) { var $ = jQuery; - var $notice = $('

' + message + '

'); + + $('.wptag-admin .notice').remove(); + + var $notice = $('

' + message + '

'); $('.wptag-admin h1').after($notice); + $notice.find('.notice-dismiss').on('click', function() { + $notice.fadeOut(300, function() { + $(this).remove(); + }); + }); + setTimeout(function() { - $notice.fadeOut(function() { + $notice.fadeOut(300, function() { $(this).remove(); }); }, 5000); - $notice.find('.notice-dismiss').on('click', function() { - $notice.fadeOut(function() { - $(this).remove(); - }); - }); + $('html, body').animate({ + scrollTop: $('.wptag-admin').offset().top - 50 + }, 500); } }; \ No newline at end of file diff --git a/includes/class-admin.php b/includes/class-admin.php index 93d5d4f..55cd58b 100644 --- a/includes/class-admin.php +++ b/includes/class-admin.php @@ -28,6 +28,8 @@ class Admin { } private function init_hooks() { + add_filter('wptag_should_output_codes', '__return_false', 999); + add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_init', array($this, 'admin_init')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets')); @@ -120,7 +122,10 @@ class Admin { 'reset_success' => 'Settings reset successfully', 'confirm_reset' => 'Are you sure you want to reset all settings? This cannot be undone.', 'confirm_import' => 'This will overwrite your current settings. Continue?', - 'loading' => 'Loading...' + 'loading' => 'Loading...', + 'fill_required' => 'Please fill in required fields for enabled services.', + 'advanced_settings' => 'Advanced Settings', + 'hide_advanced' => 'Hide Advanced Settings' ) )); } @@ -130,7 +135,10 @@ class Admin { wp_die(__('You do not have sufficient permissions to access this page.')); } - $this->handle_form_submission(); + add_filter('wptag_should_output_codes', '__return_false', 999); + remove_action('wp_head', array($this->frontend ?? null, 'output_head_codes'), 1); + remove_action('wp_body_open', array($this->frontend ?? null, 'output_body_codes'), 1); + remove_action('wp_footer', array($this->frontend ?? null, 'output_footer_codes'), 1); $active_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'analytics'; $categories = $this->get_categories_with_services(); @@ -143,13 +151,25 @@ class Admin {
-

Manage your tracking codes and analytics services with ease.

+

Manage your tracking codes and analytics services with ease. Enable services in the Services Management tab, then configure them in their respective category tabs.

+ +

Debug Mode: Check your website's source code for WPTag debug comments if codes are not appearing.

+
current_user_can_manage_codes()): ?> - - - + + +
@@ -157,14 +177,18 @@ class Admin {