balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

common.js (53929B)


      1 /**
      2  * @output wp-admin/js/common.js
      3  */
      4 
      5 /* global setUserSetting, ajaxurl, alert, confirm, pagenow */
      6 /* global columns, screenMeta */
      7 
      8 /**
      9  *  Adds common WordPress functionality to the window.
     10  *
     11  *  @param {jQuery} $        jQuery object.
     12  *  @param {Object} window   The window object.
     13  *  @param {mixed} undefined Unused.
     14  */
     15 ( function( $, window, undefined ) {
     16 	var $document = $( document ),
     17 		$window = $( window ),
     18 		$body = $( document.body ),
     19 		__ = wp.i18n.__,
     20 		sprintf = wp.i18n.sprintf;
     21 
     22 /**
     23  * Throws an error for a deprecated property.
     24  *
     25  * @since 5.5.1
     26  *
     27  * @param {string} propName    The property that was used.
     28  * @param {string} version     The version of WordPress that deprecated the property.
     29  * @param {string} replacement The property that should have been used.
     30  */
     31 function deprecatedProperty( propName, version, replacement ) {
     32 	var message;
     33 
     34 	if ( 'undefined' !== typeof replacement ) {
     35 		message = sprintf(
     36 			/* translators: 1: Deprecated property name, 2: Version number, 3: Alternative property name. */
     37 			__( '%1$s is deprecated since version %2$s! Use %3$s instead.' ),
     38 			propName,
     39 			version,
     40 			replacement
     41 		);
     42 	} else {
     43 		message = sprintf(
     44 			/* translators: 1: Deprecated property name, 2: Version number. */
     45 			__( '%1$s is deprecated since version %2$s with no alternative available.' ),
     46 			propName,
     47 			version
     48 		);
     49 	}
     50 
     51 	window.console.warn( message );
     52 }
     53 
     54 /**
     55  * Deprecate all properties on an object.
     56  *
     57  * @since 5.5.1
     58  * @since 5.6.0 Added the `version` parameter.
     59  *
     60  * @param {string} name       The name of the object, i.e. commonL10n.
     61  * @param {object} l10nObject The object to deprecate the properties on.
     62  * @param {string} version    The version of WordPress that deprecated the property.
     63  *
     64  * @return {object} The object with all its properties deprecated.
     65  */
     66 function deprecateL10nObject( name, l10nObject, version ) {
     67 	var deprecatedObject = {};
     68 
     69 	Object.keys( l10nObject ).forEach( function( key ) {
     70 		var prop = l10nObject[ key ];
     71 		var propName = name + '.' + key;
     72 
     73 		if ( 'object' === typeof prop ) {
     74 			Object.defineProperty( deprecatedObject, key, { get: function() {
     75 				deprecatedProperty( propName, version, prop.alternative );
     76 				return prop.func();
     77 			} } );
     78 		} else {
     79 			Object.defineProperty( deprecatedObject, key, { get: function() {
     80 				deprecatedProperty( propName, version, 'wp.i18n' );
     81 				return prop;
     82 			} } );
     83 		}
     84 	} );
     85 
     86 	return deprecatedObject;
     87 }
     88 
     89 window.wp.deprecateL10nObject = deprecateL10nObject;
     90 
     91 /**
     92  * Removed in 5.5.0, needed for back-compatibility.
     93  *
     94  * @since 2.6.0
     95  * @deprecated 5.5.0
     96  */
     97 window.commonL10n = window.commonL10n || {
     98 	warnDelete: '',
     99 	dismiss: '',
    100 	collapseMenu: '',
    101 	expandMenu: ''
    102 };
    103 
    104 window.commonL10n = deprecateL10nObject( 'commonL10n', window.commonL10n, '5.5.0' );
    105 
    106 /**
    107  * Removed in 5.5.0, needed for back-compatibility.
    108  *
    109  * @since 3.3.0
    110  * @deprecated 5.5.0
    111  */
    112 window.wpPointerL10n = window.wpPointerL10n || {
    113 	dismiss: ''
    114 };
    115 
    116 window.wpPointerL10n = deprecateL10nObject( 'wpPointerL10n', window.wpPointerL10n, '5.5.0' );
    117 
    118 /**
    119  * Removed in 5.5.0, needed for back-compatibility.
    120  *
    121  * @since 4.3.0
    122  * @deprecated 5.5.0
    123  */
    124 window.userProfileL10n = window.userProfileL10n || {
    125 	warn: '',
    126 	warnWeak: '',
    127 	show: '',
    128 	hide: '',
    129 	cancel: '',
    130 	ariaShow: '',
    131 	ariaHide: ''
    132 };
    133 
    134 window.userProfileL10n = deprecateL10nObject( 'userProfileL10n', window.userProfileL10n, '5.5.0' );
    135 
    136 /**
    137  * Removed in 5.5.0, needed for back-compatibility.
    138  *
    139  * @since 4.9.6
    140  * @deprecated 5.5.0
    141  */
    142 window.privacyToolsL10n = window.privacyToolsL10n || {
    143 	noDataFound: '',
    144 	foundAndRemoved: '',
    145 	noneRemoved: '',
    146 	someNotRemoved: '',
    147 	removalError: '',
    148 	emailSent: '',
    149 	noExportFile: '',
    150 	exportError: ''
    151 };
    152 
    153 window.privacyToolsL10n = deprecateL10nObject( 'privacyToolsL10n', window.privacyToolsL10n, '5.5.0' );
    154 
    155 /**
    156  * Removed in 5.5.0, needed for back-compatibility.
    157  *
    158  * @since 3.6.0
    159  * @deprecated 5.5.0
    160  */
    161 window.authcheckL10n = {
    162 	beforeunload: ''
    163 };
    164 
    165 window.authcheckL10n = window.authcheckL10n || deprecateL10nObject( 'authcheckL10n', window.authcheckL10n, '5.5.0' );
    166 
    167 /**
    168  * Removed in 5.5.0, needed for back-compatibility.
    169  *
    170  * @since 2.8.0
    171  * @deprecated 5.5.0
    172  */
    173 window.tagsl10n = {
    174 	noPerm: '',
    175 	broken: ''
    176 };
    177 
    178 window.tagsl10n = window.tagsl10n || deprecateL10nObject( 'tagsl10n', window.tagsl10n, '5.5.0' );
    179 
    180 /**
    181  * Removed in 5.5.0, needed for back-compatibility.
    182  *
    183  * @since 2.5.0
    184  * @deprecated 5.5.0
    185  */
    186 window.adminCommentsL10n = window.adminCommentsL10n || {
    187 	hotkeys_highlight_first: {
    188 		alternative: 'window.adminCommentsSettings.hotkeys_highlight_first',
    189 		func: function() { return window.adminCommentsSettings.hotkeys_highlight_first; }
    190 	},
    191 	hotkeys_highlight_last: {
    192 		alternative: 'window.adminCommentsSettings.hotkeys_highlight_last',
    193 		func: function() { return window.adminCommentsSettings.hotkeys_highlight_last; }
    194 	},
    195 	replyApprove: '',
    196 	reply: '',
    197 	warnQuickEdit: '',
    198 	warnCommentChanges: '',
    199 	docTitleComments: '',
    200 	docTitleCommentsCount: ''
    201 };
    202 
    203 window.adminCommentsL10n = deprecateL10nObject( 'adminCommentsL10n', window.adminCommentsL10n, '5.5.0' );
    204 
    205 /**
    206  * Removed in 5.5.0, needed for back-compatibility.
    207  *
    208  * @since 2.5.0
    209  * @deprecated 5.5.0
    210  */
    211 window.tagsSuggestL10n = window.tagsSuggestL10n || {
    212 	tagDelimiter: '',
    213 	removeTerm: '',
    214 	termSelected: '',
    215 	termAdded: '',
    216 	termRemoved: ''
    217 };
    218 
    219 window.tagsSuggestL10n = deprecateL10nObject( 'tagsSuggestL10n', window.tagsSuggestL10n, '5.5.0' );
    220 
    221 /**
    222  * Removed in 5.5.0, needed for back-compatibility.
    223  *
    224  * @since 3.5.0
    225  * @deprecated 5.5.0
    226  */
    227 window.wpColorPickerL10n = window.wpColorPickerL10n || {
    228 	clear: '',
    229 	clearAriaLabel: '',
    230 	defaultString: '',
    231 	defaultAriaLabel: '',
    232 	pick: '',
    233 	defaultLabel: ''
    234 };
    235 
    236 window.wpColorPickerL10n = deprecateL10nObject( 'wpColorPickerL10n', window.wpColorPickerL10n, '5.5.0' );
    237 
    238 /**
    239  * Removed in 5.5.0, needed for back-compatibility.
    240  *
    241  * @since 2.7.0
    242  * @deprecated 5.5.0
    243  */
    244 window.attachMediaBoxL10n = window.attachMediaBoxL10n || {
    245 	error: ''
    246 };
    247 
    248 window.attachMediaBoxL10n = deprecateL10nObject( 'attachMediaBoxL10n', window.attachMediaBoxL10n, '5.5.0' );
    249 
    250 /**
    251  * Removed in 5.5.0, needed for back-compatibility.
    252  *
    253  * @since 2.5.0
    254  * @deprecated 5.5.0
    255  */
    256 window.postL10n = window.postL10n || {
    257 	ok: '',
    258 	cancel: '',
    259 	publishOn: '',
    260 	publishOnFuture: '',
    261 	publishOnPast: '',
    262 	dateFormat: '',
    263 	showcomm: '',
    264 	endcomm: '',
    265 	publish: '',
    266 	schedule: '',
    267 	update: '',
    268 	savePending: '',
    269 	saveDraft: '',
    270 	'private': '',
    271 	'public': '',
    272 	publicSticky: '',
    273 	password: '',
    274 	privatelyPublished: '',
    275 	published: '',
    276 	saveAlert: '',
    277 	savingText: '',
    278 	permalinkSaved: ''
    279 };
    280 
    281 window.postL10n = deprecateL10nObject( 'postL10n', window.postL10n, '5.5.0' );
    282 
    283 /**
    284  * Removed in 5.5.0, needed for back-compatibility.
    285  *
    286  * @since 2.7.0
    287  * @deprecated 5.5.0
    288  */
    289 window.inlineEditL10n = window.inlineEditL10n || {
    290 	error: '',
    291 	ntdeltitle: '',
    292 	notitle: '',
    293 	comma: '',
    294 	saved: ''
    295 };
    296 
    297 window.inlineEditL10n = deprecateL10nObject( 'inlineEditL10n', window.inlineEditL10n, '5.5.0' );
    298 
    299 /**
    300  * Removed in 5.5.0, needed for back-compatibility.
    301  *
    302  * @since 2.7.0
    303  * @deprecated 5.5.0
    304  */
    305 window.plugininstallL10n = window.plugininstallL10n || {
    306 	plugin_information: '',
    307 	plugin_modal_label: '',
    308 	ays: ''
    309 };
    310 
    311 window.plugininstallL10n = deprecateL10nObject( 'plugininstallL10n', window.plugininstallL10n, '5.5.0' );
    312 
    313 /**
    314  * Removed in 5.5.0, needed for back-compatibility.
    315  *
    316  * @since 3.0.0
    317  * @deprecated 5.5.0
    318  */
    319 window.navMenuL10n = window.navMenuL10n || {
    320 	noResultsFound: '',
    321 	warnDeleteMenu: '',
    322 	saveAlert: '',
    323 	untitled: ''
    324 };
    325 
    326 window.navMenuL10n = deprecateL10nObject( 'navMenuL10n', window.navMenuL10n, '5.5.0' );
    327 
    328 /**
    329  * Removed in 5.5.0, needed for back-compatibility.
    330  *
    331  * @since 2.5.0
    332  * @deprecated 5.5.0
    333  */
    334 window.commentL10n = window.commentL10n || {
    335 	submittedOn: '',
    336 	dateFormat: ''
    337 };
    338 
    339 window.commentL10n = deprecateL10nObject( 'commentL10n', window.commentL10n, '5.5.0' );
    340 
    341 /**
    342  * Removed in 5.5.0, needed for back-compatibility.
    343  *
    344  * @since 2.9.0
    345  * @deprecated 5.5.0
    346  */
    347 window.setPostThumbnailL10n = window.setPostThumbnailL10n || {
    348 	setThumbnail: '',
    349 	saving: '',
    350 	error: '',
    351 	done: ''
    352 };
    353 
    354 window.setPostThumbnailL10n = deprecateL10nObject( 'setPostThumbnailL10n', window.setPostThumbnailL10n, '5.5.0' );
    355 
    356 /**
    357  * Removed in 3.3.0, needed for back-compatibility.
    358  *
    359  * @since 2.7.0
    360  * @deprecated 3.3.0
    361  */
    362 window.adminMenu = {
    363 	init : function() {},
    364 	fold : function() {},
    365 	restoreMenuState : function() {},
    366 	toggle : function() {},
    367 	favorites : function() {}
    368 };
    369 
    370 // Show/hide/save table columns.
    371 window.columns = {
    372 
    373 	/**
    374 	 * Initializes the column toggles in the screen options.
    375 	 *
    376 	 * Binds an onClick event to the checkboxes to show or hide the table columns
    377 	 * based on their toggled state. And persists the toggled state.
    378 	 *
    379 	 * @since 2.7.0
    380 	 *
    381 	 * @return {void}
    382 	 */
    383 	init : function() {
    384 		var that = this;
    385 		$('.hide-column-tog', '#adv-settings').on( 'click', function() {
    386 			var $t = $(this), column = $t.val();
    387 			if ( $t.prop('checked') )
    388 				that.checked(column);
    389 			else
    390 				that.unchecked(column);
    391 
    392 			columns.saveManageColumnsState();
    393 		});
    394 	},
    395 
    396 	/**
    397 	 * Saves the toggled state for the columns.
    398 	 *
    399 	 * Saves whether the columns should be shown or hidden on a page.
    400 	 *
    401 	 * @since 3.0.0
    402 	 *
    403 	 * @return {void}
    404 	 */
    405 	saveManageColumnsState : function() {
    406 		var hidden = this.hidden();
    407 		$.post(ajaxurl, {
    408 			action: 'hidden-columns',
    409 			hidden: hidden,
    410 			screenoptionnonce: $('#screenoptionnonce').val(),
    411 			page: pagenow
    412 		});
    413 	},
    414 
    415 	/**
    416 	 * Makes a column visible and adjusts the column span for the table.
    417 	 *
    418 	 * @since 3.0.0
    419 	 * @param {string} column The column name.
    420 	 *
    421 	 * @return {void}
    422 	 */
    423 	checked : function(column) {
    424 		$('.column-' + column).removeClass( 'hidden' );
    425 		this.colSpanChange(+1);
    426 	},
    427 
    428 	/**
    429 	 * Hides a column and adjusts the column span for the table.
    430 	 *
    431 	 * @since 3.0.0
    432 	 * @param {string} column The column name.
    433 	 *
    434 	 * @return {void}
    435 	 */
    436 	unchecked : function(column) {
    437 		$('.column-' + column).addClass( 'hidden' );
    438 		this.colSpanChange(-1);
    439 	},
    440 
    441 	/**
    442 	 * Gets all hidden columns.
    443 	 *
    444 	 * @since 3.0.0
    445 	 *
    446 	 * @return {string} The hidden column names separated by a comma.
    447 	 */
    448 	hidden : function() {
    449 		return $( '.manage-column[id]' ).filter( '.hidden' ).map(function() {
    450 			return this.id;
    451 		}).get().join( ',' );
    452 	},
    453 
    454 	/**
    455 	 * Gets the checked column toggles from the screen options.
    456 	 *
    457 	 * @since 3.0.0
    458 	 *
    459 	 * @return {string} String containing the checked column names.
    460 	 */
    461 	useCheckboxesForHidden : function() {
    462 		this.hidden = function(){
    463 			return $('.hide-column-tog').not(':checked').map(function() {
    464 				var id = this.id;
    465 				return id.substring( id, id.length - 5 );
    466 			}).get().join(',');
    467 		};
    468 	},
    469 
    470 	/**
    471 	 * Adjusts the column span for the table.
    472 	 *
    473 	 * @since 3.1.0
    474 	 *
    475 	 * @param {number} diff The modifier for the column span.
    476 	 */
    477 	colSpanChange : function(diff) {
    478 		var $t = $('table').find('.colspanchange'), n;
    479 		if ( !$t.length )
    480 			return;
    481 		n = parseInt( $t.attr('colspan'), 10 ) + diff;
    482 		$t.attr('colspan', n.toString());
    483 	}
    484 };
    485 
    486 $( function() { columns.init(); } );
    487 
    488 /**
    489  * Validates that the required form fields are not empty.
    490  *
    491  * @since 2.9.0
    492  *
    493  * @param {jQuery} form The form to validate.
    494  *
    495  * @return {boolean} Returns true if all required fields are not an empty string.
    496  */
    497 window.validateForm = function( form ) {
    498 	return !$( form )
    499 		.find( '.form-required' )
    500 		.filter( function() { return $( ':input:visible', this ).val() === ''; } )
    501 		.addClass( 'form-invalid' )
    502 		.find( ':input:visible' )
    503 		.on( 'change', function() { $( this ).closest( '.form-invalid' ).removeClass( 'form-invalid' ); } )
    504 		.length;
    505 };
    506 
    507 // Stub for doing better warnings.
    508 /**
    509  * Shows message pop-up notice or confirmation message.
    510  *
    511  * @since 2.7.0
    512  *
    513  * @type {{warn: showNotice.warn, note: showNotice.note}}
    514  *
    515  * @return {void}
    516  */
    517 window.showNotice = {
    518 
    519 	/**
    520 	 * Shows a delete confirmation pop-up message.
    521 	 *
    522 	 * @since 2.7.0
    523 	 *
    524 	 * @return {boolean} Returns true if the message is confirmed.
    525 	 */
    526 	warn : function() {
    527 		if ( confirm( __( 'You are about to permanently delete these items from your site.\nThis action cannot be undone.\n\'Cancel\' to stop, \'OK\' to delete.' ) ) ) {
    528 			return true;
    529 		}
    530 
    531 		return false;
    532 	},
    533 
    534 	/**
    535 	 * Shows an alert message.
    536 	 *
    537 	 * @since 2.7.0
    538 	 *
    539 	 * @param text The text to display in the message.
    540 	 */
    541 	note : function(text) {
    542 		alert(text);
    543 	}
    544 };
    545 
    546 /**
    547  * Represents the functions for the meta screen options panel.
    548  *
    549  * @since 3.2.0
    550  *
    551  * @type {{element: null, toggles: null, page: null, init: screenMeta.init,
    552  *         toggleEvent: screenMeta.toggleEvent, open: screenMeta.open,
    553  *         close: screenMeta.close}}
    554  *
    555  * @return {void}
    556  */
    557 window.screenMeta = {
    558 	element: null, // #screen-meta
    559 	toggles: null, // .screen-meta-toggle
    560 	page:    null, // #wpcontent
    561 
    562 	/**
    563 	 * Initializes the screen meta options panel.
    564 	 *
    565 	 * @since 3.2.0
    566 	 *
    567 	 * @return {void}
    568 	 */
    569 	init: function() {
    570 		this.element = $('#screen-meta');
    571 		this.toggles = $( '#screen-meta-links' ).find( '.show-settings' );
    572 		this.page    = $('#wpcontent');
    573 
    574 		this.toggles.on( 'click', this.toggleEvent );
    575 	},
    576 
    577 	/**
    578 	 * Toggles the screen meta options panel.
    579 	 *
    580 	 * @since 3.2.0
    581 	 *
    582 	 * @return {void}
    583 	 */
    584 	toggleEvent: function() {
    585 		var panel = $( '#' + $( this ).attr( 'aria-controls' ) );
    586 
    587 		if ( !panel.length )
    588 			return;
    589 
    590 		if ( panel.is(':visible') )
    591 			screenMeta.close( panel, $(this) );
    592 		else
    593 			screenMeta.open( panel, $(this) );
    594 	},
    595 
    596 	/**
    597 	 * Opens the screen meta options panel.
    598 	 *
    599 	 * @since 3.2.0
    600 	 *
    601 	 * @param {jQuery} panel  The screen meta options panel div.
    602 	 * @param {jQuery} button The toggle button.
    603 	 *
    604 	 * @return {void}
    605 	 */
    606 	open: function( panel, button ) {
    607 
    608 		$( '#screen-meta-links' ).find( '.screen-meta-toggle' ).not( button.parent() ).css( 'visibility', 'hidden' );
    609 
    610 		panel.parent().show();
    611 
    612 		/**
    613 		 * Sets the focus to the meta options panel and adds the necessary CSS classes.
    614 		 *
    615 		 * @since 3.2.0
    616 		 *
    617 		 * @return {void}
    618 		 */
    619 		panel.slideDown( 'fast', function() {
    620 			panel.trigger( 'focus' );
    621 			button.addClass( 'screen-meta-active' ).attr( 'aria-expanded', true );
    622 		});
    623 
    624 		$document.trigger( 'screen:options:open' );
    625 	},
    626 
    627 	/**
    628 	 * Closes the screen meta options panel.
    629 	 *
    630 	 * @since 3.2.0
    631 	 *
    632 	 * @param {jQuery} panel  The screen meta options panel div.
    633 	 * @param {jQuery} button The toggle button.
    634 	 *
    635 	 * @return {void}
    636 	 */
    637 	close: function( panel, button ) {
    638 		/**
    639 		 * Hides the screen meta options panel.
    640 		 *
    641 		 * @since 3.2.0
    642 		 *
    643 		 * @return {void}
    644 		 */
    645 		panel.slideUp( 'fast', function() {
    646 			button.removeClass( 'screen-meta-active' ).attr( 'aria-expanded', false );
    647 			$('.screen-meta-toggle').css('visibility', '');
    648 			panel.parent().hide();
    649 		});
    650 
    651 		$document.trigger( 'screen:options:close' );
    652 	}
    653 };
    654 
    655 /**
    656  * Initializes the help tabs in the help panel.
    657  *
    658  * @param {Event} e The event object.
    659  *
    660  * @return {void}
    661  */
    662 $('.contextual-help-tabs').on( 'click', 'a', function(e) {
    663 	var link = $(this),
    664 		panel;
    665 
    666 	e.preventDefault();
    667 
    668 	// Don't do anything if the click is for the tab already showing.
    669 	if ( link.is('.active a') )
    670 		return false;
    671 
    672 	// Links.
    673 	$('.contextual-help-tabs .active').removeClass('active');
    674 	link.parent('li').addClass('active');
    675 
    676 	panel = $( link.attr('href') );
    677 
    678 	// Panels.
    679 	$('.help-tab-content').not( panel ).removeClass('active').hide();
    680 	panel.addClass('active').show();
    681 });
    682 
    683 /**
    684  * Update custom permalink structure via buttons.
    685  */
    686 var permalinkStructureFocused = false,
    687     $permalinkStructure       = $( '#permalink_structure' ),
    688     $permalinkStructureInputs = $( '.permalink-structure input:radio' ),
    689     $permalinkCustomSelection = $( '#custom_selection' ),
    690     $availableStructureTags   = $( '.form-table.permalink-structure .available-structure-tags button' );
    691 
    692 // Change permalink structure input when selecting one of the common structures.
    693 $permalinkStructureInputs.on( 'change', function() {
    694 	if ( 'custom' === this.value ) {
    695 		return;
    696 	}
    697 
    698 	$permalinkStructure.val( this.value );
    699 
    700 	// Update button states after selection.
    701 	$availableStructureTags.each( function() {
    702 		changeStructureTagButtonState( $( this ) );
    703 	} );
    704 } );
    705 
    706 $permalinkStructure.on( 'click input', function() {
    707 	$permalinkCustomSelection.prop( 'checked', true );
    708 } );
    709 
    710 // Check if the permalink structure input field has had focus at least once.
    711 $permalinkStructure.on( 'focus', function( event ) {
    712 	permalinkStructureFocused = true;
    713 	$( this ).off( event );
    714 } );
    715 
    716 /**
    717  * Enables or disables a structure tag button depending on its usage.
    718  *
    719  * If the structure is already used in the custom permalink structure,
    720  * it will be disabled.
    721  *
    722  * @param {Object} button Button jQuery object.
    723  */
    724 function changeStructureTagButtonState( button ) {
    725 	if ( -1 !== $permalinkStructure.val().indexOf( button.text().trim() ) ) {
    726 		button.attr( 'data-label', button.attr( 'aria-label' ) );
    727 		button.attr( 'aria-label', button.attr( 'data-used' ) );
    728 		button.attr( 'aria-pressed', true );
    729 		button.addClass( 'active' );
    730 	} else if ( button.attr( 'data-label' ) ) {
    731 		button.attr( 'aria-label', button.attr( 'data-label' ) );
    732 		button.attr( 'aria-pressed', false );
    733 		button.removeClass( 'active' );
    734 	}
    735 }
    736 
    737 // Check initial button state.
    738 $availableStructureTags.each( function() {
    739 	changeStructureTagButtonState( $( this ) );
    740 } );
    741 
    742 // Observe permalink structure field and disable buttons of tags that are already present.
    743 $permalinkStructure.on( 'change', function() {
    744 	$availableStructureTags.each( function() {
    745 		changeStructureTagButtonState( $( this ) );
    746 	} );
    747 } );
    748 
    749 $availableStructureTags.on( 'click', function() {
    750 	var permalinkStructureValue = $permalinkStructure.val(),
    751 	    selectionStart          = $permalinkStructure[ 0 ].selectionStart,
    752 	    selectionEnd            = $permalinkStructure[ 0 ].selectionEnd,
    753 	    textToAppend            = $( this ).text().trim(),
    754 	    textToAnnounce          = $( this ).attr( 'data-added' ),
    755 	    newSelectionStart;
    756 
    757 	// Remove structure tag if already part of the structure.
    758 	if ( -1 !== permalinkStructureValue.indexOf( textToAppend ) ) {
    759 		permalinkStructureValue = permalinkStructureValue.replace( textToAppend + '/', '' );
    760 
    761 		$permalinkStructure.val( '/' === permalinkStructureValue ? '' : permalinkStructureValue );
    762 
    763 		// Announce change to screen readers.
    764 		$( '#custom_selection_updated' ).text( textToAnnounce );
    765 
    766 		// Disable button.
    767 		changeStructureTagButtonState( $( this ) );
    768 
    769 		return;
    770 	}
    771 
    772 	// Input field never had focus, move selection to end of input.
    773 	if ( ! permalinkStructureFocused && 0 === selectionStart && 0 === selectionEnd ) {
    774 		selectionStart = selectionEnd = permalinkStructureValue.length;
    775 	}
    776 
    777 	$permalinkCustomSelection.prop( 'checked', true );
    778 
    779 	// Prepend and append slashes if necessary.
    780 	if ( '/' !== permalinkStructureValue.substr( 0, selectionStart ).substr( -1 ) ) {
    781 		textToAppend = '/' + textToAppend;
    782 	}
    783 
    784 	if ( '/' !== permalinkStructureValue.substr( selectionEnd, 1 ) ) {
    785 		textToAppend = textToAppend + '/';
    786 	}
    787 
    788 	// Insert structure tag at the specified position.
    789 	$permalinkStructure.val( permalinkStructureValue.substr( 0, selectionStart ) + textToAppend + permalinkStructureValue.substr( selectionEnd ) );
    790 
    791 	// Announce change to screen readers.
    792 	$( '#custom_selection_updated' ).text( textToAnnounce );
    793 
    794 	// Disable button.
    795 	changeStructureTagButtonState( $( this ) );
    796 
    797 	// If input had focus give it back with cursor right after appended text.
    798 	if ( permalinkStructureFocused && $permalinkStructure[0].setSelectionRange ) {
    799 		newSelectionStart = ( permalinkStructureValue.substr( 0, selectionStart ) + textToAppend ).length;
    800 		$permalinkStructure[0].setSelectionRange( newSelectionStart, newSelectionStart );
    801 		$permalinkStructure.trigger( 'focus' );
    802 	}
    803 } );
    804 
    805 $( function() {
    806 	var checks, first, last, checked, sliced, mobileEvent, transitionTimeout, focusedRowActions,
    807 		lastClicked = false,
    808 		pageInput = $('input.current-page'),
    809 		currentPage = pageInput.val(),
    810 		isIOS = /iPhone|iPad|iPod/.test( navigator.userAgent ),
    811 		isAndroid = navigator.userAgent.indexOf( 'Android' ) !== -1,
    812 		$adminMenuWrap = $( '#adminmenuwrap' ),
    813 		$wpwrap = $( '#wpwrap' ),
    814 		$adminmenu = $( '#adminmenu' ),
    815 		$overlay = $( '#wp-responsive-overlay' ),
    816 		$toolbar = $( '#wp-toolbar' ),
    817 		$toolbarPopups = $toolbar.find( 'a[aria-haspopup="true"]' ),
    818 		$sortables = $('.meta-box-sortables'),
    819 		wpResponsiveActive = false,
    820 		$adminbar = $( '#wpadminbar' ),
    821 		lastScrollPosition = 0,
    822 		pinnedMenuTop = false,
    823 		pinnedMenuBottom = false,
    824 		menuTop = 0,
    825 		menuState,
    826 		menuIsPinned = false,
    827 		height = {
    828 			window: $window.height(),
    829 			wpwrap: $wpwrap.height(),
    830 			adminbar: $adminbar.height(),
    831 			menu: $adminMenuWrap.height()
    832 		},
    833 		$headerEnd = $( '.wp-header-end' );
    834 
    835 	/**
    836 	 * Makes the fly-out submenu header clickable, when the menu is folded.
    837 	 *
    838 	 * @param {Event} e The event object.
    839 	 *
    840 	 * @return {void}
    841 	 */
    842 	$adminmenu.on('click.wp-submenu-head', '.wp-submenu-head', function(e){
    843 		$(e.target).parent().siblings('a').get(0).click();
    844 	});
    845 
    846 	/**
    847 	 * Collapses the admin menu.
    848 	 *
    849 	 * @return {void}
    850 	 */
    851 	$( '#collapse-button' ).on( 'click.collapse-menu', function() {
    852 		var viewportWidth = getViewportWidth() || 961;
    853 
    854 		// Reset any compensation for submenus near the bottom of the screen.
    855 		$('#adminmenu div.wp-submenu').css('margin-top', '');
    856 
    857 		if ( viewportWidth < 960 ) {
    858 			if ( $body.hasClass('auto-fold') ) {
    859 				$body.removeClass('auto-fold').removeClass('folded');
    860 				setUserSetting('unfold', 1);
    861 				setUserSetting('mfold', 'o');
    862 				menuState = 'open';
    863 			} else {
    864 				$body.addClass('auto-fold');
    865 				setUserSetting('unfold', 0);
    866 				menuState = 'folded';
    867 			}
    868 		} else {
    869 			if ( $body.hasClass('folded') ) {
    870 				$body.removeClass('folded');
    871 				setUserSetting('mfold', 'o');
    872 				menuState = 'open';
    873 			} else {
    874 				$body.addClass('folded');
    875 				setUserSetting('mfold', 'f');
    876 				menuState = 'folded';
    877 			}
    878 		}
    879 
    880 		$document.trigger( 'wp-collapse-menu', { state: menuState } );
    881 	});
    882 
    883 	/**
    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 	 *
    907 	 * @since 4.1.0
    908 	 *
    909 	 * @param {jQuery} $menuItem The parent menu item containing the submenu.
    910 	 *
    911 	 * @return {void}
    912 	 */
    913 	function adjustSubmenu( $menuItem ) {
    914 		var bottomOffset, pageHeight, adjustment, theFold, menutop, wintop, maxtop,
    915 			$submenu = $menuItem.find( '.wp-submenu' );
    916 
    917 		menutop = $menuItem.offset().top;
    918 		wintop = $window.scrollTop();
    919 		maxtop = menutop - wintop - 30; // max = make the top of the sub almost touch admin bar.
    920 
    921 		bottomOffset = menutop + $submenu.height() + 1; // Bottom offset of the menu.
    922 		pageHeight = $wpwrap.height();                  // Height of the entire page.
    923 		adjustment = 60 + bottomOffset - pageHeight;
    924 		theFold = $window.height() + wintop - 50;       // The fold.
    925 
    926 		if ( theFold < ( bottomOffset - adjustment ) ) {
    927 			adjustment = bottomOffset - theFold;
    928 		}
    929 
    930 		if ( adjustment > maxtop ) {
    931 			adjustment = maxtop;
    932 		}
    933 
    934 		if ( adjustment > 1 ) {
    935 			$submenu.css( 'margin-top', '-' + adjustment + 'px' );
    936 		} else {
    937 			$submenu.css( 'margin-top', '' );
    938 		}
    939 	}
    940 
    941 	if ( 'ontouchstart' in window || /IEMobile\/[1-9]/.test(navigator.userAgent) ) { // Touch screen device.
    942 		// iOS Safari works with touchstart, the rest work with click.
    943 		mobileEvent = isIOS ? 'touchstart' : 'click';
    944 
    945 		/**
    946 		 * Closes any open submenus when touch/click is not on the menu.
    947 		 *
    948 		 * @param {Event} e The event object.
    949 		 *
    950 		 * @return {void}
    951 		 */
    952 		$body.on( mobileEvent+'.wp-mobile-hover', function(e) {
    953 			if ( $adminmenu.data('wp-responsive') ) {
    954 				return;
    955 			}
    956 
    957 			if ( ! $( e.target ).closest( '#adminmenu' ).length ) {
    958 				$adminmenu.find( 'li.opensub' ).removeClass( 'opensub' );
    959 			}
    960 		});
    961 
    962 		/**
    963 		 * Handles the opening or closing the submenu based on the mobile click|touch event.
    964 		 *
    965 		 * @param {Event} event The event object.
    966 		 *
    967 		 * @return {void}
    968 		 */
    969 		$adminmenu.find( 'a.wp-has-submenu' ).on( mobileEvent + '.wp-mobile-hover', function( event ) {
    970 			var $menuItem = $(this).parent();
    971 
    972 			if ( $adminmenu.data( 'wp-responsive' ) ) {
    973 				return;
    974 			}
    975 
    976 			/*
    977 			 * Show the sub instead of following the link if:
    978 			 * 	- the submenu is not open.
    979 			 * 	- the submenu is not shown inline or the menu is not folded.
    980 			 */
    981 			if ( ! $menuItem.hasClass( 'opensub' ) && ( ! $menuItem.hasClass( 'wp-menu-open' ) || $menuItem.width() < 40 ) ) {
    982 				event.preventDefault();
    983 				adjustSubmenu( $menuItem );
    984 				$adminmenu.find( 'li.opensub' ).removeClass( 'opensub' );
    985 				$menuItem.addClass('opensub');
    986 			}
    987 		});
    988 	}
    989 
    990 	if ( ! isIOS && ! isAndroid ) {
    991 		$adminmenu.find( 'li.wp-has-submenu' ).hoverIntent({
    992 
    993 			/**
    994 			 * Opens the submenu when hovered over the menu item for desktops.
    995 			 *
    996 			 * @return {void}
    997 			 */
    998 			over: function() {
    999 				var $menuItem = $( this ),
   1000 					$submenu = $menuItem.find( '.wp-submenu' ),
   1001 					top = parseInt( $submenu.css( 'top' ), 10 );
   1002 
   1003 				if ( isNaN( top ) || top > -5 ) { // The submenu is visible.
   1004 					return;
   1005 				}
   1006 
   1007 				if ( $adminmenu.data( 'wp-responsive' ) ) {
   1008 					// The menu is in responsive mode, bail.
   1009 					return;
   1010 				}
   1011 
   1012 				adjustSubmenu( $menuItem );
   1013 				$adminmenu.find( 'li.opensub' ).removeClass( 'opensub' );
   1014 				$menuItem.addClass( 'opensub' );
   1015 			},
   1016 
   1017 			/**
   1018 			 * Closes the submenu when no longer hovering the menu item.
   1019 			 *
   1020 			 * @return {void}
   1021 			 */
   1022 			out: function(){
   1023 				if ( $adminmenu.data( 'wp-responsive' ) ) {
   1024 					// The menu is in responsive mode, bail.
   1025 					return;
   1026 				}
   1027 
   1028 				$( this ).removeClass( 'opensub' ).find( '.wp-submenu' ).css( 'margin-top', '' );
   1029 			},
   1030 			timeout: 200,
   1031 			sensitivity: 7,
   1032 			interval: 90
   1033 		});
   1034 
   1035 		/**
   1036 		 * Opens the submenu on when focused on the menu item.
   1037 		 *
   1038 		 * @param {Event} event The event object.
   1039 		 *
   1040 		 * @return {void}
   1041 		 */
   1042 		$adminmenu.on( 'focus.adminmenu', '.wp-submenu a', function( event ) {
   1043 			if ( $adminmenu.data( 'wp-responsive' ) ) {
   1044 				// The menu is in responsive mode, bail.
   1045 				return;
   1046 			}
   1047 
   1048 			$( event.target ).closest( 'li.menu-top' ).addClass( 'opensub' );
   1049 
   1050 			/**
   1051 			 * Closes the submenu on blur from the menu item.
   1052 			 *
   1053 			 * @param {Event} event The event object.
   1054 			 *
   1055 			 * @return {void}
   1056 			 */
   1057 		}).on( 'blur.adminmenu', '.wp-submenu a', function( event ) {
   1058 			if ( $adminmenu.data( 'wp-responsive' ) ) {
   1059 				return;
   1060 			}
   1061 
   1062 			$( event.target ).closest( 'li.menu-top' ).removeClass( 'opensub' );
   1063 
   1064 			/**
   1065 			 * Adjusts the size for the submenu.
   1066 			 *
   1067 			 * @return {void}
   1068 			 */
   1069 		}).find( 'li.wp-has-submenu.wp-not-current-submenu' ).on( 'focusin.adminmenu', function() {
   1070 			adjustSubmenu( $( this ) );
   1071 		});
   1072 	}
   1073 
   1074 	/*
   1075 	 * The `.below-h2` class is here just for backward compatibility with plugins
   1076 	 * that are (incorrectly) using it. Do not use. Use `.inline` instead. See #34570.
   1077 	 * If '.wp-header-end' is found, append the notices after it otherwise
   1078 	 * after the first h1 or h2 heading found within the main content.
   1079 	 */
   1080 	if ( ! $headerEnd.length ) {
   1081 		$headerEnd = $( '.wrap h1, .wrap h2' ).first();
   1082 	}
   1083 	$( 'div.updated, div.error, div.notice' ).not( '.inline, .below-h2' ).insertAfter( $headerEnd );
   1084 
   1085 	/**
   1086 	 * Makes notices dismissible.
   1087 	 *
   1088 	 * @since 4.4.0
   1089 	 *
   1090 	 * @return {void}
   1091 	 */
   1092 	function makeNoticesDismissible() {
   1093 		$( '.notice.is-dismissible' ).each( function() {
   1094 			var $el = $( this ),
   1095 				$button = $( '<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>' );
   1096 
   1097 			if ( $el.find( '.notice-dismiss' ).length ) {
   1098 				return;
   1099 			}
   1100 
   1101 			// Ensure plain text.
   1102 			$button.find( '.screen-reader-text' ).text( __( 'Dismiss this notice.' ) );
   1103 			$button.on( 'click.wp-dismiss-notice', function( event ) {
   1104 				event.preventDefault();
   1105 				$el.fadeTo( 100, 0, function() {
   1106 					$el.slideUp( 100, function() {
   1107 						$el.remove();
   1108 					});
   1109 				});
   1110 			});
   1111 
   1112 			$el.append( $button );
   1113 		});
   1114 	}
   1115 
   1116 	$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 );
   1117 
   1118 	// Init screen meta.
   1119 	screenMeta.init();
   1120 
   1121 	/**
   1122 	 * Checks a checkbox.
   1123 	 *
   1124 	 * This event needs to be delegated. Ticket #37973.
   1125 	 *
   1126 	 * @return {boolean} Returns whether a checkbox is checked or not.
   1127 	 */
   1128 	$body.on( 'click', 'tbody > tr > .check-column :checkbox', function( event ) {
   1129 		// Shift click to select a range of checkboxes.
   1130 		if ( 'undefined' == event.shiftKey ) { return true; }
   1131 		if ( event.shiftKey ) {
   1132 			if ( !lastClicked ) { return true; }
   1133 			checks = $( lastClicked ).closest( 'form' ).find( ':checkbox' ).filter( ':visible:enabled' );
   1134 			first = checks.index( lastClicked );
   1135 			last = checks.index( this );
   1136 			checked = $(this).prop('checked');
   1137 			if ( 0 < first && 0 < last && first != last ) {
   1138 				sliced = ( last > first ) ? checks.slice( first, last ) : checks.slice( last, first );
   1139 				sliced.prop( 'checked', function() {
   1140 					if ( $(this).closest('tr').is(':visible') )
   1141 						return checked;
   1142 
   1143 					return false;
   1144 				});
   1145 			}
   1146 		}
   1147 		lastClicked = this;
   1148 
   1149 		// Toggle the "Select all" checkboxes depending if the other ones are all checked or not.
   1150 		var unchecked = $(this).closest('tbody').find(':checkbox').filter(':visible:enabled').not(':checked');
   1151 
   1152 		/**
   1153 		 * Determines if all checkboxes are checked.
   1154 		 *
   1155 		 * @return {boolean} Returns true if there are no unchecked checkboxes.
   1156 		 */
   1157 		$(this).closest('table').children('thead, tfoot').find(':checkbox').prop('checked', function() {
   1158 			return ( 0 === unchecked.length );
   1159 		});
   1160 
   1161 		return true;
   1162 	});
   1163 
   1164 	/**
   1165 	 * Controls all the toggles on bulk toggle change.
   1166 	 *
   1167 	 * When the bulk checkbox is changed, all the checkboxes in the tables are changed accordingly.
   1168 	 * When the shift-button is pressed while changing the bulk checkbox the checkboxes in the table are inverted.
   1169 	 *
   1170 	 * This event needs to be delegated. Ticket #37973.
   1171 	 *
   1172 	 * @param {Event} event The event object.
   1173 	 *
   1174 	 * @return {boolean}
   1175 	 */
   1176 	$body.on( 'click.wp-toggle-checkboxes', 'thead .check-column :checkbox, tfoot .check-column :checkbox', function( event ) {
   1177 		var $this = $(this),
   1178 			$table = $this.closest( 'table' ),
   1179 			controlChecked = $this.prop('checked'),
   1180 			toggle = event.shiftKey || $this.data('wp-toggle');
   1181 
   1182 		$table.children( 'tbody' ).filter(':visible')
   1183 			.children().children('.check-column').find(':checkbox')
   1184 			/**
   1185 			 * Updates the checked state on the checkbox in the table.
   1186 			 *
   1187 			 * @return {boolean} True checks the checkbox, False unchecks the checkbox.
   1188 			 */
   1189 			.prop('checked', function() {
   1190 				if ( $(this).is(':hidden,:disabled') ) {
   1191 					return false;
   1192 				}
   1193 
   1194 				if ( toggle ) {
   1195 					return ! $(this).prop( 'checked' );
   1196 				} else if ( controlChecked ) {
   1197 					return true;
   1198 				}
   1199 
   1200 				return false;
   1201 			});
   1202 
   1203 		$table.children('thead,  tfoot').filter(':visible')
   1204 			.children().children('.check-column').find(':checkbox')
   1205 
   1206 			/**
   1207 			 * Syncs the bulk checkboxes on the top and bottom of the table.
   1208 			 *
   1209 			 * @return {boolean} True checks the checkbox, False unchecks the checkbox.
   1210 			 */
   1211 			.prop('checked', function() {
   1212 				if ( toggle ) {
   1213 					return false;
   1214 				} else if ( controlChecked ) {
   1215 					return true;
   1216 				}
   1217 
   1218 				return false;
   1219 			});
   1220 	});
   1221 
   1222 	/**
   1223 	 * Marries a secondary control to its primary control.
   1224 	 *
   1225 	 * @param {jQuery} topSelector    The top selector element.
   1226 	 * @param {jQuery} topSubmit      The top submit element.
   1227 	 * @param {jQuery} bottomSelector The bottom selector element.
   1228 	 * @param {jQuery} bottomSubmit   The bottom submit element.
   1229 	 * @return {void}
   1230 	 */
   1231 	function marryControls( topSelector, topSubmit, bottomSelector, bottomSubmit ) {
   1232 		/**
   1233 		 * Updates the primary selector when the secondary selector is changed.
   1234 		 *
   1235 		 * @since 5.7.0
   1236 		 *
   1237 		 * @return {void}
   1238 		 */
   1239 		function updateTopSelector() {
   1240 			topSelector.val($(this).val());
   1241 		}
   1242 		bottomSelector.on('change', updateTopSelector);
   1243 
   1244 		/**
   1245 		 * Updates the secondary selector when the primary selector is changed.
   1246 		 *
   1247 		 * @since 5.7.0
   1248 		 *
   1249 		 * @return {void}
   1250 		 */
   1251 		function updateBottomSelector() {
   1252 			bottomSelector.val($(this).val());
   1253 		}
   1254 		topSelector.on('change', updateBottomSelector);
   1255 
   1256 		/**
   1257 		 * Triggers the primary submit when then secondary submit is clicked.
   1258 		 *
   1259 		 * @since 5.7.0
   1260 		 *
   1261 		 * @return {void}
   1262 		 */
   1263 		function triggerSubmitClick(e) {
   1264 			e.preventDefault();
   1265 			e.stopPropagation();
   1266 
   1267 			topSubmit.trigger('click');
   1268 		}
   1269 		bottomSubmit.on('click', triggerSubmitClick);
   1270 	}
   1271 
   1272 	// Marry the secondary "Bulk actions" controls to the primary controls:
   1273 	marryControls( $('#bulk-action-selector-top'), $('#doaction'), $('#bulk-action-selector-bottom'), $('#doaction2') );
   1274 
   1275 	// Marry the secondary "Change role to" controls to the primary controls:
   1276 	marryControls( $('#new_role'), $('#changeit'), $('#new_role2'), $('#changeit2') );
   1277 
   1278 	/**
   1279 	 * Shows row actions on focus of its parent container element or any other elements contained within.
   1280 	 *
   1281 	 * @return {void}
   1282 	 */
   1283 	$( '#wpbody-content' ).on({
   1284 		focusin: function() {
   1285 			clearTimeout( transitionTimeout );
   1286 			focusedRowActions = $( this ).find( '.row-actions' );
   1287 			// transitionTimeout is necessary for Firefox, but Chrome won't remove the CSS class without a little help.
   1288 			$( '.row-actions' ).not( this ).removeClass( 'visible' );
   1289 			focusedRowActions.addClass( 'visible' );
   1290 		},
   1291 		focusout: function() {
   1292 			// Tabbing between post title and .row-actions links needs a brief pause, otherwise
   1293 			// the .row-actions div gets hidden in transit in some browsers (ahem, Firefox).
   1294 			transitionTimeout = setTimeout( function() {
   1295 				focusedRowActions.removeClass( 'visible' );
   1296 			}, 30 );
   1297 		}
   1298 	}, '.table-view-list .has-row-actions' );
   1299 
   1300 	// Toggle list table rows on small screens.
   1301 	$( 'tbody' ).on( 'click', '.toggle-row', function() {
   1302 		$( this ).closest( 'tr' ).toggleClass( 'is-expanded' );
   1303 	});
   1304 
   1305 	$('#default-password-nag-no').on( 'click', function() {
   1306 		setUserSetting('default_password_nag', 'hide');
   1307 		$('div.default-password-nag').hide();
   1308 		return false;
   1309 	});
   1310 
   1311 	/**
   1312 	 * Handles tab keypresses in theme and plugin editor textareas.
   1313 	 *
   1314 	 * @param {Event} e The event object.
   1315 	 *
   1316 	 * @return {void}
   1317 	 */
   1318 	$('#newcontent').on('keydown.wpevent_InsertTab', function(e) {
   1319 		var el = e.target, selStart, selEnd, val, scroll, sel;
   1320 
   1321 		// After pressing escape key (keyCode: 27), the tab key should tab out of the textarea.
   1322 		if ( e.keyCode == 27 ) {
   1323 			// When pressing Escape: Opera 12 and 27 blur form fields, IE 8 clears them.
   1324 			e.preventDefault();
   1325 			$(el).data('tab-out', true);
   1326 			return;
   1327 		}
   1328 
   1329 		// Only listen for plain tab key (keyCode: 9) without any modifiers.
   1330 		if ( e.keyCode != 9 || e.ctrlKey || e.altKey || e.shiftKey )
   1331 			return;
   1332 
   1333 		// After tabbing out, reset it so next time the tab key can be used again.
   1334 		if ( $(el).data('tab-out') ) {
   1335 			$(el).data('tab-out', false);
   1336 			return;
   1337 		}
   1338 
   1339 		selStart = el.selectionStart;
   1340 		selEnd = el.selectionEnd;
   1341 		val = el.value;
   1342 
   1343 		// If any text is selected, replace the selection with a tab character.
   1344 		if ( document.selection ) {
   1345 			el.focus();
   1346 			sel = document.selection.createRange();
   1347 			sel.text = '\t';
   1348 		} else if ( selStart >= 0 ) {
   1349 			scroll = this.scrollTop;
   1350 			el.value = val.substring(0, selStart).concat('\t', val.substring(selEnd) );
   1351 			el.selectionStart = el.selectionEnd = selStart + 1;
   1352 			this.scrollTop = scroll;
   1353 		}
   1354 
   1355 		// Cancel the regular tab functionality, to prevent losing focus of the textarea.
   1356 		if ( e.stopPropagation )
   1357 			e.stopPropagation();
   1358 		if ( e.preventDefault )
   1359 			e.preventDefault();
   1360 	});
   1361 
   1362 	// Reset page number variable for new filters/searches but not for bulk actions. See #17685.
   1363 	if ( pageInput.length ) {
   1364 
   1365 		/**
   1366 		 * Handles pagination variable when filtering the list table.
   1367 		 *
   1368 		 * Set the pagination argument to the first page when the post-filter form is submitted.
   1369 		 * This happens when pressing the 'filter' button on the list table page.
   1370 		 *
   1371 		 * The pagination argument should not be touched when the bulk action dropdowns are set to do anything.
   1372 		 *
   1373 		 * The form closest to the pageInput is the post-filter form.
   1374 		 *
   1375 		 * @return {void}
   1376 		 */
   1377 		pageInput.closest('form').on( 'submit', function() {
   1378 			/*
   1379 			 * action = bulk action dropdown at the top of the table
   1380 			 */
   1381 			if ( $('select[name="action"]').val() == -1 && pageInput.val() == currentPage )
   1382 				pageInput.val('1');
   1383 		});
   1384 	}
   1385 
   1386 	/**
   1387 	 * Resets the bulk actions when the search button is clicked.
   1388 	 *
   1389 	 * @return {void}
   1390 	 */
   1391 	$('.search-box input[type="search"], .search-box input[type="submit"]').on( 'mousedown', function () {
   1392 		$('select[name^="action"]').val('-1');
   1393 	});
   1394 
   1395 	/**
   1396 	 * Scrolls into view when focus.scroll-into-view is triggered.
   1397 	 *
   1398 	 * @param {Event} e The event object.
   1399 	 *
   1400 	 * @return {void}
   1401  	 */
   1402 	$('#contextual-help-link, #show-settings-link').on( 'focus.scroll-into-view', function(e){
   1403 		if ( e.target.scrollIntoView )
   1404 			e.target.scrollIntoView(false);
   1405 	});
   1406 
   1407 	/**
   1408 	 * Disables the submit upload buttons when no data is entered.
   1409 	 *
   1410 	 * @return {void}
   1411 	 */
   1412 	(function(){
   1413 		var button, input, form = $('form.wp-upload-form');
   1414 
   1415 		// Exit when no upload form is found.
   1416 		if ( ! form.length )
   1417 			return;
   1418 
   1419 		button = form.find('input[type="submit"]');
   1420 		input = form.find('input[type="file"]');
   1421 
   1422 		/**
   1423 		 * Determines if any data is entered in any file upload input.
   1424 		 *
   1425 		 * @since 3.5.0
   1426 		 *
   1427 		 * @return {void}
   1428 		 */
   1429 		function toggleUploadButton() {
   1430 			// When no inputs have a value, disable the upload buttons.
   1431 			button.prop('disabled', '' === input.map( function() {
   1432 				return $(this).val();
   1433 			}).get().join(''));
   1434 		}
   1435 
   1436 		// Update the status initially.
   1437 		toggleUploadButton();
   1438 		// Update the status when any file input changes.
   1439 		input.on('change', toggleUploadButton);
   1440 	})();
   1441 
   1442 	/**
   1443 	 * Pins the menu while distraction-free writing is enabled.
   1444 	 *
   1445 	 * @param {Event} event Event data.
   1446 	 *
   1447 	 * @since 4.1.0
   1448 	 *
   1449 	 * @return {void}
   1450 	 */
   1451 	function pinMenu( event ) {
   1452 		var windowPos = $window.scrollTop(),
   1453 			resizing = ! event || event.type !== 'scroll';
   1454 
   1455 		if ( isIOS || $adminmenu.data( 'wp-responsive' ) ) {
   1456 			return;
   1457 		}
   1458 
   1459 		/*
   1460 		 * When the menu is higher than the window and smaller than the entire page.
   1461 		 * It should be adjusted to be able to see the entire menu.
   1462 		 *
   1463 		 * Otherwise it can be accessed normally.
   1464 		 */
   1465 		if ( height.menu + height.adminbar < height.window ||
   1466 			height.menu + height.adminbar + 20 > height.wpwrap ) {
   1467 			unpinMenu();
   1468 			return;
   1469 		}
   1470 
   1471 		menuIsPinned = true;
   1472 
   1473 		// If the menu is higher than the window, compensate on scroll.
   1474 		if ( height.menu + height.adminbar > height.window ) {
   1475 			// Check for overscrolling, this happens when swiping up at the top of the document in modern browsers.
   1476 			if ( windowPos < 0 ) {
   1477 				// Stick the menu to the top.
   1478 				if ( ! pinnedMenuTop ) {
   1479 					pinnedMenuTop = true;
   1480 					pinnedMenuBottom = false;
   1481 
   1482 					$adminMenuWrap.css({
   1483 						position: 'fixed',
   1484 						top: '',
   1485 						bottom: ''
   1486 					});
   1487 				}
   1488 
   1489 				return;
   1490 			} else if ( windowPos + height.window > $document.height() - 1 ) {
   1491 				// When overscrolling at the bottom, stick the menu to the bottom.
   1492 				if ( ! pinnedMenuBottom ) {
   1493 					pinnedMenuBottom = true;
   1494 					pinnedMenuTop = false;
   1495 
   1496 					$adminMenuWrap.css({
   1497 						position: 'fixed',
   1498 						top: '',
   1499 						bottom: 0
   1500 					});
   1501 				}
   1502 
   1503 				return;
   1504 			}
   1505 
   1506 			if ( windowPos > lastScrollPosition ) {
   1507 				// When a down scroll has been detected.
   1508 
   1509 				// If it was pinned to the top, unpin and calculate relative scroll.
   1510 				if ( pinnedMenuTop ) {
   1511 					pinnedMenuTop = false;
   1512 					// Calculate new offset position.
   1513 					menuTop = $adminMenuWrap.offset().top - height.adminbar - ( windowPos - lastScrollPosition );
   1514 
   1515 					if ( menuTop + height.menu + height.adminbar < windowPos + height.window ) {
   1516 						menuTop = windowPos + height.window - height.menu - height.adminbar;
   1517 					}
   1518 
   1519 					$adminMenuWrap.css({
   1520 						position: 'absolute',
   1521 						top: menuTop,
   1522 						bottom: ''
   1523 					});
   1524 				} else if ( ! pinnedMenuBottom && $adminMenuWrap.offset().top + height.menu < windowPos + height.window ) {
   1525 					// Pin it to the bottom.
   1526 					pinnedMenuBottom = true;
   1527 
   1528 					$adminMenuWrap.css({
   1529 						position: 'fixed',
   1530 						top: '',
   1531 						bottom: 0
   1532 					});
   1533 				}
   1534 			} else if ( windowPos < lastScrollPosition ) {
   1535 				// When a scroll up is detected.
   1536 
   1537 				// If it was pinned to the bottom, unpin and calculate relative scroll.
   1538 				if ( pinnedMenuBottom ) {
   1539 					pinnedMenuBottom = false;
   1540 
   1541 					// Calculate new offset position.
   1542 					menuTop = $adminMenuWrap.offset().top - height.adminbar + ( lastScrollPosition - windowPos );
   1543 
   1544 					if ( menuTop + height.menu > windowPos + height.window ) {
   1545 						menuTop = windowPos;
   1546 					}
   1547 
   1548 					$adminMenuWrap.css({
   1549 						position: 'absolute',
   1550 						top: menuTop,
   1551 						bottom: ''
   1552 					});
   1553 				} else if ( ! pinnedMenuTop && $adminMenuWrap.offset().top >= windowPos + height.adminbar ) {
   1554 
   1555 					// Pin it to the top.
   1556 					pinnedMenuTop = true;
   1557 
   1558 					$adminMenuWrap.css({
   1559 						position: 'fixed',
   1560 						top: '',
   1561 						bottom: ''
   1562 					});
   1563 				}
   1564 			} else if ( resizing ) {
   1565 				// Window is being resized.
   1566 
   1567 				pinnedMenuTop = pinnedMenuBottom = false;
   1568 
   1569 				// Calculate the new offset.
   1570 				menuTop = windowPos + height.window - height.menu - height.adminbar - 1;
   1571 
   1572 				if ( menuTop > 0 ) {
   1573 					$adminMenuWrap.css({
   1574 						position: 'absolute',
   1575 						top: menuTop,
   1576 						bottom: ''
   1577 					});
   1578 				} else {
   1579 					unpinMenu();
   1580 				}
   1581 			}
   1582 		}
   1583 
   1584 		lastScrollPosition = windowPos;
   1585 	}
   1586 
   1587 	/**
   1588 	 * Determines the height of certain elements.
   1589 	 *
   1590 	 * @since 4.1.0
   1591 	 *
   1592 	 * @return {void}
   1593 	 */
   1594 	function resetHeights() {
   1595 		height = {
   1596 			window: $window.height(),
   1597 			wpwrap: $wpwrap.height(),
   1598 			adminbar: $adminbar.height(),
   1599 			menu: $adminMenuWrap.height()
   1600 		};
   1601 	}
   1602 
   1603 	/**
   1604 	 * Unpins the menu.
   1605 	 *
   1606 	 * @since 4.1.0
   1607 	 *
   1608 	 * @return {void}
   1609 	 */
   1610 	function unpinMenu() {
   1611 		if ( isIOS || ! menuIsPinned ) {
   1612 			return;
   1613 		}
   1614 
   1615 		pinnedMenuTop = pinnedMenuBottom = menuIsPinned = false;
   1616 		$adminMenuWrap.css({
   1617 			position: '',
   1618 			top: '',
   1619 			bottom: ''
   1620 		});
   1621 	}
   1622 
   1623 	/**
   1624 	 * Pins and unpins the menu when applicable.
   1625 	 *
   1626 	 * @since 4.1.0
   1627 	 *
   1628 	 * @return {void}
   1629 	 */
   1630 	function setPinMenu() {
   1631 		resetHeights();
   1632 
   1633 		if ( $adminmenu.data('wp-responsive') ) {
   1634 			$body.removeClass( 'sticky-menu' );
   1635 			unpinMenu();
   1636 		} else if ( height.menu + height.adminbar > height.window ) {
   1637 			pinMenu();
   1638 			$body.removeClass( 'sticky-menu' );
   1639 		} else {
   1640 			$body.addClass( 'sticky-menu' );
   1641 			unpinMenu();
   1642 		}
   1643 	}
   1644 
   1645 	if ( ! isIOS ) {
   1646 		$window.on( 'scroll.pin-menu', pinMenu );
   1647 		$document.on( 'tinymce-editor-init.pin-menu', function( event, editor ) {
   1648 			editor.on( 'wp-autoresize', resetHeights );
   1649 		});
   1650 	}
   1651 
   1652 	/**
   1653 	 * Changes the sortables and responsiveness of metaboxes.
   1654 	 *
   1655 	 * @since 3.8.0
   1656 	 *
   1657 	 * @return {void}
   1658 	 */
   1659 	window.wpResponsive = {
   1660 
   1661 		/**
   1662 		 * Initializes the wpResponsive object.
   1663 		 *
   1664 		 * @since 3.8.0
   1665 		 *
   1666 		 * @return {void}
   1667 		 */
   1668 		init: function() {
   1669 			var self = this;
   1670 
   1671 			this.maybeDisableSortables = this.maybeDisableSortables.bind( this );
   1672 
   1673 			// Modify functionality based on custom activate/deactivate event.
   1674 			$document.on( 'wp-responsive-activate.wp-responsive', function() {
   1675 				self.activate();
   1676 			}).on( 'wp-responsive-deactivate.wp-responsive', function() {
   1677 				self.deactivate();
   1678 			});
   1679 
   1680 			$( '#wp-admin-bar-menu-toggle a' ).attr( 'aria-expanded', 'false' );
   1681 
   1682 			// Toggle sidebar when toggle is clicked.
   1683 			$( '#wp-admin-bar-menu-toggle' ).on( 'click.wp-responsive', function( event ) {
   1684 				event.preventDefault();
   1685 
   1686 				// Close any open toolbar submenus.
   1687 				$adminbar.find( '.hover' ).removeClass( 'hover' );
   1688 
   1689 				$wpwrap.toggleClass( 'wp-responsive-open' );
   1690 				if ( $wpwrap.hasClass( 'wp-responsive-open' ) ) {
   1691 					$(this).find('a').attr( 'aria-expanded', 'true' );
   1692 					$( '#adminmenu a:first' ).trigger( 'focus' );
   1693 				} else {
   1694 					$(this).find('a').attr( 'aria-expanded', 'false' );
   1695 				}
   1696 			} );
   1697 
   1698 			// Add menu events.
   1699 			$adminmenu.on( 'click.wp-responsive', 'li.wp-has-submenu > a', function( event ) {
   1700 				if ( ! $adminmenu.data('wp-responsive') ) {
   1701 					return;
   1702 				}
   1703 
   1704 				$( this ).parent( 'li' ).toggleClass( 'selected' );
   1705 				event.preventDefault();
   1706 			});
   1707 
   1708 			self.trigger();
   1709 			$document.on( 'wp-window-resized.wp-responsive', this.trigger.bind( this ) );
   1710 
   1711 			// This needs to run later as UI Sortable may be initialized later on $(document).ready().
   1712 			$window.on( 'load.wp-responsive', this.maybeDisableSortables );
   1713 			$document.on( 'postbox-toggled', this.maybeDisableSortables );
   1714 
   1715 			// When the screen columns are changed, potentially disable sortables.
   1716 			$( '#screen-options-wrap input' ).on( 'click', this.maybeDisableSortables );
   1717 		},
   1718 
   1719 		/**
   1720 		 * Disable sortables if there is only one metabox, or the screen is in one column mode. Otherwise, enable sortables.
   1721 		 *
   1722 		 * @since 5.3.0
   1723 		 *
   1724 		 * @return {void}
   1725 		 */
   1726 		maybeDisableSortables: function() {
   1727 			var width = navigator.userAgent.indexOf('AppleWebKit/') > -1 ? $window.width() : window.innerWidth;
   1728 
   1729 			if (
   1730 				( width <= 782 ) ||
   1731 				( 1 >= $sortables.find( '.ui-sortable-handle:visible' ).length && jQuery( '.columns-prefs-1 input' ).prop( 'checked' ) )
   1732 			) {
   1733 				this.disableSortables();
   1734 			} else {
   1735 				this.enableSortables();
   1736 			}
   1737 		},
   1738 
   1739 		/**
   1740 		 * Changes properties of body and admin menu.
   1741 		 *
   1742 		 * Pins and unpins the menu and adds the auto-fold class to the body.
   1743 		 * Makes the admin menu responsive and disables the metabox sortables.
   1744 		 *
   1745 		 * @since 3.8.0
   1746 		 *
   1747 		 * @return {void}
   1748 		 */
   1749 		activate: function() {
   1750 			setPinMenu();
   1751 
   1752 			if ( ! $body.hasClass( 'auto-fold' ) ) {
   1753 				$body.addClass( 'auto-fold' );
   1754 			}
   1755 
   1756 			$adminmenu.data( 'wp-responsive', 1 );
   1757 			this.disableSortables();
   1758 		},
   1759 
   1760 		/**
   1761 		 * Changes properties of admin menu and enables metabox sortables.
   1762 		 *
   1763 		 * Pin and unpin the menu.
   1764 		 * Removes the responsiveness of the admin menu and enables the metabox sortables.
   1765 		 *
   1766 		 * @since 3.8.0
   1767 		 *
   1768 		 * @return {void}
   1769 		 */
   1770 		deactivate: function() {
   1771 			setPinMenu();
   1772 			$adminmenu.removeData('wp-responsive');
   1773 
   1774 			this.maybeDisableSortables();
   1775 		},
   1776 
   1777 		/**
   1778 		 * Sets the responsiveness and enables the overlay based on the viewport width.
   1779 		 *
   1780 		 * @since 3.8.0
   1781 		 *
   1782 		 * @return {void}
   1783 		 */
   1784 		trigger: function() {
   1785 			var viewportWidth = getViewportWidth();
   1786 
   1787 			// Exclude IE < 9, it doesn't support @media CSS rules.
   1788 			if ( ! viewportWidth ) {
   1789 				return;
   1790 			}
   1791 
   1792 			if ( viewportWidth <= 782 ) {
   1793 				if ( ! wpResponsiveActive ) {
   1794 					$document.trigger( 'wp-responsive-activate' );
   1795 					wpResponsiveActive = true;
   1796 				}
   1797 			} else {
   1798 				if ( wpResponsiveActive ) {
   1799 					$document.trigger( 'wp-responsive-deactivate' );
   1800 					wpResponsiveActive = false;
   1801 				}
   1802 			}
   1803 
   1804 			if ( viewportWidth <= 480 ) {
   1805 				this.enableOverlay();
   1806 			} else {
   1807 				this.disableOverlay();
   1808 			}
   1809 
   1810 			this.maybeDisableSortables();
   1811 		},
   1812 
   1813 		/**
   1814 		 * Inserts a responsive overlay and toggles the window.
   1815 		 *
   1816 		 * @since 3.8.0
   1817 		 *
   1818 		 * @return {void}
   1819 		 */
   1820 		enableOverlay: function() {
   1821 			if ( $overlay.length === 0 ) {
   1822 				$overlay = $( '<div id="wp-responsive-overlay"></div>' )
   1823 					.insertAfter( '#wpcontent' )
   1824 					.hide()
   1825 					.on( 'click.wp-responsive', function() {
   1826 						$toolbar.find( '.menupop.hover' ).removeClass( 'hover' );
   1827 						$( this ).hide();
   1828 					});
   1829 			}
   1830 
   1831 			$toolbarPopups.on( 'click.wp-responsive', function() {
   1832 				$overlay.show();
   1833 			});
   1834 		},
   1835 
   1836 		/**
   1837 		 * Disables the responsive overlay and removes the overlay.
   1838 		 *
   1839 		 * @since 3.8.0
   1840 		 *
   1841 		 * @return {void}
   1842 		 */
   1843 		disableOverlay: function() {
   1844 			$toolbarPopups.off( 'click.wp-responsive' );
   1845 			$overlay.hide();
   1846 		},
   1847 
   1848 		/**
   1849 		 * Disables sortables.
   1850 		 *
   1851 		 * @since 3.8.0
   1852 		 *
   1853 		 * @return {void}
   1854 		 */
   1855 		disableSortables: function() {
   1856 			if ( $sortables.length ) {
   1857 				try {
   1858 					$sortables.sortable( 'disable' );
   1859 					$sortables.find( '.ui-sortable-handle' ).addClass( 'is-non-sortable' );
   1860 				} catch ( e ) {}
   1861 			}
   1862 		},
   1863 
   1864 		/**
   1865 		 * Enables sortables.
   1866 		 *
   1867 		 * @since 3.8.0
   1868 		 *
   1869 		 * @return {void}
   1870 		 */
   1871 		enableSortables: function() {
   1872 			if ( $sortables.length ) {
   1873 				try {
   1874 					$sortables.sortable( 'enable' );
   1875 					$sortables.find( '.ui-sortable-handle' ).removeClass( 'is-non-sortable' );
   1876 				} catch ( e ) {}
   1877 			}
   1878 		}
   1879 	};
   1880 
   1881 	/**
   1882 	 * Add an ARIA role `button` to elements that behave like UI controls when JavaScript is on.
   1883 	 *
   1884 	 * @since 4.5.0
   1885 	 *
   1886 	 * @return {void}
   1887 	 */
   1888 	function aria_button_if_js() {
   1889 		$( '.aria-button-if-js' ).attr( 'role', 'button' );
   1890 	}
   1891 
   1892 	$( document ).on( 'ajaxComplete', function() {
   1893 		aria_button_if_js();
   1894 	});
   1895 
   1896 	/**
   1897 	 * Get the viewport width.
   1898 	 *
   1899 	 * @since 4.7.0
   1900 	 *
   1901 	 * @return {number|boolean} The current viewport width or false if the
   1902 	 *                          browser doesn't support innerWidth (IE < 9).
   1903 	 */
   1904 	function getViewportWidth() {
   1905 		var viewportWidth = false;
   1906 
   1907 		if ( window.innerWidth ) {
   1908 			// On phones, window.innerWidth is affected by zooming.
   1909 			viewportWidth = Math.max( window.innerWidth, document.documentElement.clientWidth );
   1910 		}
   1911 
   1912 		return viewportWidth;
   1913 	}
   1914 
   1915 	/**
   1916 	 * Sets the admin menu collapsed/expanded state.
   1917 	 *
   1918 	 * Sets the global variable `menuState` and triggers a custom event passing
   1919 	 * the current menu state.
   1920 	 *
   1921 	 * @since 4.7.0
   1922 	 *
   1923 	 * @return {void}
   1924 	 */
   1925 	function setMenuState() {
   1926 		var viewportWidth = getViewportWidth() || 961;
   1927 
   1928 		if ( viewportWidth <= 782  ) {
   1929 			menuState = 'responsive';
   1930 		} else if ( $body.hasClass( 'folded' ) || ( $body.hasClass( 'auto-fold' ) && viewportWidth <= 960 && viewportWidth > 782 ) ) {
   1931 			menuState = 'folded';
   1932 		} else {
   1933 			menuState = 'open';
   1934 		}
   1935 
   1936 		$document.trigger( 'wp-menu-state-set', { state: menuState } );
   1937 	}
   1938 
   1939 	// Set the menu state when the window gets resized.
   1940 	$document.on( 'wp-window-resized.set-menu-state', setMenuState );
   1941 
   1942 	/**
   1943 	 * Sets ARIA attributes on the collapse/expand menu button.
   1944 	 *
   1945 	 * When the admin menu is open or folded, updates the `aria-expanded` and
   1946 	 * `aria-label` attributes of the button to give feedback to assistive
   1947 	 * technologies. In the responsive view, the button is always hidden.
   1948 	 *
   1949 	 * @since 4.7.0
   1950 	 *
   1951 	 * @return {void}
   1952 	 */
   1953 	$document.on( 'wp-menu-state-set wp-collapse-menu', function( event, eventData ) {
   1954 		var $collapseButton = $( '#collapse-button' ),
   1955 			ariaExpanded, ariaLabelText;
   1956 
   1957 		if ( 'folded' === eventData.state ) {
   1958 			ariaExpanded = 'false';
   1959 			ariaLabelText = __( 'Expand Main menu' );
   1960 		} else {
   1961 			ariaExpanded = 'true';
   1962 			ariaLabelText = __( 'Collapse Main menu' );
   1963 		}
   1964 
   1965 		$collapseButton.attr({
   1966 			'aria-expanded': ariaExpanded,
   1967 			'aria-label': ariaLabelText
   1968 		});
   1969 	});
   1970 
   1971 	window.wpResponsive.init();
   1972 	setPinMenu();
   1973 	setMenuState();
   1974 	currentMenuItemHasPopup();
   1975 	makeNoticesDismissible();
   1976 	aria_button_if_js();
   1977 
   1978 	$document.on( 'wp-pin-menu wp-window-resized.pin-menu postboxes-columnchange.pin-menu postbox-toggled.pin-menu wp-collapse-menu.pin-menu wp-scroll-start.pin-menu', setPinMenu );
   1979 
   1980 	// Set initial focus on a specific element.
   1981 	$( '.wp-initial-focus' ).trigger( 'focus' );
   1982 
   1983 	// Toggle update details on update-core.php.
   1984 	$body.on( 'click', '.js-update-details-toggle', function() {
   1985 		var $updateNotice = $( this ).closest( '.js-update-details' ),
   1986 			$progressDiv = $( '#' + $updateNotice.data( 'update-details' ) );
   1987 
   1988 		/*
   1989 		 * When clicking on "Show details" move the progress div below the update
   1990 		 * notice. Make sure it gets moved just the first time.
   1991 		 */
   1992 		if ( ! $progressDiv.hasClass( 'update-details-moved' ) ) {
   1993 			$progressDiv.insertAfter( $updateNotice ).addClass( 'update-details-moved' );
   1994 		}
   1995 
   1996 		// Toggle the progress div visibility.
   1997 		$progressDiv.toggle();
   1998 		// Toggle the Show Details button expanded state.
   1999 		$( this ).attr( 'aria-expanded', $progressDiv.is( ':visible' ) );
   2000 	});
   2001 });
   2002 
   2003 /**
   2004  * Hides the update button for expired plugin or theme uploads.
   2005  *
   2006  * On the "Update plugin/theme from uploaded zip" screen, once the upload has expired,
   2007  * hides the "Replace current with uploaded" button and displays a warning.
   2008  *
   2009  * @since 5.5.0
   2010  */
   2011 $( function( $ ) {
   2012 	var $overwrite, $warning;
   2013 
   2014 	if ( ! $body.hasClass( 'update-php' ) ) {
   2015 		return;
   2016 	}
   2017 
   2018 	$overwrite = $( 'a.update-from-upload-overwrite' );
   2019 	$warning   = $( '.update-from-upload-expired' );
   2020 
   2021 	if ( ! $overwrite.length || ! $warning.length ) {
   2022 		return;
   2023 	}
   2024 
   2025 	window.setTimeout(
   2026 		function() {
   2027 			$overwrite.hide();
   2028 			$warning.removeClass( 'hidden' );
   2029 
   2030 			if ( window.wp && window.wp.a11y ) {
   2031 				window.wp.a11y.speak( $warning.text() );
   2032 			}
   2033 		},
   2034 		7140000 // 119 minutes. The uploaded file is deleted after 2 hours.
   2035 	);
   2036 } );
   2037 
   2038 // Fire a custom jQuery event at the end of window resize.
   2039 ( function() {
   2040 	var timeout;
   2041 
   2042 	/**
   2043 	 * Triggers the WP window-resize event.
   2044 	 *
   2045 	 * @since 3.8.0
   2046 	 *
   2047 	 * @return {void}
   2048 	 */
   2049 	function triggerEvent() {
   2050 		$document.trigger( 'wp-window-resized' );
   2051 	}
   2052 
   2053 	/**
   2054 	 * Fires the trigger event again after 200 ms.
   2055 	 *
   2056 	 * @since 3.8.0
   2057 	 *
   2058 	 * @return {void}
   2059 	 */
   2060 	function fireOnce() {
   2061 		window.clearTimeout( timeout );
   2062 		timeout = window.setTimeout( triggerEvent, 200 );
   2063 	}
   2064 
   2065 	$window.on( 'resize.wp-fire-once', fireOnce );
   2066 }());
   2067 
   2068 // Make Windows 8 devices play along nicely.
   2069 (function(){
   2070 	if ( '-ms-user-select' in document.documentElement.style && navigator.userAgent.match(/IEMobile\/10\.0/) ) {
   2071 		var msViewportStyle = document.createElement( 'style' );
   2072 		msViewportStyle.appendChild(
   2073 			document.createTextNode( '@-ms-viewport{width:auto!important}' )
   2074 		);
   2075 		document.getElementsByTagName( 'head' )[0].appendChild( msViewportStyle );
   2076 	}
   2077 })();
   2078 
   2079 }( jQuery, window ));