top = parseInt( $submenu.css( 'top' ), 10 );
if ( isNaN( top ) || top > -5 ) { // The submenu is visible.
if ( $adminmenu.data( 'wp-responsive' ) ) {
// The menu is in responsive mode, bail.
adjustSubmenu( $menuItem );
$adminmenu.find( 'li.opensub' ).removeClass( 'opensub' );
$menuItem.addClass( 'opensub' );
* Closes the submenu when no longer hovering the menu item.
if ( $adminmenu.data( 'wp-responsive' ) ) {
// The menu is in responsive mode, bail.
$( this ).removeClass( 'opensub' ).find( '.wp-submenu' ).css( 'margin-top', '' );
* Opens the submenu on when focused on the menu item.
* @param {Event} event The event object.
$adminmenu.on( 'focus.adminmenu', '.wp-submenu a', function( event ) {
if ( $adminmenu.data( 'wp-responsive' ) ) {
// The menu is in responsive mode, bail.
$( event.target ).closest( 'li.menu-top' ).addClass( 'opensub' );
* Closes the submenu on blur from the menu item.
* @param {Event} event The event object.
}).on( 'blur.adminmenu', '.wp-submenu a', function( event ) {
if ( $adminmenu.data( 'wp-responsive' ) ) {
$( event.target ).closest( 'li.menu-top' ).removeClass( 'opensub' );
* Adjusts the size for the submenu.
}).find( 'li.wp-has-submenu.wp-not-current-submenu' ).on( 'focusin.adminmenu', function() {
adjustSubmenu( $( this ) );
* The `.below-h2` class is here just for backward compatibility with plugins
* that are (incorrectly) using it. Do not use. Use `.inline` instead. See #34570.
* If '.wp-header-end' is found, append the notices after it otherwise
* after the first h1 or h2 heading found within the main content.
if ( ! $headerEnd.length ) {
$headerEnd = $( '.wrap h1, .wrap h2' ).first();
$( 'div.updated, div.error, div.notice' ).not( '.inline, .below-h2' ).insertAfter( $headerEnd );
* Makes notices dismissible.
function makeNoticesDismissible() {
$( '.notice.is-dismissible' ).each( function() {
$button = $( '<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>' );
if ( $el.find( '.notice-dismiss' ).length ) {
$button.find( '.screen-reader-text' ).text( __( 'Dismiss this notice.' ) );
$button.on( 'click.wp-dismiss-notice', function( event ) {
$el.fadeTo( 100, 0, function() {
$el.slideUp( 100, function() {
$document.on( 'wp-updates-notice-added wp-plugin-install-error wp-plugin-update-error wp-plugin-delete-error wp-theme-install-error wp-theme-delete-error', makeNoticesDismissible );
* This event needs to be delegated. Ticket #37973.
* @return {boolean} Returns whether a checkbox is checked or not.
$body.on( 'click', 'tbody > tr > .check-column :checkbox', function( event ) {
// Shift click to select a range of checkboxes.
if ( 'undefined' == event.shiftKey ) { return true; }
if ( !lastClicked ) { return true; }
checks = $( lastClicked ).closest( 'form' ).find( ':checkbox' ).filter( ':visible:enabled' );
first = checks.index( lastClicked );
last = checks.index( this );
checked = $(this).prop('checked');
if ( 0 < first && 0 < last && first != last ) {
sliced = ( last > first ) ? checks.slice( first, last ) : checks.slice( last, first );
sliced.prop( 'checked', function() {
if ( $(this).closest('tr').is(':visible') )
// Toggle the "Select all" checkboxes depending if the other ones are all checked or not.
var unchecked = $(this).closest('tbody').find(':checkbox').filter(':visible:enabled').not(':checked');
* Determines if all checkboxes are checked.
* @return {boolean} Returns true if there are no unchecked checkboxes.
$(this).closest('table').children('thead, tfoot').find(':checkbox').prop('checked', function() {
return ( 0 === unchecked.length );
* Controls all the toggles on bulk toggle change.
* When the bulk checkbox is changed, all the checkboxes in the tables are changed accordingly.
* When the shift-button is pressed while changing the bulk checkbox the checkboxes in the table are inverted.
* This event needs to be delegated. Ticket #37973.
* @param {Event} event The event object.
$body.on( 'click.wp-toggle-checkboxes', 'thead .check-column :checkbox, tfoot .check-column :checkbox', function( event ) {
$table = $this.closest( 'table' ),
controlChecked = $this.prop('checked'),
toggle = event.shiftKey || $this.data('wp-toggle');
$table.children( 'tbody' ).filter(':visible')
.children().children('.check-column').find(':checkbox')
* Updates the checked state on the checkbox in the table.
* @return {boolean} True checks the checkbox, False unchecks the checkbox.
.prop('checked', function() {
if ( $(this).is(':hidden,:disabled') ) {
return ! $(this).prop( 'checked' );
} else if ( controlChecked ) {
$table.children('thead, tfoot').filter(':visible')
.children().children('.check-column').find(':checkbox')
* Syncs the bulk checkboxes on the top and bottom of the table.
* @return {boolean} True checks the checkbox, False unchecks the checkbox.
.prop('checked', function() {
} else if ( controlChecked ) {
* Marries a secondary control to its primary control.
* @param {jQuery} topSelector The top selector element.
* @param {jQuery} topSubmit The top submit element.
* @param {jQuery} bottomSelector The bottom selector element.
* @param {jQuery} bottomSubmit The bottom submit element.
function marryControls( topSelector, topSubmit, bottomSelector, bottomSubmit ) {
* Updates the primary selector when the secondary selector is changed.
function updateTopSelector() {
topSelector.val($(this).val());
bottomSelector.on('change', updateTopSelector);
* Updates the secondary selector when the primary selector is changed.
function updateBottomSelector() {
bottomSelector.val($(this).val());
topSelector.on('change', updateBottomSelector);
* Triggers the primary submit when then secondary submit is clicked.
function triggerSubmitClick(e) {
topSubmit.trigger('click');
bottomSubmit.on('click', triggerSubmitClick);
// Marry the secondary "Bulk actions" controls to the primary controls:
marryControls( $('#bulk-action-selector-top'), $('#doaction'), $('#bulk-action-selector-bottom'), $('#doaction2') );
// Marry the secondary "Change role to" controls to the primary controls:
marryControls( $('#new_role'), $('#changeit'), $('#new_role2'), $('#changeit2') );
* Shows row actions on focus of its parent container element or any other elements contained within.
$( '#wpbody-content' ).on({
clearTimeout( transitionTimeout );
focusedRowActions = $( this ).find( '.row-actions' );
// transitionTimeout is necessary for Firefox, but Chrome won't remove the CSS class without a little help.
$( '.row-actions' ).not( this ).removeClass( 'visible' );
focusedRowActions.addClass( 'visible' );
// Tabbing between post title and .row-actions links needs a brief pause, otherwise
// the .row-actions div gets hidden in transit in some browsers (ahem, Firefox).
transitionTimeout = setTimeout( function() {
focusedRowActions.removeClass( 'visible' );
}, '.table-view-list .has-row-actions' );
// Toggle list table rows on small screens.
$( 'tbody' ).on( 'click', '.toggle-row', function() {
$( this ).closest( 'tr' ).toggleClass( 'is-expanded' );
$('#default-password-nag-no').on( 'click', function() {
setUserSetting('default_password_nag', 'hide');
$('div.default-password-nag').hide();
* Handles tab keypresses in theme and plugin editor textareas.
* @param {Event} e The event object.
$('#newcontent').on('keydown.wpevent_InsertTab', function(e) {
var el = e.target, selStart, selEnd, val, scroll, sel;
// After pressing escape key (keyCode: 27), the tab key should tab out of the textarea.
// When pressing Escape: Opera 12 and 27 blur form fields, IE 8 clears them.
$(el).data('tab-out', true);
// Only listen for plain tab key (keyCode: 9) without any modifiers.
if ( e.keyCode != 9 || e.ctrlKey || e.altKey || e.shiftKey )
// After tabbing out, reset it so next time the tab key can be used again.
if ( $(el).data('tab-out') ) {
$(el).data('tab-out', false);
selStart = el.selectionStart;
selEnd = el.selectionEnd;
// If any text is selected, replace the selection with a tab character.
if ( document.selection ) {
sel = document.selection.createRange();
} else if ( selStart >= 0 ) {
el.value = val.substring(0, selStart).concat('\t', val.substring(selEnd) );
el.selectionStart = el.selectionEnd = selStart + 1;
// Cancel the regular tab functionality, to prevent losing focus of the textarea.
// Reset page number variable for new filters/searches but not for bulk actions. See #17685.
if ( pageInput.length ) {
* Handles pagination variable when filtering the list table.
* Set the pagination argument to the first page when the post-filter form is submitted.
* This happens when pressing the 'filter' button on the list table page.
* The pagination argument should not be touched when the bulk action dropdowns are set to do anything.
* The form closest to the pageInput is the post-filter form.
pageInput.closest('form').on( 'submit', function() {
* action = bulk action dropdown at the top of the table
if ( $('select[name="action"]').val() == -1 && pageInput.val() == currentPage )
* Resets the bulk actions when the search button is clicked.
$('.search-box input[type="search"], .search-box input[type="submit"]').on( 'mousedown', function () {
$('select[name^="action"]').val('-1');
* Scrolls into view when focus.scroll-into-view is triggered.
* @param {Event} e The event object.
$('#contextual-help-link, #show-settings-link').on( 'focus.scroll-into-view', function(e){
if ( e.target.scrollIntoView )
e.target.scrollIntoView(false);
* Disables the submit upload buttons when no data is entered.
var button, input, form = $('form.wp-upload-form');
// Exit when no upload form is found.
button = form.find('input[type="submit"]');
input = form.find('input[type="file"]');
* Determines if any data is entered in any file upload input.
function toggleUploadButton() {
// When no inputs have a value, disable the upload buttons.
button.prop('disabled', '' === input.map( function() {
// Update the status initially.
// Update the status when any file input changes.
input.on('change', toggleUploadButton);
* Pins the menu while distraction-free writing is enabled.
* @param {Event} event Event data.
function pinMenu( event ) {
var windowPos = $window.scrollTop(),
resizing = ! event || event.type !== 'scroll';
if ( isIOS || $adminmenu.data( 'wp-responsive' ) ) {
* When the menu is higher than the window and smaller than the entire page.
* It should be adjusted to be able to see the entire menu.
* Otherwise it can be accessed normally.
if ( height.menu + height.adminbar < height.window ||
height.menu + height.adminbar + 20 > height.wpwrap ) {
// If the menu is higher than the window, compensate on scroll.
if ( height.menu + height.adminbar > height.window ) {
// Check for overscrolling, this happens when swiping up at the top of the document in modern browsers.
// Stick the menu to the top.
pinnedMenuBottom = false;
} else if ( windowPos + height.window > $document.height() - 1 ) {
// When overscrolling at the bottom, stick the menu to the bottom.
if ( ! pinnedMenuBottom ) {