diff --git a/src/class-tiny-dashboard.php b/src/class-tiny-dashboard.php new file mode 100644 index 00000000..196f3339 --- /dev/null +++ b/src/class-tiny-dashboard.php @@ -0,0 +1,177 @@ +settings = $settings; + $this->background_optimizer = $background_optimizer; + } + + public function ajax_init() { + add_action( + 'wp_ajax_tiny_dashboard_widget', + array( $this, 'ajax_dashboard_widget' ) + ); + } + + public function admin_init() { + if ( current_user_can( 'upload_files' ) ) { + add_action( + 'wp_dashboard_setup', + array( $this, 'add_dashboard_widget' ) + ); + } + } + + public function add_dashboard_widget() { + wp_enqueue_style( + self::NAME . '_dashboard_widget', + plugins_url( '/css/dashboard-widget.css', __FILE__ ), + array(), + Tiny_Plugin::version() + ); + + wp_enqueue_script( + self::NAME . '_dashboard_widget', + plugins_url( '/js/dashboard-widget.js', __FILE__ ), + array(), + Tiny_Plugin::version(), + true + ); + + wp_add_dashboard_widget( + $this->get_prefixed_name( 'dashboard_widget' ), + esc_html__( 'TinyPNG - JPEG, PNG & WebP image compression', 'tiny-compress-images' ), + array( $this, 'add_widget_view' ) + ); + } + + /** + * The statistics scan the whole library, so the dashboard shows a spinner + * and the widget JS fetches the real content from ajax_dashboard_widget(). + */ + public function add_widget_view() { + include __DIR__ . '/views/dashboard-widget-loading.php'; + } + + public function ajax_dashboard_widget() { + if ( ! check_ajax_referer( 'tiny-dashboard-widget', '_nonce', false ) || + ! current_user_can( 'upload_files' ) ) { + status_header( 403 ); + wp_die( -1, 403 ); + } + + $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); + $widget = $this->get_widget_data( $stats ); + include __DIR__ . '/views/dashboard-widget.php'; + wp_die(); + } + + /** + * Logic for the view + * + * @param array $optimization_stats See Tiny_Bulk_Optimization::get_optimization_statistics(). + * @return array + */ + public function get_widget_data( $optimization_stats ) { + $images_total = max( 0, intval( $optimization_stats['uploaded-images'] ) ); + $images_remaining = min( + $images_total, + count( $optimization_stats['available-for-optimization'] ) + ); + $images_optimized = $images_total - $images_remaining; + $bytes_saved = $optimization_stats['unoptimized-library-size'] + - $optimization_stats['optimized-library-size']; + + $percentage = $images_total > 0 + ? intval( floor( $images_optimized / $images_total * 100 ) ) + : 0; + + $estimated_credit_use = intval( $optimization_stats['estimated_credit_use'] ); + + // Only free accounts have a limited number of credits, including + // free accounts that bought a credit bundle. + $remaining_credits = $this->settings->get_remaining_credits(); + $has_limited_credits = $this->settings->is_on_free_plan() && + is_numeric( $remaining_credits ); + $remaining_credits = $has_limited_credits ? intval( $remaining_credits ) : null; + + // How many of the remaining images the credits still cover. + $images_affordable = 0; + if ( $has_limited_credits && $images_remaining > 0 && $estimated_credit_use > 0 ) { + $images_affordable = intval( + floor( $remaining_credits / ( $estimated_credit_use / $images_remaining ) ) + ); + } + + $seconds_left = null; + if ( ! $this->settings->has_api_key() ) { + $state = 'not_connected'; + } elseif ( $this->settings->refresh_api_key_pending() ) { + $state = 'pending'; + } elseif ( 0 === $images_total ) { + $state = 'empty'; + } elseif ( $this->background_optimizer->is_running() ) { + $state = 'compressing'; + + $seconds_left = intval( + round( $estimated_credit_use / Tiny_Background_Optimize::WORKERS ) + ); + } elseif ( 0 === $images_remaining ) { + $state = 'done'; + } elseif ( 0 === $remaining_credits ) { + $state = 'out_of_credits'; + } elseif ( $has_limited_credits && $estimated_credit_use > $remaining_credits ) { + $state = 'credits_short'; + } else { + $state = 'ready'; + } + + return array( + 'state' => $state, + 'images_optimized' => $images_optimized, + 'images_total' => $images_total, + 'images_remaining' => $images_remaining, + 'images_affordable' => $images_affordable, + 'bytes_saved' => max( 0, intval( $bytes_saved ) ), + 'percentage' => $percentage, + 'estimated_credit_use' => $estimated_credit_use, + 'remaining_credits' => $remaining_credits, + 'seconds_left' => $seconds_left, + 'email_address' => $this->settings->get_email_address(), + 'auto_compress' => $this->settings->auto_compress_enabled(), + ); + } +} diff --git a/src/class-tiny-plugin.php b/src/class-tiny-plugin.php index 80e006ad..4a00d97b 100644 --- a/src/class-tiny-plugin.php +++ b/src/class-tiny-plugin.php @@ -48,6 +48,7 @@ public function __construct() { $this->settings = new Tiny_Settings(); new Tiny_Conversion( $this->settings ); $this->background_optimizer = new Tiny_Background_Optimize( $this->settings ); + new Tiny_Dashboard( $this->settings, $this->background_optimizer ); } public function set_compressor( $compressor ) { @@ -125,11 +126,6 @@ public function ajax_init() { $this->get_method( 'ajax_bulk_queue_optimize_next' ) ); - add_action( - 'wp_ajax_tiny_get_optimization_statistics', - $this->get_method( 'ajax_optimization_statistics' ) - ); - add_action( 'wp_ajax_tiny_get_compression_status', $this->get_method( 'ajax_compression_status' ) @@ -178,11 +174,6 @@ public function ajax_init() { } public function admin_init() { - add_action( - 'wp_dashboard_setup', - $this->get_method( 'add_dashboard_widget' ) - ); - add_action( 'admin_enqueue_scripts', $this->get_method( 'enqueue_scripts' ) @@ -803,15 +794,6 @@ public function ajax_bulk_queue_cancel() { wp_send_json_success(); } - public function ajax_optimization_statistics() { - if ( check_ajax_referer( 'tiny-compress', '_nonce', false ) && - current_user_can( 'upload_files' ) ) { - $stats = Tiny_Bulk_Optimization::get_optimization_statistics( $this->settings ); - echo json_encode( $stats ); - } - exit(); - } - public function ajax_compression_status() { $response = $this->validate_ajax_attachment_request(); @@ -952,61 +934,13 @@ public function render_bulk_optimization_page() { $email_address = $this->settings->get_email_address(); $bulk_running = $this->background_optimizer->is_running(); - include __DIR__ . '/views/bulk-optimization.php'; - } - - public function add_dashboard_widget() { - wp_enqueue_style( - self::NAME . '_chart', - plugins_url( '/css/optimization-chart.css', __FILE__ ), - array(), - self::version() - ); - - wp_enqueue_style( - self::NAME . '_dashboard_widget', - plugins_url( '/css/dashboard-widget.css', __FILE__ ), - array(), - self::version() - ); - - wp_register_script( - self::NAME . '_dashboard_widget', - plugins_url( '/js/dashboard-widget.js', __FILE__ ), - array(), - self::version(), - true + /* The dashboard widget links here with a nonce to start right away. */ + $start_on_load = isset( $_GET['start'], $_GET['_wpnonce'] ) && wp_verify_nonce( + sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), + 'tiny-bulk-start' ); - /* - This might be deduplicated with the admin script localization, but - the order of including scripts is sometimes different. So in that - case we need to make sure that the order of inclusion is correct. */ - wp_localize_script( - self::NAME . '_dashboard_widget', - 'tinyCompressDashboard', - array( - 'nonce' => wp_create_nonce( 'tiny-compress' ), - ) - ); - - wp_enqueue_script( self::NAME . '_dashboard_widget' ); - - $widget_title = esc_html__( - 'TinyPNG Image Optimization – Image Compression JPEG & PNG | Convert to WebP & AVIF', - 'tiny-compress-images' - ); - - wp_add_dashboard_widget( - $this->get_prefixed_name( 'dashboard_widget' ), - $widget_title, - $this->get_method( 'add_widget_view' ) - ); - } - - public function add_widget_view() { - $admin_colors = self::retrieve_admin_colors(); - include __DIR__ . '/views/dashboard-widget.php'; + include __DIR__ . '/views/bulk-optimization.php'; } private static function retrieve_admin_colors() { diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 8f442ea5..045e38e7 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -224,6 +224,10 @@ protected function get_api_key() { } } + public function has_api_key() { + return (bool) $this->get_api_key(); + } + protected function get_api_key_pending() { if ( defined( 'TINY_API_KEY' ) ) { return false; @@ -236,6 +240,24 @@ protected function clear_api_key_pending() { delete_option( self::get_prefixed_name( 'api_key_pending' ) ); } + /** + * Whether the API key still waits for its activation link to be opened. + * Asks the API only while the key is pending, and clears the flag once + * the key works. + * + * @return bool + */ + public function refresh_api_key_pending() { + if ( ! $this->get_api_key_pending() ) { + return false; + } + if ( $this->compressor->get_status()->ok ) { + $this->clear_api_key_pending(); + return false; + } + return true; + } + protected static function get_intermediate_size( $size ) { /* Inspired by @@ -846,18 +868,18 @@ public function render_account_status() { include __DIR__ . '/views/account-status-create-simple.php'; } } else { - $status = $this->compressor->get_status(); - $status->pending = false; - if ( $status->ok ) { - if ( $this->get_api_key_pending() ) { - $this->clear_api_key_pending(); - } - } elseif ( $this->get_api_key_pending() ) { - $status->ok = true; - $status->pending = true; - $status->message = ( - 'An email has been sent to activate your account' - ); + if ( $this->refresh_api_key_pending() ) { + $status = (object) array( + 'ok' => true, + 'pending' => true, + 'message' => __( + 'An email has been sent to activate your account', + 'tiny-compress-images' + ), + ); + } else { + $status = $this->compressor->get_status(); + $status->pending = false; } include __DIR__ . '/views/account-status-connected.php'; } diff --git a/src/css/dashboard-widget.css b/src/css/dashboard-widget.css index bf4b9a80..02248212 100644 --- a/src/css/dashboard-widget.css +++ b/src/css/dashboard-widget.css @@ -1,129 +1,315 @@ -div.tiny_dashboard_widget div.inside { - min-height: 200px; +#tinypng_dashboard_widget .inside { margin: 0; - padding-bottom: 0; + padding: 0; +} + +.tiny-widget-loading { + padding: 24px 12px; +} + +.tiny-widget-loading .spinner { + float: none; + margin: 0; +} + +.tiny-widget { + container-type: inline-size; overflow: hidden; + color: #12141d; + font-size: 14px; + line-height: 20px; } -div.tiny_dashboard_widget div.inside div.spinner { - position: absolute; - visibility: visible; - z-index: 10; - top: 30%; - left: 50%; - margin-left: -12px; +.tiny-widget [hidden] { + display: none; } -div.tiny_dashboard_widget div.inside div.sky { - position: absolute; - left: 0; - top: 0; - height: 100%; - width: 100%; - opacity: 0.3; - background: linear-gradient(180deg, #c6dde4 0%, #fefeff 100%); - /* ie6-9 */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#33C6DDE4', endColorstr='#33FEFEFF',GradientType=0 ); +.tiny-widget p { + margin: 0; + color: #5b5b67; +} + +.tiny-widget-main, +.tiny-widget-credits { + display: flex; + flex-direction: column; + gap: 8px; + padding: 24px 12px; + animation: tiny-widget-slide-from-left 0.25s ease-out; +} + +.tiny-widget-credits { + animation-name: tiny-widget-slide-from-right; +} + +@keyframes tiny-widget-slide-from-left { + from { + opacity: 0; + transform: translateX(-24px); + } +} + +@keyframes tiny-widget-slide-from-right { + from { + opacity: 0; + transform: translateX(24px); + } +} + +@media (prefers-reduced-motion: reduce) { + .tiny-widget-main, + .tiny-widget-credits { + animation: none; + } +} + +.tiny-widget-top { + display: flex; + align-items: flex-start; + gap: 16px; +} + +.tiny-widget-content { + display: flex; + flex: 1; + flex-direction: column; + align-items: flex-start; + gap: 4px; + min-width: 0; +} + +.tiny-widget-panda { + flex-shrink: 0; +} + +.tiny-widget-badge { + padding: 2px 10px; + border-radius: 9999px; + font-size: 13px; + font-weight: 600; + margin-bottom: 8px; +} + +.tiny-widget-badge-red { + background: #fef2f2; + color: #dc2626; +} + +.tiny-widget-badge-amber { + background: #fef3c7; + color: #b45309; +} + +.tiny-widget-badge-green { + background: #e8faf0; + color: #00b075; +} + +.tiny-widget-hero { + font-size: 36px; + line-height: 40px; + font-weight: 600; + letter-spacing: -0.36px; +} + +.tiny-widget-hero span { + display: block; + color: #5b5b67; + font-size: 16px; + line-height: 24px; + font-weight: 400; + letter-spacing: 0; } -div.tiny_dashboard_widget div.inside div.cloud { - position: absolute; - right: 0; - top: 0; - height: 240px; - width: 298px; - background-image: url("../images/cloud.png"); - background-size: cover; +#tinypng_dashboard_widget .tiny-widget-heading { + margin: 0; + padding: 0; + font-size: 20px; + line-height: 28px; + font-weight: 600; +} + +.tiny-widget-below { + display: flex; + flex-direction: column; + gap: 12px; +} + +.tiny-widget-library { + display: flex; + flex-direction: column; + gap: 8px; } -div.tiny_dashboard_widget div.inside div.grass { - position: absolute; - right: 0; - bottom: 0; - height: 24px; - width: 536px; - background-image: url("../images/grass.png"); - background-size: cover; +.tiny-widget-bar { + height: 10px; + overflow: hidden; + border-radius: 9999px; + background: #d4d4db; } -div.tiny_dashboard_widget div.inside div.panda { - position: absolute; - bottom: 0; - background-repeat: no-repeat; - -webkit-background-size: 100%; - background-size: cover; - background-position: bottom; +.tiny-widget-bar-fill { + height: 100%; + border-radius: 9999px; + background: #06d28b; } -div.tiny_dashboard_widget.full-optimized div.inside div.panda { - right: 10%; - width: 305px; - height: 105.5px; - margin-right: 0; - background-image: url("../images/panda-laying.png"); +.tiny-widget-legend { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 6px 16px; + color: #5b5b67; } -div.tiny_dashboard_widget.half-optimized div.inside div.panda { - right: -230px; - width: 255px; - height: 203px; - margin-right: 45%; - background-image: url("../images/panda-eating.png"); +.tiny-widget-legend span { + display: inline-flex; + align-items: center; + gap: 6px; } -div.tiny_dashboard_widget.not-optimized div.inside div.panda, -div.tiny_dashboard_widget.no-images-uploaded div.inside div.panda { - right: -196px; - width: 241px; - height: 203px; - margin-right: 45%; - background-image: url("../images/panda-waiting.png"); +.tiny-widget-legend strong { + color: #12141d; + font-weight: 600; } -div.tiny_dashboard_widget.no-images-uploaded div.inside div.no-images, -div.tiny_dashboard_widget.not-optimized div.inside div.not-optimized, -div.tiny_dashboard_widget.half-optimized div.inside div.half-optimized, -div.tiny_dashboard_widget.full-optimized div.inside div.full-optimized { - display: block !important; - position: relative; - z-index: 1; +.tiny-widget-swatch { + width: 10px; + height: 10px; + border-radius: 2px; + background: #06d28b; } -div.tiny_dashboard_widget div.inside div#optimization-chart { - margin-top: 12px; - margin-bottom: 40px; - min-width: 160px; +.tiny-widget-swatch-todo { + background: #d4d4db; } -div.tiny_dashboard_widget.full-optimized div.inside.mobile div#optimization-chart { - width: 100%; - margin-top: -5px; - margin-bottom: 95px; +.tiny-widget-actions { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px; } -.ie8 div.tiny_dashboard_widget div.inside div.panda { +.tiny-widget .button-large { + min-height: 44px; + padding: 0 20px; + line-height: 42px; + font-weight: 600; +} + +.tiny-widget-link { + align-self: flex-start; + padding: 0; + border: 0; background: none; + color: var(--wp-admin-theme-color, #2271b1); + font-size: 14px; + line-height: 20px; + cursor: pointer; } -.ie8 div.tiny_dashboard_widget div.inside div.grass { - width: 100%; - background-image: url("../images/grass-ie8.png"); - background-repeat: no-repeat; - background-position: bottom; +.tiny-widget-link:hover, +.tiny-widget-link:focus { + text-decoration: underline; } -.ie8 div.tiny_dashboard_widget div.inside div#optimization-chart { - display: none; +#tinypng_dashboard_widget .tiny-widget-credits-heading { + margin: 0; + padding: 0; + font-size: 16px; + line-height: 24px; + font-weight: 600; +} + +.tiny-widget-offer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.tiny-widget-offer + .tiny-widget-offer { + padding-top: 16px; + border-top: 1px solid #ededf1; +} + +.tiny-widget-offer-text { + display: flex; + flex-direction: column; + gap: 2px; +} + +.tiny-widget-offer-text strong { + font-weight: 500; } -.ie8 div.tiny_dashboard_widget.no-images-uploaded div.inside div#ie8-compressed, -.ie8 div.tiny_dashboard_widget.not-optimized div.inside div#ie8-compressed, -.ie8 div.tiny_dashboard_widget.half-optimized div.inside div#ie8-compressed, -.ie8 div.tiny_dashboard_widget.full-optimized div.inside div#ie8-compressed { - display: block !important; - position: relative; - z-index: 1; +.tiny-widget-offer-text span { + color: #5b5b67; +} + +.tiny-widget-offer .button { + flex-shrink: 0; +} + +.tiny-widget-footer { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 8px 16px; + padding: 12px; + border-top: 1px solid #ededf1; + background: #f8f8fa; +} + +.tiny-widget-footer nav { + display: flex; + gap: 16px; + font-weight: 600; +} + +.tiny-widget-footer a { + text-decoration: none; +} + +.tiny-widget-credits-line { + font-weight: 500; +} + +.tiny-widget-credits-line-warning { + color: #b45309; + font-weight: 600; +} + +.tiny-widget-credits-line-error { + color: #dc2626; + font-weight: 600; +} + +@container (max-width: 420px) { + .tiny-widget-panda { + width: 80px; + height: 80px; + } + + .tiny-widget-actions .button:not(:only-child) { + width: 100%; + text-align: center; + } + + .tiny-widget-offer { + flex-direction: column; + align-items: stretch; + } + + .tiny-widget-offer .button { + text-align: center; + } } -#tinypng_dashboard_widget > button.handlediv { - margin-top: 0; +@container (max-width: 340px) { + .tiny-widget-panda { + display: none; + } } diff --git a/src/images/cloud.png b/src/images/cloud.png deleted file mode 100755 index ae57e01f..00000000 Binary files a/src/images/cloud.png and /dev/null differ diff --git a/src/images/grass-ie8.png b/src/images/grass-ie8.png deleted file mode 100644 index 3ac19f9a..00000000 Binary files a/src/images/grass-ie8.png and /dev/null differ diff --git a/src/images/grass.png b/src/images/grass.png deleted file mode 100755 index 71e7b9a8..00000000 Binary files a/src/images/grass.png and /dev/null differ diff --git a/src/images/panda-eating.png b/src/images/panda-eating.png deleted file mode 100755 index 6579fcb7..00000000 Binary files a/src/images/panda-eating.png and /dev/null differ diff --git a/src/images/panda-laying.png b/src/images/panda-laying.png deleted file mode 100755 index 8f341deb..00000000 Binary files a/src/images/panda-laying.png and /dev/null differ diff --git a/src/images/panda-waiting.png b/src/images/panda-waiting.png deleted file mode 100755 index f6ac18af..00000000 Binary files a/src/images/panda-waiting.png and /dev/null differ diff --git a/src/images/widget/panda-astronaut.png b/src/images/widget/panda-astronaut.png new file mode 100644 index 00000000..02c5f81e Binary files /dev/null and b/src/images/widget/panda-astronaut.png differ diff --git a/src/images/widget/panda-coffee.png b/src/images/widget/panda-coffee.png new file mode 100644 index 00000000..3197512d Binary files /dev/null and b/src/images/widget/panda-coffee.png differ diff --git a/src/images/widget/panda-duck.png b/src/images/widget/panda-duck.png new file mode 100644 index 00000000..0fa09a53 Binary files /dev/null and b/src/images/widget/panda-duck.png differ diff --git a/src/images/widget/panda-juggle.png b/src/images/widget/panda-juggle.png new file mode 100644 index 00000000..3d850bfe Binary files /dev/null and b/src/images/widget/panda-juggle.png differ diff --git a/src/images/widget/panda-rocket.png b/src/images/widget/panda-rocket.png new file mode 100644 index 00000000..76da09d2 Binary files /dev/null and b/src/images/widget/panda-rocket.png differ diff --git a/src/images/widget/panda-skate.png b/src/images/widget/panda-skate.png new file mode 100644 index 00000000..f2917005 Binary files /dev/null and b/src/images/widget/panda-skate.png differ diff --git a/src/images/widget/panda-unbox.png b/src/images/widget/panda-unbox.png new file mode 100644 index 00000000..25cfdb7a Binary files /dev/null and b/src/images/widget/panda-unbox.png differ diff --git a/src/js/bulk-optimization.js b/src/js/bulk-optimization.js index 264d3915..5da2a34e 100644 --- a/src/js/bulk-optimization.js +++ b/src/js/bulk-optimization.js @@ -188,12 +188,34 @@ }); } - function prepareBulkOptimization(items, running) { + function prepareBulkOptimization(items, running, startOnLoad) { window.allBulkOptimizationItems = items; updateProgressBar(0); if (running) { startBulkOptimization(items, true); } + startFromUrl(items, running, startOnLoad); + } + + // The dashboard widget opens this page with &start=1 and a nonce, which the + // server checks. Start right away, then drop both from the URL so a reload + // does not start again. + function startFromUrl(items, running, startOnLoad) { + const url = new URL(location.href); + if (url.searchParams.has('start')) { + url.searchParams.delete('start'); + url.searchParams.delete('_wpnonce'); + history.replaceState(null, '', url); + } + if (!startOnLoad || running) { + return; + } + + const start = document.getElementById('id-start'); + if (start && start.offsetParent !== null) { + jQuery('#hide-warning').trigger('click'); + startBulkOptimization(items); + } } function startBulkOptimization(items, running) { diff --git a/src/js/dashboard-widget.js b/src/js/dashboard-widget.js index 0bd39aa1..4e49b183 100644 --- a/src/js/dashboard-widget.js +++ b/src/js/dashboard-widget.js @@ -1,125 +1,40 @@ -(function() { - function generateDashboardWidget(element) { - element = jQuery(element); - var container = element.find('.inside'); - jQuery('.chart').addClass('hidden'); - // Adding a class to the widget element so that classes are only used in the stylesheet - jQuery('#tinypng_dashboard_widget').addClass('tiny_dashboard_widget'); - attachHandlers(container); - retrieveStats(container); +(function () { + const container = document.querySelector('#tinypng_dashboard_widget .inside'); + if (!container) { + return; } - function retrieveStats(container) { - jQuery.ajax({ - url: ajaxurl, - type: 'POST', - data: { - _nonce: tinyCompressDashboard.nonce, - action: 'tiny_get_optimization_statistics', - id: '#tinypng_dashboard_widget' - }, - success: function(data) { - if (data === 0) { - container.append('
An error occured.
'); - } else { - renderWidget(data); - } - }, - error: function() { - container.append('An error occured.
'); + // The statistics scan the whole library, so the server renders the widget + // after the page has loaded and all state rules stay in PHP. + async function load() { + const loading = container.querySelector('.tiny-widget-loading'); + try { + const response = await fetch(window.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + body: new URLSearchParams({ action: 'tiny_dashboard_widget', _nonce: loading.dataset.nonce }), + }); + if (!response.ok) { + throw new Error(response.statusText); } - }); - } - - function attachHandlers(container) { - setContainerClass(container); - jQuery(window).resize(function(){ - setContainerClass(container); - }); - jQuery('#tinypng_dashboard_widget .hndle').click(function() { - jQuery(this).siblings('.inside').removeClass('mobile'); - }); - } - - function setContainerClass(container) { - if (jQuery(container).width() < 400) { - jQuery(container).addClass('mobile'); - } else if (jQuery(container).width() < 490 && jQuery(container).width() >= 400) { - jQuery(container).addClass('tablet'); - jQuery(container).removeClass('mobile'); - } else if (jQuery(container).width() >= 490) { - jQuery(container).removeClass('tablet').removeClass('mobile'); - } - } - - function renderWidget(data) { - var stats = jQuery.parseJSON(data); - if (stats !== null) { - var savings = stats['display-percentage']; - var libraryOptimized = optimizedPercentage(stats); - renderContent(libraryOptimized, stats, savings); - renderChart(savings); - jQuery('#optimization-chart').show(); - } - jQuery('#widget-spinner').attr('class', 'hidden'); - } - - function renderPercentage(percentage) { - jQuery('#savings-percentage').find('span').html(percentage); - } - - function renderContent(percentage, stats, savingsPercentage) { - renderPercentage(savingsPercentage); - if ( 0 === stats['uploaded-images'] + stats['available-unoptimized-sizes'] ) { - jQuery('#tinypng_dashboard_widget').addClass('no-images-uploaded'); - } else if ( percentage === 0 ) { - jQuery('#tinypng_dashboard_widget').addClass('not-optimized'); - } else if ( percentage === 100 ) { - jQuery('#tinypng_dashboard_widget').addClass('full-optimized'); - } else { - jQuery('#uploaded-images').html( stats['uploaded-images'] ); - jQuery('#unoptimized-sizes').html( stats['available-unoptimized-sizes'] ); - jQuery('#tinypng_dashboard_widget').addClass('half-optimized'); + container.innerHTML = await response.text(); + } catch (error) { + loading.querySelector('.spinner').remove(); + loading.querySelector('p').hidden = false; } - jQuery('#ie8-compressed').find('span').html(savingsPercentage); - } - - function chartOptions(percentage) { - var chart = {}; - chart.size = 160; - chart.radius = chart.size / 2 * 0.9; - chart['main-radius'] = chart.radius * 0.88; - chart['circle-size'] = 2 * Math.PI * chart['main-radius']; - chart['dash-array-size'] = percentage / 100 * chart['circle-size']; - return chart; } - function optimizedPercentage(stats) { - if ( 0 !== stats['unoptimized-library-size'] ) { - return Math.round((stats['optimized-image-sizes'] / (stats['optimized-image-sizes'] + stats['available-unoptimized-sizes']) * 100), 0); - } else { - return 0; + // Get more credits is a second view in the same HTML. Nothing is stored, so + // a reload shows the main view again. + container.addEventListener('click', function (event) { + const action = event.target.closest('[data-tiny-action]'); + if (!action) { + return; } - } - - function renderChart(savingsPercentage) { - var chart = chartOptions(savingsPercentage); - jQuery('#optimization-chart svg circle.main').css('stroke-dasharray', chart['dash-array-size'] + ' ' + chart['circle-size']); - var style = - ' @keyframes shwoosh {' + - ' from { stroke-dasharray: 0 ' + chart['circle-size'] + '}' + - ' to { stroke-dasharray:' + chart['dash-array-size'] + ' ' + chart['circle-size'] + '}}'; + const showCredits = action.dataset.tinyAction === 'more-credits'; + container.querySelector('.tiny-widget-main').hidden = showCredits; + container.querySelector('.tiny-widget-credits').hidden = !showCredits; + }); - // JQuery bug where you cannot append to style tag https://bugs.jquery.com/ticket/9832 - try { - jQuery('#tinypng_dashboard_widget .inside style').append(style); - } catch(err) { - - } - } - - // Check if widget is loaded - if (jQuery('#tinypng_dashboard_widget').length) { - generateDashboardWidget('#tinypng_dashboard_widget'); - } -}).call(); + load(); +})(); diff --git a/src/views/bulk-optimization.php b/src/views/bulk-optimization.php index 3ba98ec4..025dc298 100644 --- a/src/views/bulk-optimization.php +++ b/src/views/bulk-optimization.php @@ -327,7 +327,7 @@ ?>