wp/wp-admin/js/site-health.js
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     8 
     8 
     9 jQuery( document ).ready( function( $ ) {
     9 jQuery( document ).ready( function( $ ) {
    10 
    10 
    11 	var __ = wp.i18n.__,
    11 	var __ = wp.i18n.__,
    12 		_n = wp.i18n._n,
    12 		_n = wp.i18n._n,
    13 		sprintf = wp.i18n.sprintf;
    13 		sprintf = wp.i18n.sprintf,
    14 
    14 		data,
    15 	var data;
    15 		clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' ),
    16 	var clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' );
    16 		isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length,
    17 	var isDebugTab = $( '.health-check-body.health-check-debug-tab' ).length;
    17 		pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' ),
    18 	var pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' );
    18 		successTimeout;
    19 
    19 
    20 	// Debug information copy section.
    20 	// Debug information copy section.
    21 	clipboard.on( 'success', function( e ) {
    21 	clipboard.on( 'success', function( e ) {
    22 		var $wrapper = $( e.trigger ).closest( 'div' );
    22 		var triggerElement = $( e.trigger ),
    23 		$( '.success', $wrapper ).addClass( 'visible' );
    23 			successElement = $( '.success', triggerElement.closest( 'div' ) );
    24 
    24 
    25 		wp.a11y.speak( __( 'Site information has been added to your clipboard.' ) );
    25 		// Clear the selection and move focus back to the trigger.
       
    26 		e.clearSelection();
       
    27 		// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
       
    28 		triggerElement.focus();
       
    29 
       
    30 		// Show success visual feedback.
       
    31 		clearTimeout( successTimeout );
       
    32 		successElement.removeClass( 'hidden' );
       
    33 
       
    34 		// Hide success visual feedback after 3 seconds since last success.
       
    35 		successTimeout = setTimeout( function() {
       
    36 			successElement.addClass( 'hidden' );
       
    37 			// Remove the visually hidden textarea so that it isn't perceived by assistive technologies.
       
    38 			if ( clipboard.clipboardAction.fakeElem && clipboard.clipboardAction.removeFake ) {
       
    39 				clipboard.clipboardAction.removeFake();
       
    40 			}
       
    41 		}, 3000 );
       
    42 
       
    43 		// Handle success audible feedback.
       
    44 		wp.a11y.speak( __( 'Site information has been copied to your clipboard.' ) );
    26 	} );
    45 	} );
    27 
    46 
    28 	// Accordion handling in various areas.
    47 	// Accordion handling in various areas.
    29 	$( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
    48 	$( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
    30 		var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
    49 		var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
    46 		goodIssuesWrapper.toggleClass( 'hidden' );
    65 		goodIssuesWrapper.toggleClass( 'hidden' );
    47 		$( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
    66 		$( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
    48 	} );
    67 	} );
    49 
    68 
    50 	/**
    69 	/**
    51 	 * Append a new issue to the issue list.
    70 	 * Appends a new issue to the issue list.
    52 	 *
    71 	 *
    53 	 * @since 5.2.0
    72 	 * @since 5.2.0
    54 	 *
    73 	 *
    55 	 * @param {Object} issue The issue data.
    74 	 * @param {Object} issue The issue data.
    56 	 */
    75 	 */
    57 	function AppendIssue( issue ) {
    76 	function appendIssue( issue ) {
    58 		var template = wp.template( 'health-check-issue' ),
    77 		var template = wp.template( 'health-check-issue' ),
    59 			issueWrapper = $( '#health-check-issues-' + issue.status ),
    78 			issueWrapper = $( '#health-check-issues-' + issue.status ),
    60 			heading,
    79 			heading,
    61 			count;
    80 			count;
    62 
    81 		
    63 		SiteHealth.site_status.issues[ issue.status ]++;
    82 		SiteHealth.site_status.issues[ issue.status ]++;
    64 
    83 
    65 		count = SiteHealth.site_status.issues[ issue.status ];
    84 		count = SiteHealth.site_status.issues[ issue.status ];
    66 
    85 
    67 		if ( 'critical' === issue.status ) {
    86 		if ( 'critical' === issue.status ) {
    68 			heading = sprintf( _n( '%s Critical issue', '%s Critical issues', count ), '<span class="issue-count">' + count + '</span>' );
    87 			heading = sprintf(
       
    88 				_n( '%s critical issue', '%s critical issues', count ),
       
    89 				'<span class="issue-count">' + count + '</span>'
       
    90 			);
    69 		} else if ( 'recommended' === issue.status ) {
    91 		} else if ( 'recommended' === issue.status ) {
    70 			heading = sprintf( _n( '%s Recommended improvement', '%s Recommended improvements', count ), '<span class="issue-count">' + count + '</span>' );
    92 			heading = sprintf(
       
    93 				_n( '%s recommended improvement', '%s recommended improvements', count ),
       
    94 				'<span class="issue-count">' + count + '</span>'
       
    95 			);
    71 		} else if ( 'good' === issue.status ) {
    96 		} else if ( 'good' === issue.status ) {
    72 			heading = sprintf( _n( '%s Item with no issues detected', '%s Items with no issues detected', count ), '<span class="issue-count">' + count + '</span>' );
    97 			heading = sprintf(
       
    98 				_n( '%s item with no issues detected', '%s items with no issues detected', count ),
       
    99 				'<span class="issue-count">' + count + '</span>'
       
   100 			);
    73 		}
   101 		}
    74 
   102 
    75 		if ( heading ) {
   103 		if ( heading ) {
    76 			$( '.site-health-issue-count-title', issueWrapper ).html( heading );
   104 			$( '.site-health-issue-count-title', issueWrapper ).html( heading );
    77 		}
   105 		}
    78 
   106 
    79 		$( '.issues', '#health-check-issues-' + issue.status ).append( template( issue ) );
   107 		$( '.issues', '#health-check-issues-' + issue.status ).append( template( issue ) );
    80 	}
   108 	}
    81 
   109 
    82 	/**
   110 	/**
    83 	 * Update site health status indicator as asynchronous tests are run and returned.
   111 	 * Updates site health status indicator as asynchronous tests are run and returned.
    84 	 *
   112 	 *
    85 	 * @since 5.2.0
   113 	 * @since 5.2.0
    86 	 */
   114 	 */
    87 	function RecalculateProgression() {
   115 	function recalculateProgression() {
    88 		var r, c, pct;
   116 		var r, c, pct;
    89 		var $progress = $( '.site-health-progress' );
   117 		var $progress = $( '.site-health-progress' );
    90 		var $progressCount = $progress.find( '.site-health-progress-count' );
   118 		var $wrapper = $progress.closest( '.site-health-progress-wrapper' );
       
   119 		var $progressLabel = $( '.site-health-progress-label', $wrapper );
    91 		var $circle = $( '.site-health-progress svg #bar' );
   120 		var $circle = $( '.site-health-progress svg #bar' );
    92 		var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) + parseInt( SiteHealth.site_status.issues.recommended, 0 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
   121 		var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) +
    93 		var failedTests = parseInt( SiteHealth.site_status.issues.recommended, 0 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
   122 				parseInt( SiteHealth.site_status.issues.recommended, 0 ) +
       
   123 				( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
       
   124 		var failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) +
       
   125 				( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
    94 		var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
   126 		var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
    95 
   127 
    96 		if ( 0 === totalTests ) {
   128 		if ( 0 === totalTests ) {
    97 			$progress.addClass( 'hidden' );
   129 			$progress.addClass( 'hidden' );
    98 			return;
   130 			return;
    99 		}
   131 		}
   100 
   132 
   101 		$progress.removeClass( 'loading' );
   133 		$wrapper.removeClass( 'loading' );
   102 
   134 
   103 		r = $circle.attr( 'r' );
   135 		r = $circle.attr( 'r' );
   104 		c = Math.PI * ( r * 2 );
   136 		c = Math.PI * ( r * 2 );
   105 
   137 
   106 		if ( 0 > val ) {
   138 		if ( 0 > val ) {
   120 
   152 
   121 		if ( 1 > parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) {
   153 		if ( 1 > parseInt( SiteHealth.site_status.issues.recommended, 0 ) ) {
   122 			$( '#health-check-issues-recommended' ).addClass( 'hidden' );
   154 			$( '#health-check-issues-recommended' ).addClass( 'hidden' );
   123 		}
   155 		}
   124 
   156 
   125 		if ( 50 <= val ) {
   157 		if ( 80 <= val && 0 === parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
   126 			$circle.addClass( 'orange' ).removeClass( 'red' );
   158 			$wrapper.addClass( 'green' ).removeClass( 'orange' );
   127 		}
   159 
   128 
   160 			$progressLabel.text( __( 'Good' ) );
   129 		if ( 90 <= val ) {
   161 			wp.a11y.speak( __( 'All site health tests have finished running. Your site is looking good, and the results are now available on the page.' ) );
   130 			$circle.addClass( 'green' ).removeClass( 'orange' );
   162 		} else {
   131 		}
   163 			$wrapper.addClass( 'orange' ).removeClass( 'green' );
   132 
   164 
   133 		if ( 100 === val ) {
   165 			$progressLabel.text( __( 'Should be improved' ) );
   134 			$( '.site-status-all-clear' ).removeClass( 'hide' );
   166 			wp.a11y.speak( __( 'All site health tests have finished running. There are items that should be addressed, and the results are now available on the page.' ) );
   135 			$( '.site-status-has-issues' ).addClass( 'hide' );
   167 		}
   136 		}
       
   137 
       
   138 		$progressCount.text( val + '%' );
       
   139 
   168 
   140 		if ( ! isDebugTab ) {
   169 		if ( ! isDebugTab ) {
   141 			$.post(
   170 			$.post(
   142 				ajaxurl,
   171 				ajaxurl,
   143 				{
   172 				{
   145 					'_wpnonce': SiteHealth.nonce.site_status_result,
   174 					'_wpnonce': SiteHealth.nonce.site_status_result,
   146 					'counts': SiteHealth.site_status.issues
   175 					'counts': SiteHealth.site_status.issues
   147 				}
   176 				}
   148 			);
   177 			);
   149 
   178 
   150 			wp.a11y.speak( sprintf(
   179 			if ( 100 === val ) {
   151 				// translators: %s: The percentage score for the tests.
   180 				$( '.site-status-all-clear' ).removeClass( 'hide' );
   152 				__( 'All site health tests have finished running. Your site scored %s, and the results are now available on the page.' ),
   181 				$( '.site-status-has-issues' ).addClass( 'hide' );
   153 				val + '%'
   182 			}
   154 			) );
       
   155 		}
   183 		}
   156 	}
   184 	}
   157 
   185 
   158 	/**
   186 	/**
   159 	 * Queue the next asynchronous test when we're ready to run it.
   187 	 * Queues the next asynchronous test when we're ready to run it.
   160 	 *
   188 	 *
   161 	 * @since 5.2.0
   189 	 * @since 5.2.0
   162 	 */
   190 	 */
   163 	function maybeRunNextAsyncTest() {
   191 	function maybeRunNextAsyncTest() {
   164 		var doCalculation = true;
   192 		var doCalculation = true;
   180 
   208 
   181 				$.post(
   209 				$.post(
   182 					ajaxurl,
   210 					ajaxurl,
   183 					data,
   211 					data,
   184 					function( response ) {
   212 					function( response ) {
   185 						AppendIssue( response.data );
   213 						/** This filter is documented in wp-admin/includes/class-wp-site-health.php */
       
   214 						appendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
   186 						maybeRunNextAsyncTest();
   215 						maybeRunNextAsyncTest();
   187 					}
   216 					}
   188 				);
   217 				);
   189 
   218 
   190 				return false;
   219 				return false;
   191 			} );
   220 			} );
   192 		}
   221 		}
   193 
   222 
   194 		if ( doCalculation ) {
   223 		if ( doCalculation ) {
   195 			RecalculateProgression();
   224 			recalculateProgression();
   196 		}
   225 		}
   197 	}
   226 	}
   198 
   227 
   199 	if ( 'undefined' !== typeof SiteHealth && ! isDebugTab ) {
   228 	if ( 'undefined' !== typeof SiteHealth && ! isDebugTab ) {
   200 		if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
   229 		if ( 0 === SiteHealth.site_status.direct.length && 0 === SiteHealth.site_status.async.length ) {
   201 			RecalculateProgression();
   230 			recalculateProgression();
   202 		} else {
   231 		} else {
   203 			SiteHealth.site_status.issues = {
   232 			SiteHealth.site_status.issues = {
   204 				'good': 0,
   233 				'good': 0,
   205 				'recommended': 0,
   234 				'recommended': 0,
   206 				'critical': 0
   235 				'critical': 0
   207 			};
   236 			};
   208 		}
   237 		}
   209 
   238 
   210 		if ( 0 < SiteHealth.site_status.direct.length ) {
   239 		if ( 0 < SiteHealth.site_status.direct.length ) {
   211 			$.each( SiteHealth.site_status.direct, function() {
   240 			$.each( SiteHealth.site_status.direct, function() {
   212 				AppendIssue( this );
   241 				appendIssue( this );
   213 			} );
   242 			} );
   214 		}
   243 		}
   215 
   244 
   216 		if ( 0 < SiteHealth.site_status.async.length ) {
   245 		if ( 0 < SiteHealth.site_status.async.length ) {
   217 			data = {
   246 			data = {
   223 
   252 
   224 			$.post(
   253 			$.post(
   225 				ajaxurl,
   254 				ajaxurl,
   226 				data,
   255 				data,
   227 				function( response ) {
   256 				function( response ) {
   228 					AppendIssue( response.data );
   257 					appendIssue( response.data );
   229 					maybeRunNextAsyncTest();
   258 					maybeRunNextAsyncTest();
   230 				}
   259 				}
   231 			);
   260 			);
   232 		} else {
   261 		} else {
   233 			RecalculateProgression();
   262 			recalculateProgression();
   234 		}
   263 		}
   235 	}
   264 	}
   236 
   265 
   237 	function getDirectorySizes() {
   266 	function getDirectorySizes() {
   238 		var data = {
   267 		var data = {
   256 			updateDirSizes( response.data || {} );
   285 			updateDirSizes( response.data || {} );
   257 		} ).always( function() {
   286 		} ).always( function() {
   258 			var delay = ( new Date().getTime() ) - timestamp;
   287 			var delay = ( new Date().getTime() ) - timestamp;
   259 
   288 
   260 			$( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
   289 			$( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
   261 			RecalculateProgression();
   290 			recalculateProgression();
   262 
   291 
   263 			if ( delay > 3000  ) {
   292 			if ( delay > 3000  ) {
   264 				// We have announced that we're waiting.
   293 				/*
   265 				// Announce that we're ready after giving at least 3 seconds for the first announcement
   294 				 * We have announced that we're waiting.
   266 				// to be read out, or the two may collide.
   295 				 * Announce that we're ready after giving at least 3 seconds
       
   296 				 * for the first announcement to be read out, or the two may collide.
       
   297 				 */
   267 				if ( delay > 6000 ) {
   298 				if ( delay > 6000 ) {
   268 					delay = 0;
   299 					delay = 0;
   269 				} else {
   300 				} else {
   270 					delay = 6500 - delay;
   301 					delay = 6500 - delay;
   271 				}
   302 				}
   282 		} );
   313 		} );
   283 	}
   314 	}
   284 
   315 
   285 	function updateDirSizes( data ) {
   316 	function updateDirSizes( data ) {
   286 		var copyButton = $( 'button.button.copy-button' );
   317 		var copyButton = $( 'button.button.copy-button' );
   287 		var clipdoardText = copyButton.attr( 'data-clipboard-text' );
   318 		var clipboardText = copyButton.attr( 'data-clipboard-text' );
   288 
   319 
   289 		$.each( data, function( name, value ) {
   320 		$.each( data, function( name, value ) {
   290 			var text = value.debug || value.size;
   321 			var text = value.debug || value.size;
   291 
   322 
   292 			if ( typeof text !== 'undefined' ) {
   323 			if ( typeof text !== 'undefined' ) {
   293 				clipdoardText = clipdoardText.replace( name + ': loading...', name + ': ' + text );
   324 				clipboardText = clipboardText.replace( name + ': loading...', name + ': ' + text );
   294 			}
   325 			}
   295 		} );
   326 		} );
   296 
   327 
   297 		copyButton.attr( 'data-clipboard-text', clipdoardText );
   328 		copyButton.attr( 'data-clipboard-text', clipboardText );
   298 
   329 
   299 		pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
   330 		pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
   300 			var td = $( element );
   331 			var td = $( element );
   301 			var name = td.attr( 'class' );
   332 			var name = td.attr( 'class' );
   302 
   333 
   308 
   339 
   309 	if ( isDebugTab ) {
   340 	if ( isDebugTab ) {
   310 		if ( pathsSizesSection.length ) {
   341 		if ( pathsSizesSection.length ) {
   311 			getDirectorySizes();
   342 			getDirectorySizes();
   312 		} else {
   343 		} else {
   313 			RecalculateProgression();
   344 			recalculateProgression();
   314 		}
   345 		}
   315 	}
   346 	}
   316 } );
   347 } );