749 $availableStructureTags.on( 'click', function() { |
765 $availableStructureTags.on( 'click', function() { |
750 var permalinkStructureValue = $permalinkStructure.val(), |
766 var permalinkStructureValue = $permalinkStructure.val(), |
751 selectionStart = $permalinkStructure[ 0 ].selectionStart, |
767 selectionStart = $permalinkStructure[ 0 ].selectionStart, |
752 selectionEnd = $permalinkStructure[ 0 ].selectionEnd, |
768 selectionEnd = $permalinkStructure[ 0 ].selectionEnd, |
753 textToAppend = $( this ).text().trim(), |
769 textToAppend = $( this ).text().trim(), |
754 textToAnnounce = $( this ).attr( 'data-added' ), |
770 textToAnnounce, |
755 newSelectionStart; |
771 newSelectionStart; |
|
772 |
|
773 if ( $( this ).hasClass( 'active' ) ) { |
|
774 textToAnnounce = $( this ).attr( 'data-removed' ); |
|
775 } else { |
|
776 textToAnnounce = $( this ).attr( 'data-added' ); |
|
777 } |
756 |
778 |
757 // Remove structure tag if already part of the structure. |
779 // Remove structure tag if already part of the structure. |
758 if ( -1 !== permalinkStructureValue.indexOf( textToAppend ) ) { |
780 if ( -1 !== permalinkStructureValue.indexOf( textToAppend ) ) { |
759 permalinkStructureValue = permalinkStructureValue.replace( textToAppend + '/', '' ); |
781 permalinkStructureValue = permalinkStructureValue.replace( textToAppend + '/', '' ); |
760 |
782 |
879 |
901 |
880 $document.trigger( 'wp-collapse-menu', { state: menuState } ); |
902 $document.trigger( 'wp-collapse-menu', { state: menuState } ); |
881 }); |
903 }); |
882 |
904 |
883 /** |
905 /** |
884 * Handles the `aria-haspopup` attribute on the current menu item when it has a submenu. |
|
885 * |
|
886 * @since 4.4.0 |
|
887 * |
|
888 * @return {void} |
|
889 */ |
|
890 function currentMenuItemHasPopup() { |
|
891 var $current = $( 'a.wp-has-current-submenu' ); |
|
892 |
|
893 if ( 'folded' === menuState ) { |
|
894 // When folded or auto-folded and not responsive view, the current menu item does have a fly-out sub-menu. |
|
895 $current.attr( 'aria-haspopup', 'true' ); |
|
896 } else { |
|
897 // When expanded or in responsive view, reset aria-haspopup. |
|
898 $current.attr( 'aria-haspopup', 'false' ); |
|
899 } |
|
900 } |
|
901 |
|
902 $document.on( 'wp-menu-state-set wp-collapse-menu wp-responsive-activate wp-responsive-deactivate', currentMenuItemHasPopup ); |
|
903 |
|
904 /** |
|
905 * Ensures an admin submenu is within the visual viewport. |
906 * Ensures an admin submenu is within the visual viewport. |
906 * |
907 * |
907 * @since 4.1.0 |
908 * @since 4.1.0 |
908 * |
909 * |
909 * @param {jQuery} $menuItem The parent menu item containing the submenu. |
910 * @param {jQuery} $menuItem The parent menu item containing the submenu. |
1671 this.maybeDisableSortables = this.maybeDisableSortables.bind( this ); |
1672 this.maybeDisableSortables = this.maybeDisableSortables.bind( this ); |
1672 |
1673 |
1673 // Modify functionality based on custom activate/deactivate event. |
1674 // Modify functionality based on custom activate/deactivate event. |
1674 $document.on( 'wp-responsive-activate.wp-responsive', function() { |
1675 $document.on( 'wp-responsive-activate.wp-responsive', function() { |
1675 self.activate(); |
1676 self.activate(); |
|
1677 self.toggleAriaHasPopup( 'add' ); |
1676 }).on( 'wp-responsive-deactivate.wp-responsive', function() { |
1678 }).on( 'wp-responsive-deactivate.wp-responsive', function() { |
1677 self.deactivate(); |
1679 self.deactivate(); |
|
1680 self.toggleAriaHasPopup( 'remove' ); |
1678 }); |
1681 }); |
1679 |
1682 |
1680 $( '#wp-admin-bar-menu-toggle a' ).attr( 'aria-expanded', 'false' ); |
1683 $( '#wp-admin-bar-menu-toggle a' ).attr( 'aria-expanded', 'false' ); |
1681 |
1684 |
1682 // Toggle sidebar when toggle is clicked. |
1685 // Toggle sidebar when toggle is clicked. |
1693 } else { |
1696 } else { |
1694 $(this).find('a').attr( 'aria-expanded', 'false' ); |
1697 $(this).find('a').attr( 'aria-expanded', 'false' ); |
1695 } |
1698 } |
1696 } ); |
1699 } ); |
1697 |
1700 |
|
1701 // Close sidebar when target moves outside of toggle and sidebar. |
|
1702 $( document ).on( 'click', function( event ) { |
|
1703 if ( ! $wpwrap.hasClass( 'wp-responsive-open' ) || ! document.hasFocus() ) { |
|
1704 return; |
|
1705 } |
|
1706 |
|
1707 var focusIsInToggle = $.contains( $( '#wp-admin-bar-menu-toggle' )[0], event.target ); |
|
1708 var focusIsInSidebar = $.contains( $( '#adminmenuwrap' )[0], event.target ); |
|
1709 |
|
1710 if ( ! focusIsInToggle && ! focusIsInSidebar ) { |
|
1711 $( '#wp-admin-bar-menu-toggle' ).trigger( 'click.wp-responsive' ); |
|
1712 } |
|
1713 } ); |
|
1714 |
|
1715 // Close sidebar when a keypress completes outside of toggle and sidebar. |
|
1716 $( document ).on( 'keyup', function( event ) { |
|
1717 var toggleButton = $( '#wp-admin-bar-menu-toggle' )[0]; |
|
1718 if ( ! $wpwrap.hasClass( 'wp-responsive-open' ) ) { |
|
1719 return; |
|
1720 } |
|
1721 if ( 27 === event.keyCode ) { |
|
1722 $( toggleButton ).trigger( 'click.wp-responsive' ); |
|
1723 $( toggleButton ).find( 'a' ).trigger( 'focus' ); |
|
1724 } else { |
|
1725 if ( 9 === event.keyCode ) { |
|
1726 var sidebar = $( '#adminmenuwrap' )[0]; |
|
1727 var focusedElement = event.relatedTarget || document.activeElement; |
|
1728 // A brief delay is required to allow focus to switch to another element. |
|
1729 setTimeout( function() { |
|
1730 var focusIsInToggle = $.contains( toggleButton, focusedElement ); |
|
1731 var focusIsInSidebar = $.contains( sidebar, focusedElement ); |
|
1732 |
|
1733 if ( ! focusIsInToggle && ! focusIsInSidebar ) { |
|
1734 $( toggleButton ).trigger( 'click.wp-responsive' ); |
|
1735 } |
|
1736 }, 10 ); |
|
1737 } |
|
1738 } |
|
1739 }); |
|
1740 |
1698 // Add menu events. |
1741 // Add menu events. |
1699 $adminmenu.on( 'click.wp-responsive', 'li.wp-has-submenu > a', function( event ) { |
1742 $adminmenu.on( 'click.wp-responsive', 'li.wp-has-submenu > a', function( event ) { |
1700 if ( ! $adminmenu.data('wp-responsive') ) { |
1743 if ( ! $adminmenu.data('wp-responsive') ) { |
1701 return; |
1744 return; |
1702 } |
1745 } |
1703 |
1746 let state = ( 'false' === $( this ).attr( 'aria-expanded' ) ) ? 'true' : 'false'; |
1704 $( this ).parent( 'li' ).toggleClass( 'selected' ); |
1747 $( this ).parent( 'li' ).toggleClass( 'selected' ); |
|
1748 $( this ).attr( 'aria-expanded', state ); |
|
1749 $( this ).trigger( 'focus' ); |
1705 event.preventDefault(); |
1750 event.preventDefault(); |
1706 }); |
1751 }); |
1707 |
1752 |
1708 self.trigger(); |
1753 self.trigger(); |
1709 $document.on( 'wp-window-resized.wp-responsive', this.trigger.bind( this ) ); |
1754 $document.on( 'wp-window-resized.wp-responsive', this.trigger.bind( this ) ); |
1770 deactivate: function() { |
1815 deactivate: function() { |
1771 setPinMenu(); |
1816 setPinMenu(); |
1772 $adminmenu.removeData('wp-responsive'); |
1817 $adminmenu.removeData('wp-responsive'); |
1773 |
1818 |
1774 this.maybeDisableSortables(); |
1819 this.maybeDisableSortables(); |
|
1820 }, |
|
1821 |
|
1822 /** |
|
1823 * Toggles the aria-haspopup attribute for the responsive admin menu. |
|
1824 * |
|
1825 * The aria-haspopup attribute is only necessary for the responsive menu. |
|
1826 * See ticket https://core.trac.wordpress.org/ticket/43095 |
|
1827 * |
|
1828 * @since 6.6.0 |
|
1829 * |
|
1830 * @param {string} action Whether to add or remove the aria-haspopup attribute. |
|
1831 * |
|
1832 * @return {void} |
|
1833 */ |
|
1834 toggleAriaHasPopup: function( action ) { |
|
1835 var elements = $adminmenu.find( '[data-ariahaspopup]' ); |
|
1836 |
|
1837 if ( action === 'add' ) { |
|
1838 elements.each( function() { |
|
1839 $( this ).attr( 'aria-haspopup', 'menu' ).attr( 'aria-expanded', 'false' ); |
|
1840 } ); |
|
1841 |
|
1842 return; |
|
1843 } |
|
1844 |
|
1845 elements.each( function() { |
|
1846 $( this ).removeAttr( 'aria-haspopup' ).removeAttr( 'aria-expanded' ); |
|
1847 } ); |
1775 }, |
1848 }, |
1776 |
1849 |
1777 /** |
1850 /** |
1778 * Sets the responsiveness and enables the overlay based on the viewport width. |
1851 * Sets the responsiveness and enables the overlay based on the viewport width. |
1779 * |
1852 * |
2075 document.getElementsByTagName( 'head' )[0].appendChild( msViewportStyle ); |
2147 document.getElementsByTagName( 'head' )[0].appendChild( msViewportStyle ); |
2076 } |
2148 } |
2077 })(); |
2149 })(); |
2078 |
2150 |
2079 }( jQuery, window )); |
2151 }( jQuery, window )); |
|
2152 |
|
2153 /** |
|
2154 * Freeze animated plugin icons when reduced motion is enabled. |
|
2155 * |
|
2156 * When the user has enabled the 'prefers-reduced-motion' setting, this module |
|
2157 * stops animations for all GIFs on the page with the class 'plugin-icon' or |
|
2158 * plugin icon images in the update plugins table. |
|
2159 * |
|
2160 * @since 6.4.0 |
|
2161 */ |
|
2162 (function() { |
|
2163 // Private variables and methods. |
|
2164 var priv = {}, |
|
2165 pub = {}, |
|
2166 mediaQuery; |
|
2167 |
|
2168 // Initialize pauseAll to false; it will be set to true if reduced motion is preferred. |
|
2169 priv.pauseAll = false; |
|
2170 if ( window.matchMedia ) { |
|
2171 mediaQuery = window.matchMedia( '(prefers-reduced-motion: reduce)' ); |
|
2172 if ( ! mediaQuery || mediaQuery.matches ) { |
|
2173 priv.pauseAll = true; |
|
2174 } |
|
2175 } |
|
2176 |
|
2177 // Method to replace animated GIFs with a static frame. |
|
2178 priv.freezeAnimatedPluginIcons = function( img ) { |
|
2179 var coverImage = function() { |
|
2180 var width = img.width; |
|
2181 var height = img.height; |
|
2182 var canvas = document.createElement( 'canvas' ); |
|
2183 |
|
2184 // Set canvas dimensions. |
|
2185 canvas.width = width; |
|
2186 canvas.height = height; |
|
2187 |
|
2188 // Copy classes from the image to the canvas. |
|
2189 canvas.className = img.className; |
|
2190 |
|
2191 // Check if the image is inside a specific table. |
|
2192 var isInsideUpdateTable = img.closest( '#update-plugins-table' ); |
|
2193 |
|
2194 if ( isInsideUpdateTable ) { |
|
2195 // Transfer computed styles from image to canvas. |
|
2196 var computedStyles = window.getComputedStyle( img ), |
|
2197 i, max; |
|
2198 for ( i = 0, max = computedStyles.length; i < max; i++ ) { |
|
2199 var propName = computedStyles[ i ]; |
|
2200 var propValue = computedStyles.getPropertyValue( propName ); |
|
2201 canvas.style[ propName ] = propValue; |
|
2202 } |
|
2203 } |
|
2204 |
|
2205 // Draw the image onto the canvas. |
|
2206 canvas.getContext( '2d' ).drawImage( img, 0, 0, width, height ); |
|
2207 |
|
2208 // Set accessibility attributes on canvas. |
|
2209 canvas.setAttribute( 'aria-hidden', 'true' ); |
|
2210 canvas.setAttribute( 'role', 'presentation' ); |
|
2211 |
|
2212 // Insert canvas before the image and set the image to be near-invisible. |
|
2213 var parent = img.parentNode; |
|
2214 parent.insertBefore( canvas, img ); |
|
2215 img.style.opacity = 0.01; |
|
2216 img.style.width = '0px'; |
|
2217 img.style.height = '0px'; |
|
2218 }; |
|
2219 |
|
2220 // If the image is already loaded, apply the coverImage function. |
|
2221 if ( img.complete ) { |
|
2222 coverImage(); |
|
2223 } else { |
|
2224 // Otherwise, wait for the image to load. |
|
2225 img.addEventListener( 'load', coverImage, true ); |
|
2226 } |
|
2227 }; |
|
2228 |
|
2229 // Public method to freeze all relevant GIFs on the page. |
|
2230 pub.freezeAll = function() { |
|
2231 var images = document.querySelectorAll( '.plugin-icon, #update-plugins-table img' ); |
|
2232 for ( var x = 0; x < images.length; x++ ) { |
|
2233 if ( /\.gif(?:\?|$)/i.test( images[ x ].src ) ) { |
|
2234 priv.freezeAnimatedPluginIcons( images[ x ] ); |
|
2235 } |
|
2236 } |
|
2237 }; |
|
2238 |
|
2239 // Only run the freezeAll method if the user prefers reduced motion. |
|
2240 if ( true === priv.pauseAll ) { |
|
2241 pub.freezeAll(); |
|
2242 } |
|
2243 |
|
2244 // Listen for jQuery AJAX events. |
|
2245 ( function( $ ) { |
|
2246 if ( window.pagenow === 'plugin-install' ) { |
|
2247 // Only listen for ajaxComplete if this is the plugin-install.php page. |
|
2248 $( document ).ajaxComplete( function( event, xhr, settings ) { |
|
2249 |
|
2250 // Check if this is the 'search-install-plugins' request. |
|
2251 if ( settings.data && typeof settings.data === 'string' && settings.data.includes( 'action=search-install-plugins' ) ) { |
|
2252 // Recheck if the user prefers reduced motion. |
|
2253 if ( window.matchMedia ) { |
|
2254 var mediaQuery = window.matchMedia( '(prefers-reduced-motion: reduce)' ); |
|
2255 if ( mediaQuery.matches ) { |
|
2256 pub.freezeAll(); |
|
2257 } |
|
2258 } else { |
|
2259 // Fallback for browsers that don't support matchMedia. |
|
2260 if ( true === priv.pauseAll ) { |
|
2261 pub.freezeAll(); |
|
2262 } |
|
2263 } |
|
2264 } |
|
2265 } ); |
|
2266 } |
|
2267 } )( jQuery ); |
|
2268 |
|
2269 // Expose public methods. |
|
2270 return pub; |
|
2271 })(); |