Make WordPress Core

Changeset 57713


Ignore:
Timestamp:
02/26/2024 08:16:09 PM (3 years ago)
Author:
jorbin
Message:

Site icon: Polish up Site Icon on the general settings screen.

This fixes a number of issues, chief among them:

  • Updates to the site title are reflected in the preview.
  • Improve alt text for preview
  • Make string describing site icon more succinct.
  • Add inline documentation to JavaScript

Props kebbet, jorbin, swissspidy, afercia, mukesh27, alexstine, jameskoster, andraganescu.
Fixes #54370.

Location:
trunk/src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/admin/site-icon.js

    r57602 r57713  
    1 (function($) {
    2         var frame;
    3 
    4         function calculateImageSelectOptions ( attachment ) {
    5                 var realWidth  = attachment.get( 'width' ),
     1/**
     2 * Handle the site icon setting in options-general.php.
     3 *
     4 * @since 6.5.0
     5 * @output wp-admin/js/site-icon.js
     6 */
     7
     8/* global jQuery, wp */
     9
     10( function ( $ ) {
     11        var $chooseButton = $( '#choose-from-library-button' ),
     12                $iconPreview = $( '#site-icon-preview' ),
     13                $browserIconPreview = $( '#browser-icon-preview' ),
     14                $appIconPreview = $( '#app-icon-preview' ),
     15                $hiddenDataField = $( '#site_icon_hidden_field' ),
     16                $removeButton = $( '#js-remove-site-icon' ),
     17                frame;
     18
     19        /**
     20         * Calculate image selection options based on the attachment dimensions.
     21         *
     22         * @since 6.5.0
     23         *
     24         * @param {Object} attachment The attachment object representing the image.
     25         * @return {Object} The image selection options.
     26         */
     27        function calculateImageSelectOptions( attachment ) {
     28                var realWidth = attachment.get( 'width' ),
    629                        realHeight = attachment.get( 'height' ),
    730                        xInit = 512,
    831                        yInit = 512,
    932                        ratio = xInit / yInit,
    10                         xImg  = xInit,
    11                         yImg  = yInit,
    12                         x1, y1, imgSelectOptions;
     33                        xImg = xInit,
     34                        yImg = yInit,
     35                        x1,
     36                        y1,
     37                        imgSelectOptions;
    1338
    1439                if ( realWidth / realHeight > ratio ) {
    … …  
    3661                        y1: y1,
    3762                        x2: xInit + x1,
    38                         y2: yInit + y1
     63                        y2: yInit + y1,
    3964                };
    4065
    … …  
    4267        }
    4368
    44         $( function() {
    45                 // Build the choose from library frame.
    46                 $( '#choose-from-library-link' ).on( 'click', function() {
    47                         var $el = $(this);
    48 
    49                         // Create the media frame.
    50                         frame = wp.media({
    51                                 button: {
    52                                         // Set the text of the button.
    53                                         text: $el.data('update'),
    54                                         // Don't close, we might need to crop.
    55                                         close: false
    56                                 },
    57                                 states: [
    58                                         new wp.media.controller.Library({
    59                                                 title: $el.data( 'choose' ),
    60                                                 library: wp.media.query({ type: 'image' }),
    61                                                 date: false,
    62                                                 suggestedWidth: $el.data( 'size' ),
    63                                                 suggestedHeight: $el.data( 'size' )
    64                                         }),
    65                                         new wp.media.controller.SiteIconCropper({
    66                                                 control: {
    67                                                         params: {
    68                                                                 width: $el.data( 'size' ),
    69                                                                 height: $el.data( 'size' )
    70                                                         }
     69        /**
     70         * Initializes the media frame for selecting or cropping an image.
     71         *
     72         * @since 6.5.0
     73         */
     74        $chooseButton.on( 'click', function () {
     75                var $el = $( this );
     76
     77                // Create the media frame.
     78                frame = wp.media( {
     79                        button: {
     80                                // Set the text of the button.
     81                                text: $el.data( 'update' ),
     82
     83                                // Don't close, we might need to crop.
     84                                close: false,
     85                        },
     86                        states: [
     87                                new wp.media.controller.Library( {
     88                                        title: $el.data( 'choose-text' ),
     89                                        library: wp.media.query( { type: 'image' } ),
     90                                        date: false,
     91                                        suggestedWidth: $el.data( 'size' ),
     92                                        suggestedHeight: $el.data( 'size' ),
     93                                } ),
     94                                new wp.media.controller.SiteIconCropper( {
     95                                        control: {
     96                                                params: {
     97                                                        width: $el.data( 'size' ),
     98                                                        height: $el.data( 'size' ),
    7199                                                },
    72                                                 imgSelectOptions: calculateImageSelectOptions
    73                                         })
    74                                 ]
    75                         });
    76 
    77                         frame.on( 'cropped', function( attachment) {
    78                                 $( '#site_icon_hidden_field' ).val(attachment.id);
    79                                 switchToUpdate(attachment.url);
     100                                        },
     101                                        imgSelectOptions: calculateImageSelectOptions,
     102                                } ),
     103                        ],
     104                } );
     105
     106                frame.on( 'cropped', function ( attachment ) {
     107                        $hiddenDataField.val( attachment.id );
     108                        switchToUpdate( attachment );
     109                        frame.close();
     110
     111                        // Start over with a frame that is so fresh and so clean clean.
     112                        frame = null;
     113                } );
     114
     115                // When an image is selected, run a callback.
     116                frame.on( 'select', function () {
     117                        // Grab the selected attachment.
     118                        var attachment = frame.state().get( 'selection' ).first();
     119
     120                        if (
     121                                attachment.attributes.height === $el.data( 'size' ) &&
     122                                $el.data( 'size' ) === attachment.attributes.width
     123                        ) {
     124                                switchToUpdate( attachment.attributes );
    80125                                frame.close();
    81                                 // Start over with a frame that is so fresh and so clean clean.
    82                                 frame = null;
    83                         });
    84 
    85                         // When an image is selected, run a callback.
    86                         frame.on( 'select', function() {
    87                                 // Grab the selected attachment.
    88                                 var attachment = frame.state().get('selection').first();
    89 
    90                                 if ( attachment.attributes.height === $el.data('size') && $el.data('size') === attachment.attributes.width ) {
    91                                         // Set the value of the hidden input to the attachment id.
    92                                         $( '#site_icon_hidden_field').val(attachment.id);
    93                                         switchToUpdate(attachment.attributes.url);
    94                                         frame.close();
    95                                 } else {
    96                                         frame.setState( 'cropper' );
    97                                 }
    98                         });
    99 
    100                         frame.open();
    101                 });
    102         });
    103 
    104         function switchToUpdate( url ){
    105                 // Set site-icon-img src to the url and remove the hidden class.
    106                 $( '#site-icon-preview').find('img').not('.browser-preview').each( function(i, img ){
    107                         $(img).attr('src', url );
    108                 });
    109                 $( '#site-icon-preview' ).removeClass( 'hidden' );
    110                 // Remove hidden class from remove.
    111                 $( '#js-remove-site-icon' ).removeClass( 'hidden' );
    112                 // If the button is not in the update state, swap the classes.
    113                 if( $( '#choose-from-library-link' ).attr( 'data-state' ) !== '1' ){
    114                         var classes = $( '#choose-from-library-link' ).attr( 'class' );
    115                         $( '#choose-from-library-link' ).attr( 'class', $( '#choose-from-library-link' ).attr('data-alt-classes') );
    116                         $( '#choose-from-library-link' ).attr( 'data-alt-classes', classes );
    117                         $( '#choose-from-library-link' ).attr( 'data-state', '1' );
     126
     127                                // Set the value of the hidden input to the attachment id.
     128                                $hiddenDataField.val( attachment.id );
     129                        } else {
     130                                frame.setState( 'cropper' );
     131                        }
     132                } );
     133
     134                frame.open();
     135        } );
     136
     137        /**
     138         * Update the UI when a site icon is selected.
     139         *
     140         * @since 6.5.0
     141         *
     142         * @param {array} attributes The attributes for the attachment.
     143         */
     144        function switchToUpdate( attributes ) {
     145                var i18nAppAlternativeString, i18nBrowserAlternativeString;
     146
     147                if ( attributes.alt ) {
     148                        i18nAppAlternativeString = wp.i18n.sprintf(
     149                                /* translators: %s: The selected image alt text. */
     150                                wp.i18n.__( 'App icon preview: Current image: %s' ),
     151                                attributes.alt
     152                        );
     153                        i18nBrowserAlternativeString = wp.i18n.sprintf(
     154                                /* translators: %s: The selected image alt text. */
     155                                wp.i18n.__( 'Browser icon preview: Current image: %s' ),
     156                                attributes.alt
     157                        );
     158                } else {
     159                        i18nAppAlternativeString = wp.i18n.sprintf(
     160                                /* translators: %s: The selected image filename. */
     161                                wp.i18n.__(
     162                                        'App icon preview: The current image has no alternative text. The file name is: %s'
     163                                ),
     164                                attributes.filename
     165                        );
     166                        i18nBrowserAlternativeString = wp.i18n.sprintf(
     167                                /* translators: %s: The selected image filename. */
     168                                wp.i18n.__(
     169                                        'Browser icon preview: The current image has no alternative text. The file name is: %s'
     170                                ),
     171                                attributes.filename
     172                        );
    118173                }
    119174
    120                 // swap the text of the button
    121                 $( '#choose-from-library-link' ).text( $( '#choose-from-library-link' ).attr( 'data-update-text' ) );
     175                // Set site-icon-img src and alternative text to app icon preview.
     176                $appIconPreview.attr( {
     177                        src: attributes.url,
     178                        alt: i18nAppAlternativeString,
     179                } );
     180
     181                // Set site-icon-img src and alternative text to browser preview.
     182                $browserIconPreview.attr( {
     183                        src: attributes.url,
     184                        alt: i18nBrowserAlternativeString,
     185                } );
     186
     187                // Remove hidden class from icon preview div and remove button.
     188                $iconPreview.removeClass( 'hidden' );
     189                $removeButton.removeClass( 'hidden' );
     190
     191                // If the choose button is not in the update state, swap the classes.
     192                if ( $chooseButton.attr( 'data-state' ) !== '1' ) {
     193                        $chooseButton.attr( {
     194                                class: $chooseButton.attr( 'data-alt-classes' ),
     195                                'data-alt-classes': $chooseButton.attr( 'class' ),
     196                                'data-state': '1',
     197                        } );
     198                }
     199
     200                // Swap the text of the choose button.
     201                $chooseButton.text( $chooseButton.attr( 'data-update-text' ) );
    122202        }
    123203
    124         $( '#js-remove-site-icon' ).on( 'click', function() {
    125                 $( '#site_icon_hidden_field' ).val( 'false' );
    126                 $( '#site-icon-preview' ).toggleClass( 'hidden' );
     204        /**
     205         * Handles the click event of the remove button.
     206         *
     207         * @since 6.5.0
     208         */
     209        $removeButton.on( 'click', function () {
     210                $hiddenDataField.val( 'false' );
    127211                $( this ).toggleClass( 'hidden' );
    128 
    129                 var classes = $( '#choose-from-library-link' ).attr( 'class' );
    130                 $( '#choose-from-library-link' ).attr( 'class', $( '#choose-from-library-link' ).attr( 'data-alt-classes' ) );
    131                 $( '#choose-from-library-link' ).attr( 'data-alt-classes', classes );
    132 
    133                 // Swap the text of the button.
    134                 $( '#choose-from-library-link' ).text( $( '#choose-from-library-link' ).attr( 'data-choose-text' ) );
    135                 // Set the state of the button so it can be changed on new icon.
    136                 $( '#choose-from-library-link' ).attr( 'data-state', '');
    137         });
    138 }(jQuery));
     212                $iconPreview.toggleClass( 'hidden' );
     213                $browserIconPreview.attr( {
     214                        src: '',
     215                        alt: '',
     216                } );
     217                $appIconPreview.attr( {
     218                        src: '',
     219                        alt: '',
     220                } );
     221
     222                /**
     223                 * Resets state to the button, for correct visual style and state.
     224                 * Updates the text of the button.
     225                 * Sets focus state to the button.
     226                 */
     227                $chooseButton
     228                        .attr( {
     229                                class: $chooseButton.attr( 'data-alt-classes' ),
     230                                'data-alt-classes': $chooseButton.attr( 'class' ),
     231                                'data-state': '',
     232                        } )
     233                        .text( $chooseButton.attr( 'data-choose-text' ) )
     234                        .trigger( 'focus' );
     235        } );
     236} )( jQuery );
  • trunk/src/wp-admin/css/forms.css

    r57602 r57713  
    790790}
    791791
    792 .button-add-site-icon{
     792.button-add-site-icon {
    793793        width: 100%;
    794794        cursor: pointer;
    … …  
    802802
    803803.button-add-site-icon:focus,
    804 .button-add-site-icon:hover{
    805         background: white;
    806 }
    807 
    808 .site-icon-section .favicon-preview{
     804.button-add-site-icon:hover {
     805        background: #fff;
     806}
     807
     808.site-icon-section .favicon-preview {
    809809        float: left;
    810810}
    811 .site-icon-section .app-icon-preview{
     811.site-icon-section .app-icon-preview {
    812812        float: left;
    813813        margin: 0 20px;
    814814}
    815815
    816 .site-icon-section .site-icon-preview img{
     816.site-icon-section .site-icon-preview img {
    817817        max-width: 100%;
    818818}
    819819
    820 .button-ad-site-icon:focus{
     820.button-add-site-icon:focus {
    821821        background-color: #fff;
    822822        border-color: #3582c4;
  • trunk/src/wp-admin/css/site-icon.css

    r57618 r57713  
    88        position: relative;
    99        max-width: 180px;
    10         float: left;
    1110}
    1211
  • trunk/src/wp-admin/includes/options.php

    r56176 r57713  
    3737        jQuery( function($) {
    3838                var $siteName = $( '#wp-admin-bar-site-name' ).children( 'a' ).first(),
     39                        $siteIconPreview = $('#site-icon-preview-site-title'),
    3940                        homeURL = ( <?php echo wp_json_encode( get_home_url() ); ?> || '' ).replace( /^(https?:\/\/)?(www\.)?/, '' );
    4041
    … …  
    4849
    4950                        $siteName.text( title );
     51                        $siteIconPreview.text( title );
    5052                });
    5153
  • trunk/src/wp-admin/options-general.php

    r57618 r57713  
    108108        $classes_for_upload_button = 'upload-button button-add-media button-add-site-icon';
    109109        $classes_for_update_button = 'button';
    110 
    111         $classes_for_avatar = 'avatar avatar-150';
     110        $classes_for_wrapper       = '';
     111
    112112        if ( has_site_icon() ) {
    113                 $classes_for_avatar          .= ' has-site-icon';
     113                $classes_for_wrapper         .= ' has-site-icon';
    114114                $classes_for_button           = $classes_for_update_button;
    115115                $classes_for_button_on_change = $classes_for_upload_button;
    116116        } else {
    117                 $classes_for_avatar          .= ' hidden';
     117                $classes_for_wrapper         .= ' hidden';
    118118                $classes_for_button           = $classes_for_upload_button;
    119119                $classes_for_button_on_change = $classes_for_update_button;
    120120        }
    121121
    122 
    123         ?>
    124         <div id="site-icon-preview" class="site-icon-preview wp-clearfix <?php echo esc_attr( $classes_for_avatar ); ?>">
     122        // Handle alt text for site icon on page load.
     123        $site_icon_id           = (int) get_option( 'site_icon' );
     124        $app_icon_alt_value     = '';
     125        $browser_icon_alt_value = '';
     126
     127        if ( $site_icon_id ) {
     128                $img_alt            = get_post_meta( $site_icon_id, '_wp_attachment_image_alt', true );
     129                $filename           = wp_basename( get_site_icon_url() );
     130                $app_icon_alt_value = sprintf(
     131                        /* translators: %s: The selected image filename. */
     132                        __( 'App icon preview: The current image has no alternative text. The file name is: %s' ),
     133                        $filename
     134                );
     135
     136                $browser_icon_alt_value = sprintf(
     137                        /* translators: %s: The selected image filename. */
     138                        __( 'Browser icon preview: The current image has no alternative text. The file name is: %s' ),
     139                        $filename
     140                );
     141
     142                if ( $img_alt ) {
     143                        $app_icon_alt_value = sprintf(
     144                                /* translators: %s: The selected image alt text. */
     145                                __( 'App icon preview: Current image: %s' ),
     146                                $img_alt
     147                        );
     148
     149                        $browser_icon_alt_value = sprintf(
     150                                /* translators: %s: The selected image alt text. */
     151                                __( 'Browser icon preview: Current image: %s' ),
     152                                $img_alt
     153                        );
     154                }
     155        }
     156        ?>
     157
     158
     159        <div id="site-icon-preview" class="site-icon-preview wp-clearfix settings-page-preview <?php echo esc_attr( $classes_for_wrapper ); ?>">
    125160                <div class="favicon-preview">
    126161                        <img src="<?php echo esc_url( admin_url( 'images/' . ( is_rtl() ? 'browser-rtl.png' : 'browser.png' ) ) ); ?>" class="browser-preview" width="182" alt="">
    127162                        <div class="favicon">
    128                                 <img src="<?php site_icon_url(); ?>" alt="<?php esc_attr_e( 'Preview as a browser icon' ); ?>">
     163                                <img id="browser-icon-preview" src="<?php site_icon_url(); ?>" alt="<?php echo esc_attr( $browser_icon_alt_value ); ?>">
    129164                        </div>
    130                         <span class="browser-title" aria-hidden="true"><?php echo get_bloginfo( 'name' ); ?></span>
     165                        <span id="site-icon-preview-site-title" class="browser-title" aria-hidden="true"><?php bloginfo( 'name' ); ?></span>
    131166                </div>
    132                 <img class="app-icon-preview" src="<?php site_icon_url(); ?>" alt="<?php esc_attr_e( 'Preview as an app icon' ); ?>">
     167                <img id="app-icon-preview" class="app-icon-preview" src="<?php site_icon_url(); ?>" alt="<?php echo esc_attr( $app_icon_alt_value ); ?>">
    133168        </div>
     169
    134170        <input type="hidden" name="site_icon" id="site_icon_hidden_field" value="<?php form_option( 'site_icon' ); ?>" />
    135171        <div class="action-buttons">
    136172                <button type="button"
    137                         id="choose-from-library-link"
     173                        id="choose-from-library-button"
    138174                        type="button"
    139175                        class="<?php echo esc_attr( $classes_for_button ); ?>"
    … …  
    162198
    163199        <p class="description">
    164                 <?php _e( 'Site Icons are what you see in browser tabs, bookmark bars, and within the WordPress mobile apps. Upload one here!' ); ?>
    165         </p>
    166         <p class="description">
    167200                <?php
    168201                        /* translators: %s: Site Icon size in pixels. */
    169                         printf( __( 'Site Icons should be square and at least %s pixels.' ), '<strong>512 &times; 512</strong>' );
     202                        printf( __( 'Site Icons are what you see in browser tabs, bookmark bars, and within the WordPress mobile apps. They should be square and at least %s pixels.' ), '<code>512 &times; 512</code>' );
    170203                ?>
    171204        </p>
  • trunk/src/wp-includes/script-loader.php

    r57699 r57713  
    850850        $scripts->add( 'wp-lists', "/wp-includes/js/wp-lists$suffix.js", array( 'wp-ajax-response', 'jquery-color' ), false, 1 );
    851851
    852         $scripts->add( 'site-icon', '/wp-admin/js/site-icon.js', array( 'jquery', 'jcrop' ), false, 1 );
     852        $scripts->add( 'site-icon', '/wp-admin/js/site-icon.js', array( 'jquery' ), false, 1 );
     853        $scripts->set_translations( 'site-icon' );
    853854
    854855        // WordPress no longer uses or bundles Prototype or script.aculo.us. These are now pulled from an external source.
Note: See TracChangeset for help on using the changeset viewer.