wp/wp-admin/js/post.js
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     2  * @file Contains all dynamic functionality needed on post and term pages.
     2  * @file Contains all dynamic functionality needed on post and term pages.
     3  *
     3  *
     4  * @output wp-admin/js/post.js
     4  * @output wp-admin/js/post.js
     5  */
     5  */
     6 
     6 
     7  /* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting */
     7  /* global ajaxurl, wpAjax, postboxes, pagenow, tinymce, alert, deleteUserSetting, ClipboardJS */
     8  /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */
     8  /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */
     9  /* global WPSetThumbnailHTML, wptitlehint */
     9  /* global WPSetThumbnailHTML, wptitlehint */
    10 
    10 
    11 // Backwards compatibility: prevent fatal errors.
    11 // Backward compatibility: prevent fatal errors.
    12 window.makeSlugeditClickable = window.editPermalink = function(){};
    12 window.makeSlugeditClickable = window.editPermalink = function(){};
    13 
    13 
    14 // Make sure the wp object exists.
    14 // Make sure the wp object exists.
    15 window.wp = window.wp || {};
    15 window.wp = window.wp || {};
    16 
    16 
    17 ( function( $ ) {
    17 ( function( $ ) {
    18 	var titleHasFocus = false;
    18 	var titleHasFocus = false,
       
    19 		__ = wp.i18n.__;
    19 
    20 
    20 	/**
    21 	/**
    21 	 * Control loading of comments on the post and term edit pages.
    22 	 * Control loading of comments on the post and term edit pages.
    22 	 *
    23 	 *
    23 	 * @type {{st: number, get: commentsBox.get, load: commentsBox.load}}
    24 	 * @type {{st: number, get: commentsBox.get, load: commentsBox.load}}
    27 	window.commentsBox = {
    28 	window.commentsBox = {
    28 		// Comment offset to use when fetching new comments.
    29 		// Comment offset to use when fetching new comments.
    29 		st : 0,
    30 		st : 0,
    30 
    31 
    31 		/**
    32 		/**
    32 		 * Fetch comments using AJAX and display them in the box.
    33 		 * Fetch comments using Ajax and display them in the box.
    33 		 *
    34 		 *
    34 		 * @memberof commentsBox
    35 		 * @memberof commentsBox
    35 		 *
    36 		 *
    36 		 * @param {int} total Total number of comments for this post.
    37 		 * @param {number} total Total number of comments for this post.
    37 		 * @param {int} num   Optional. Number of comments to fetch, defaults to 20.
    38 		 * @param {number} num   Optional. Number of comments to fetch, defaults to 20.
    38 		 * @returns {boolean} Always returns false.
    39 		 * @return {boolean} Always returns false.
    39 		 */
    40 		 */
    40 		get : function(total, num) {
    41 		get : function(total, num) {
    41 			var st = this.st, data;
    42 			var st = this.st, data;
    42 			if ( ! num )
    43 			if ( ! num )
    43 				num = 20;
    44 				num = 20;
    71 
    72 
    72 						// If the offset is over the total number of comments we cannot fetch any more, so hide the button.
    73 						// If the offset is over the total number of comments we cannot fetch any more, so hide the button.
    73 						if ( commentsBox.st > commentsBox.total )
    74 						if ( commentsBox.st > commentsBox.total )
    74 							$('#show-comments').hide();
    75 							$('#show-comments').hide();
    75 						else
    76 						else
    76 							$('#show-comments').show().children('a').html(postL10n.showcomm);
    77 							$('#show-comments').show().children('a').text( __( 'Show more comments' ) );
    77 
    78 
    78 						return;
    79 						return;
    79 					} else if ( 1 == r ) {
    80 					} else if ( 1 == r ) {
    80 						$('#show-comments').html(postL10n.endcomm);
    81 						$('#show-comments').text( __( 'No more comments found.' ) );
    81 						return;
    82 						return;
    82 					}
    83 					}
    83 
    84 
    84 					$('#the-comment-list').append('<tr><td colspan="2">'+wpAjax.broken+'</td></tr>');
    85 					$('#the-comment-list').append('<tr><td colspan="2">'+wpAjax.broken+'</td></tr>');
    85 				}
    86 				}
    89 		},
    90 		},
    90 
    91 
    91 		/**
    92 		/**
    92 		 * Load the next batch of comments.
    93 		 * Load the next batch of comments.
    93 		 *
    94 		 *
    94 		 * @param {int} total Total number of comments to load.
       
    95 		 *
       
    96 		 * @memberof commentsBox
    95 		 * @memberof commentsBox
       
    96 		 *
       
    97 		 * @param {number} total Total number of comments to load.
    97 		 */
    98 		 */
    98 		load: function(total){
    99 		load: function(total){
    99 			this.st = jQuery('#the-comment-list tr.comment:visible').length;
   100 			this.st = jQuery('#the-comment-list tr.comment:visible').length;
   100 			this.get(total);
   101 			this.get(total);
   101 		}
   102 		}
   113 	};
   114 	};
   114 
   115 
   115 	/**
   116 	/**
   116 	 * Set the Image ID of the Featured Image
   117 	 * Set the Image ID of the Featured Image
   117 	 *
   118 	 *
   118 	 * @param {int} id The post_id of the image to use as Featured Image.
   119 	 * @param {number} id The post_id of the image to use as Featured Image.
   119 	 *
   120 	 *
   120 	 * @global
   121 	 * @global
   121 	 */
   122 	 */
   122 	window.WPSetThumbnailID = function(id){
   123 	window.WPSetThumbnailID = function(id){
   123 		var field = $('input[value="_thumbnail_id"]', '#list-table');
   124 		var field = $('input[value="_thumbnail_id"]', '#list-table');
   142 			 *
   143 			 *
   143 			 * @param {string} str Response, will be '0' when an error occurred otherwise contains link to add Featured Image.
   144 			 * @param {string} str Response, will be '0' when an error occurred otherwise contains link to add Featured Image.
   144 			 */
   145 			 */
   145 			function(str){
   146 			function(str){
   146 			if ( str == '0' ) {
   147 			if ( str == '0' ) {
   147 				alert( setPostThumbnailL10n.error );
   148 				alert( __( 'Could not set that as the thumbnail image. Try a different attachment.' ) );
   148 			} else {
   149 			} else {
   149 				WPSetThumbnailHTML(str);
   150 				WPSetThumbnailHTML(str);
   150 			}
   151 			}
   151 		}
   152 		}
   152 		);
   153 		);
   198 						wrap.addClass('saving');
   199 						wrap.addClass('saving');
   199 						wp.autosave.server.triggerSave();
   200 						wp.autosave.server.triggerSave();
   200 					}
   201 					}
   201 
   202 
   202 					if ( received.lock_error.avatar_src ) {
   203 					if ( received.lock_error.avatar_src ) {
   203 						avatar = $( '<img class="avatar avatar-64 photo" width="64" height="64" alt="" />' ).attr( 'src', received.lock_error.avatar_src.replace( /&amp;/g, '&' ) );
   204 						avatar = $( '<img />', {
       
   205 							'class': 'avatar avatar-64 photo',
       
   206 							width: 64,
       
   207 							height: 64,
       
   208 							alt: '',
       
   209 							src: received.lock_error.avatar_src,
       
   210 							srcset: received.lock_error.avatar_src_2x ? received.lock_error.avatar_src_2x + ' 2x' : undefined
       
   211 						} );
   204 						wrap.find('div.post-locked-avatar').empty().append( avatar );
   212 						wrap.find('div.post-locked-avatar').empty().append( avatar );
   205 					}
   213 					}
   206 
   214 
   207 					wrap.show().find('.currently-editing').text( received.lock_error.text );
   215 					wrap.show().find('.currently-editing').text( received.lock_error.text );
   208 					wrap.find('.wp-tab-first').focus();
   216 					wrap.find('.wp-tab-first').focus();
   286 /**
   294 /**
   287  * All post and postbox controls and functionality.
   295  * All post and postbox controls and functionality.
   288  */
   296  */
   289 jQuery(document).ready( function($) {
   297 jQuery(document).ready( function($) {
   290 	var stamp, visibility, $submitButtons, updateVisibility, updateText,
   298 	var stamp, visibility, $submitButtons, updateVisibility, updateText,
   291 		sticky = '',
       
   292 		$textarea = $('#content'),
   299 		$textarea = $('#content'),
   293 		$document = $(document),
   300 		$document = $(document),
   294 		postId = $('#post_ID').val() || 0,
   301 		postId = $('#post_ID').val() || 0,
   295 		$submitpost = $('#submitpost'),
   302 		$submitpost = $('#submitpost'),
   296 		releaseLock = true,
   303 		releaseLock = true,
   297 		$postVisibilitySelect = $('#post-visibility-select'),
   304 		$postVisibilitySelect = $('#post-visibility-select'),
   298 		$timestampdiv = $('#timestampdiv'),
   305 		$timestampdiv = $('#timestampdiv'),
   299 		$postStatusSelect = $('#post-status-select'),
   306 		$postStatusSelect = $('#post-status-select'),
   300 		isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false;
   307 		isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false,
       
   308 		copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.edit-media' ),
       
   309 		copyAttachmentURLSuccessTimeout,
       
   310 		__ = wp.i18n.__, _x = wp.i18n._x;
   301 
   311 
   302 	postboxes.add_postbox_toggles(pagenow);
   312 	postboxes.add_postbox_toggles(pagenow);
   303 
   313 
   304 	/*
   314 	/*
   305 	 * Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post,
   315 	 * Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post,
   307 	 */
   317 	 */
   308 	window.name = '';
   318 	window.name = '';
   309 
   319 
   310 	// Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
   320 	// Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
   311 	$('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) {
   321 	$('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) {
   312 		// Don't do anything when [tab] is pressed.
   322 		// Don't do anything when [Tab] is pressed.
   313 		if ( e.which != 9 )
   323 		if ( e.which != 9 )
   314 			return;
   324 			return;
   315 
   325 
   316 		var target = $(e.target);
   326 		var target = $(e.target);
   317 
   327 
   318 		// [shift] + [tab] on first tab cycles back to last tab.
   328 		// [Shift] + [Tab] on first tab cycles back to last tab.
   319 		if ( target.hasClass('wp-tab-first') && e.shiftKey ) {
   329 		if ( target.hasClass('wp-tab-first') && e.shiftKey ) {
   320 			$(this).find('.wp-tab-last').focus();
   330 			$(this).find('.wp-tab-last').focus();
   321 			e.preventDefault();
   331 			e.preventDefault();
   322 		// [tab] on last tab cycles back to first tab.
   332 		// [Tab] on last tab cycles back to first tab.
   323 		} else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) {
   333 		} else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) {
   324 			$(this).find('.wp-tab-first').focus();
   334 			$(this).find('.wp-tab-first').focus();
   325 			e.preventDefault();
   335 			e.preventDefault();
   326 		}
   336 		}
   327 	}).filter(':visible').find('.wp-tab-first').focus();
   337 	}).filter(':visible').find('.wp-tab-first').focus();
   328 
   338 
   329 	// Set the heartbeat interval to 15 sec. if post lock dialogs are enabled.
   339 	// Set the heartbeat interval to 15 seconds if post lock dialogs are enabled.
   330 	if ( wp.heartbeat && $('#post-lock-dialog').length ) {
   340 	if ( wp.heartbeat && $('#post-lock-dialog').length ) {
   331 		wp.heartbeat.interval( 15 );
   341 		wp.heartbeat.interval( 15 );
   332 	}
   342 	}
   333 
   343 
   334 	// The form is being submitted by the user.
   344 	// The form is being submitted by the user.
   383 				$submitpost.find( '#minor-publishing .spinner' ).addClass( 'is-active' );
   393 				$submitpost.find( '#minor-publishing .spinner' ).addClass( 'is-active' );
   384 			}
   394 			}
   385 		});
   395 		});
   386 	});
   396 	});
   387 
   397 
   388 	// Submit the form saving a draft or an autosave, and show a preview in a new tab
   398 	// Submit the form saving a draft or an autosave, and show a preview in a new tab.
   389 	$('#post-preview').on( 'click.post-preview', function( event ) {
   399 	$('#post-preview').on( 'click.post-preview', function( event ) {
   390 		var $this = $(this),
   400 		var $this = $(this),
   391 			$form = $('form#post'),
   401 			$form = $('form#post'),
   392 			$previewField = $('input#wp-preview'),
   402 			$previewField = $('input#wp-preview'),
   393 			target = $this.attr('target') || 'wp-preview',
   403 			target = $this.attr('target') || 'wp-preview',
   463 	}).on( 'autosave-enable-buttons.edit-post', function() {
   473 	}).on( 'autosave-enable-buttons.edit-post', function() {
   464 		if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {
   474 		if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {
   465 			$submitButtons.removeClass( 'disabled' );
   475 			$submitButtons.removeClass( 'disabled' );
   466 		}
   476 		}
   467 	}).on( 'before-autosave.edit-post', function() {
   477 	}).on( 'before-autosave.edit-post', function() {
   468 		$( '.autosave-message' ).text( postL10n.savingText );
   478 		$( '.autosave-message' ).text( __( 'Saving Draft…' ) );
   469 	}).on( 'after-autosave.edit-post', function( event, data ) {
   479 	}).on( 'after-autosave.edit-post', function( event, data ) {
   470 		$( '.autosave-message' ).text( data.message );
   480 		$( '.autosave-message' ).text( data.message );
   471 
   481 
   472 		if ( $( document.body ).hasClass( 'post-new-php' ) ) {
   482 		if ( $( document.body ).hasClass( 'post-new-php' ) ) {
   473 			$( '.submitbox .submitdelete' ).show();
   483 			$( '.submitbox .submitdelete' ).show();
   482 		var editor = typeof tinymce !== 'undefined' && tinymce.get('content');
   492 		var editor = typeof tinymce !== 'undefined' && tinymce.get('content');
   483 
   493 
   484 		if ( ( editor && ! editor.isHidden() && editor.isDirty() ) ||
   494 		if ( ( editor && ! editor.isHidden() && editor.isDirty() ) ||
   485 			( wp.autosave && wp.autosave.server.postChanged() ) ) {
   495 			( wp.autosave && wp.autosave.server.postChanged() ) ) {
   486 
   496 
   487 			return postL10n.saveAlert;
   497 			return __( 'The changes you made will be lost if you navigate away from this page.' );
   488 		}
   498 		}
   489 	}).on( 'unload.edit-post', function( event ) {
   499 	}).on( 'unload.edit-post', function( event ) {
   490 		if ( ! releaseLock ) {
   500 		if ( ! releaseLock ) {
   491 			return;
   501 			return;
   492 		}
   502 		}
   532 			data: data,
   542 			data: data,
   533 			url: ajaxurl
   543 			url: ajaxurl
   534 		});
   544 		});
   535 	});
   545 	});
   536 
   546 
   537 	// Multiple Taxonomies.
   547 	// Multiple taxonomies.
   538 	if ( $('#tagsdiv-post_tag').length ) {
   548 	if ( $('#tagsdiv-post_tag').length ) {
   539 		window.tagBox && window.tagBox.init();
   549 		window.tagBox && window.tagBox.init();
   540 	} else {
   550 	} else {
   541 		$('.meta-box-sortables').children('div.postbox').each(function(){
   551 		$('.meta-box-sortables').children('div.postbox').each(function(){
   542 			if ( this.id.indexOf('tagsdiv-') === 0 ) {
   552 			if ( this.id.indexOf('tagsdiv-') === 0 ) {
   557 
   567 
   558 		if ( taxonomy == 'category' ) {
   568 		if ( taxonomy == 'category' ) {
   559 			settingName = 'cats';
   569 			settingName = 'cats';
   560 		}
   570 		}
   561 
   571 
   562 		// TODO: move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js
   572 		// @todo Move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js.
   563 		$('a', '#' + taxonomy + '-tabs').click( function( e ) {
   573 		$('a', '#' + taxonomy + '-tabs').click( function( e ) {
   564 			e.preventDefault();
   574 			e.preventDefault();
   565 			var t = $(this).attr('href');
   575 			var t = $(this).attr('href');
   566 			$(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
   576 			$(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
   567 			$('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide();
   577 			$('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide();
   579 		// Add category button controls.
   589 		// Add category button controls.
   580 		$('#new' + taxonomy).one( 'focus', function() {
   590 		$('#new' + taxonomy).one( 'focus', function() {
   581 			$( this ).val( '' ).removeClass( 'form-input-tip' );
   591 			$( this ).val( '' ).removeClass( 'form-input-tip' );
   582 		});
   592 		});
   583 
   593 
   584 		// On [enter] submit the taxonomy.
   594 		// On [Enter] submit the taxonomy.
   585 		$('#new' + taxonomy).keypress( function(event){
   595 		$('#new' + taxonomy).keypress( function(event){
   586 			if( 13 === event.keyCode ) {
   596 			if( 13 === event.keyCode ) {
   587 				event.preventDefault();
   597 				event.preventDefault();
   588 				$('#' + taxonomy + '-add-submit').click();
   598 				$('#' + taxonomy + '-add-submit').click();
   589 			}
   599 			}
   597 		/**
   607 		/**
   598 		 * Before adding a new taxonomy, disable submit button.
   608 		 * Before adding a new taxonomy, disable submit button.
   599 		 *
   609 		 *
   600 		 * @param {Object} s Taxonomy object which will be added.
   610 		 * @param {Object} s Taxonomy object which will be added.
   601 		 *
   611 		 *
   602 		 * @returns {Object}
   612 		 * @return {Object}
   603 		 */
   613 		 */
   604 		catAddBefore = function( s ) {
   614 		catAddBefore = function( s ) {
   605 			if ( !$('#new'+taxonomy).val() ) {
   615 			if ( !$('#new'+taxonomy).val() ) {
   606 				return false;
   616 				return false;
   607 			}
   617 			}
   618 		 * If the taxonomy has a parent place the taxonomy underneath the parent.
   628 		 * If the taxonomy has a parent place the taxonomy underneath the parent.
   619 		 *
   629 		 *
   620 		 * @param {Object} r Response.
   630 		 * @param {Object} r Response.
   621 		 * @param {Object} s Taxonomy data.
   631 		 * @param {Object} s Taxonomy data.
   622 		 *
   632 		 *
   623 		 * @returns void
   633 		 * @return {void}
   624 		 */
   634 		 */
   625 		catAddAfter = function( r, s ) {
   635 		catAddAfter = function( r, s ) {
   626 			var sup, drop = $('#new'+taxonomy+'_parent');
   636 			var sup, drop = $('#new'+taxonomy+'_parent');
   627 
   637 
   628 			$( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false );
   638 			$( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false );
   652 			var t = $(this), c = t.is(':checked'), id = t.val();
   662 			var t = $(this), c = t.is(':checked'), id = t.val();
   653 			if ( id && t.parents('#taxonomy-'+taxonomy).length )
   663 			if ( id && t.parents('#taxonomy-'+taxonomy).length )
   654 				$('#in-' + taxonomy + '-' + id + ', #in-popular-' + taxonomy + '-' + id).prop( 'checked', c );
   664 				$('#in-' + taxonomy + '-' + id + ', #in-popular-' + taxonomy + '-' + id).prop( 'checked', c );
   655 		});
   665 		});
   656 
   666 
   657 	}); // end cats
   667 	}); // End cats.
   658 
   668 
   659 	// Custom Fields postbox.
   669 	// Custom Fields postbox.
   660 	if ( $('#postcustom').length ) {
   670 	if ( $('#postcustom').length ) {
   661 		$( '#the-list' ).wpList( {
   671 		$( '#the-list' ).wpList( {
   662 			/**
   672 			/**
   664 			 *
   674 			 *
   665 			 * @ignore
   675 			 * @ignore
   666 			 *
   676 			 *
   667 			 * @param {Object} s Request object.
   677 			 * @param {Object} s Request object.
   668 			 *
   678 			 *
   669 			 * @returns {Object} Data modified with post_ID attached.
   679 			 * @return {Object} Data modified with post_ID attached.
   670 			 */
   680 			 */
   671 			addBefore: function( s ) {
   681 			addBefore: function( s ) {
   672 				s.data += '&post_id=' + $('#post_ID').val();
   682 				s.data += '&post_id=' + $('#post_ID').val();
   673 				return s;
   683 				return s;
   674 			},
   684 			},
   693 		/**
   703 		/**
   694 		 * When the visibility of a post changes sub-options should be shown or hidden.
   704 		 * When the visibility of a post changes sub-options should be shown or hidden.
   695 		 *
   705 		 *
   696 		 * @ignore
   706 		 * @ignore
   697 		 *
   707 		 *
   698 		 * @returns void
   708 		 * @return {void}
   699 		 */
   709 		 */
   700 		updateVisibility = function() {
   710 		updateVisibility = function() {
   701 			// Show sticky for public posts.
   711 			// Show sticky for public posts.
   702 			if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
   712 			if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
   703 				$('#sticky').prop('checked', false);
   713 				$('#sticky').prop('checked', false);
   717 		/**
   727 		/**
   718 		 * Make sure all labels represent the current settings.
   728 		 * Make sure all labels represent the current settings.
   719 		 *
   729 		 *
   720 		 * @ignore
   730 		 * @ignore
   721 		 *
   731 		 *
   722 		 * @returns {boolean} False when an invalid timestamp has been selected, otherwise True.
   732 		 * @return {boolean} False when an invalid timestamp has been selected, otherwise True.
   723 		 */
   733 		 */
   724 		updateText = function() {
   734 		updateText = function() {
   725 
   735 
   726 			if ( ! $timestampdiv.length )
   736 			if ( ! $timestampdiv.length )
   727 				return true;
   737 				return true;
   742 				$timestampdiv.find('.timestamp-wrap').removeClass('form-invalid');
   752 				$timestampdiv.find('.timestamp-wrap').removeClass('form-invalid');
   743 			}
   753 			}
   744 
   754 
   745 			// Determine what the publish should be depending on the date and post status.
   755 			// Determine what the publish should be depending on the date and post status.
   746 			if ( attemptedDate > currentDate && $('#original_post_status').val() != 'future' ) {
   756 			if ( attemptedDate > currentDate && $('#original_post_status').val() != 'future' ) {
   747 				publishOn = postL10n.publishOnFuture;
   757 				publishOn = __( 'Schedule for:' );
   748 				$('#publish').val( postL10n.schedule );
   758 				$('#publish').val( _x( 'Schedule', 'post action/button label' ) );
   749 			} else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) {
   759 			} else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) {
   750 				publishOn = postL10n.publishOn;
   760 				publishOn = __( 'Publish on:' );
   751 				$('#publish').val( postL10n.publish );
   761 				$('#publish').val( __( 'Publish' ) );
   752 			} else {
   762 			} else {
   753 				publishOn = postL10n.publishOnPast;
   763 				publishOn = __( 'Published on:' );
   754 				$('#publish').val( postL10n.update );
   764 				$('#publish').val( __( 'Update' ) );
   755 			}
   765 			}
   756 
   766 
   757 			// If the date is the same, set it to trigger update events.
   767 			// If the date is the same, set it to trigger update events.
   758 			if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) {
   768 			if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) {
   759 				// Re-set to the current value.
   769 				// Re-set to the current value.
   760 				$('#timestamp').html(stamp);
   770 				$('#timestamp').html(stamp);
   761 			} else {
   771 			} else {
   762 				$('#timestamp').html(
   772 				$('#timestamp').html(
   763 					'\n' + publishOn + ' <b>' +
   773 					'\n' + publishOn + ' <b>' +
   764 					postL10n.dateFormat
   774 					// translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute.
       
   775 					__( '%1$s %2$s, %3$s at %4$s:%5$s' )
   765 						.replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) )
   776 						.replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) )
   766 						.replace( '%2$s', parseInt( jj, 10 ) )
   777 						.replace( '%2$s', parseInt( jj, 10 ) )
   767 						.replace( '%3$s', aa )
   778 						.replace( '%3$s', aa )
   768 						.replace( '%4$s', ( '00' + hh ).slice( -2 ) )
   779 						.replace( '%4$s', ( '00' + hh ).slice( -2 ) )
   769 						.replace( '%5$s', ( '00' + mn ).slice( -2 ) ) +
   780 						.replace( '%5$s', ( '00' + mn ).slice( -2 ) ) +
   771 				);
   782 				);
   772 			}
   783 			}
   773 
   784 
   774 			// Add "privately published" to post status when applies.
   785 			// Add "privately published" to post status when applies.
   775 			if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) {
   786 			if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) {
   776 				$('#publish').val( postL10n.update );
   787 				$('#publish').val( __( 'Update' ) );
   777 				if ( 0 === optPublish.length ) {
   788 				if ( 0 === optPublish.length ) {
   778 					postStatus.append('<option value="publish">' + postL10n.privatelyPublished + '</option>');
   789 					postStatus.append('<option value="publish">' + __( 'Privately Published' ) + '</option>');
   779 				} else {
   790 				} else {
   780 					optPublish.html( postL10n.privatelyPublished );
   791 					optPublish.html( __( 'Privately Published' ) );
   781 				}
   792 				}
   782 				$('option[value="publish"]', postStatus).prop('selected', true);
   793 				$('option[value="publish"]', postStatus).prop('selected', true);
   783 				$('#misc-publishing-actions .edit-post-status').hide();
   794 				$('#misc-publishing-actions .edit-post-status').hide();
   784 			} else {
   795 			} else {
   785 				if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
   796 				if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
   786 					if ( optPublish.length ) {
   797 					if ( optPublish.length ) {
   787 						optPublish.remove();
   798 						optPublish.remove();
   788 						postStatus.val($('#hidden_post_status').val());
   799 						postStatus.val($('#hidden_post_status').val());
   789 					}
   800 					}
   790 				} else {
   801 				} else {
   791 					optPublish.html( postL10n.published );
   802 					optPublish.html( __( 'Published' ) );
   792 				}
   803 				}
   793 				if ( postStatus.is(':hidden') )
   804 				if ( postStatus.is(':hidden') )
   794 					$('#misc-publishing-actions .edit-post-status').show();
   805 					$('#misc-publishing-actions .edit-post-status').show();
   795 			}
   806 			}
   796 
   807 
   797 			// Update "Status:" to currently selected status.
   808 			// Update "Status:" to currently selected status.
   798 			$('#post-status-display').text(
   809 			$('#post-status-display').text(
   799 				wp.sanitize.stripTagsAndEncodeText( $('option:selected', postStatus).text() ) // Remove any potential tags from post status text.
   810 				// Remove any potential tags from post status text.
       
   811 				wp.sanitize.stripTagsAndEncodeText( $('option:selected', postStatus).text() )
   800 			);
   812 			);
   801 
   813 
   802 			// Show or hide the "Save Draft" button.
   814 			// Show or hide the "Save Draft" button.
   803 			if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
   815 			if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
   804 				$('#save-post').hide();
   816 				$('#save-post').hide();
   805 			} else {
   817 			} else {
   806 				$('#save-post').show();
   818 				$('#save-post').show();
   807 				if ( $('option:selected', postStatus).val() == 'pending' ) {
   819 				if ( $('option:selected', postStatus).val() == 'pending' ) {
   808 					$('#save-post').show().val( postL10n.savePending );
   820 					$('#save-post').show().val( __( 'Save as Pending' ) );
   809 				} else {
   821 				} else {
   810 					$('#save-post').show().val( postL10n.saveDraft );
   822 					$('#save-post').show().val( __( 'Save Draft' ) );
   811 				}
   823 				}
   812 			}
   824 			}
   813 			return true;
   825 			return true;
   814 		};
   826 		};
   815 
   827 
   836 			updateText();
   848 			updateText();
   837 			event.preventDefault();
   849 			event.preventDefault();
   838 		});
   850 		});
   839 
   851 
   840 		// Set the selected visibility as current.
   852 		// Set the selected visibility as current.
   841 		$postVisibilitySelect.find('.save-post-visibility').click( function( event ) { // crazyhorse - multiple ok cancels
   853 		$postVisibilitySelect.find('.save-post-visibility').click( function( event ) { // Crazyhorse - multiple OK cancels.
       
   854 			var visibilityLabel = '', selectedVisibility = $postVisibilitySelect.find('input:radio:checked').val();
       
   855 
   842 			$postVisibilitySelect.slideUp('fast');
   856 			$postVisibilitySelect.slideUp('fast');
   843 			$('#visibility .edit-visibility').show().focus();
   857 			$('#visibility .edit-visibility').show().focus();
   844 			updateText();
   858 			updateText();
   845 
   859 
   846 			if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
   860 			if ( 'public' !== selectedVisibility ) {
   847 				$('#sticky').prop('checked', false);
   861 				$('#sticky').prop('checked', false);
   848 			}
   862 			}
   849 
   863 
   850 			if ( $('#sticky').prop('checked') ) {
   864 			switch ( selectedVisibility ) {
   851 				sticky = 'Sticky';
   865 				case 'public':
   852 			} else {
   866 					visibilityLabel = $( '#sticky' ).prop( 'checked' ) ? __( 'Public, Sticky' ) : __( 'Public' );
   853 				sticky = '';
   867 					break;
   854 			}
   868 				case 'private':
   855 
   869 					visibilityLabel = __( 'Private' );
   856 			$('#post-visibility-display').html(	postL10n[ $postVisibilitySelect.find('input:radio:checked').val() + sticky ]	);
   870 					break;
       
   871 				case 'password':
       
   872 					visibilityLabel = __( 'Password Protected' );
       
   873 					break;
       
   874 			}
       
   875 
       
   876 			$('#post-visibility-display').text( visibilityLabel );
   857 			event.preventDefault();
   877 			event.preventDefault();
   858 		});
   878 		});
   859 
   879 
   860 		// When the selection changes, update labels.
   880 		// When the selection changes, update labels.
   861 		$postVisibilitySelect.find('input:radio').change( function() {
   881 		$postVisibilitySelect.find('input:radio').change( function() {
   884 			updateText();
   904 			updateText();
   885 			event.preventDefault();
   905 			event.preventDefault();
   886 		});
   906 		});
   887 
   907 
   888 		// Save the changed timestamp.
   908 		// Save the changed timestamp.
   889 		$timestampdiv.find('.save-timestamp').click( function( event ) { // crazyhorse - multiple ok cancels
   909 		$timestampdiv.find('.save-timestamp').click( function( event ) { // Crazyhorse - multiple OK cancels.
   890 			if ( updateText() ) {
   910 			if ( updateText() ) {
   891 				$timestampdiv.slideUp('fast');
   911 				$timestampdiv.slideUp('fast');
   892 				$timestampdiv.siblings('a.edit-timestamp').show().focus();
   912 				$timestampdiv.siblings('a.edit-timestamp').show().focus();
   893 			}
   913 			}
   894 			event.preventDefault();
   914 			event.preventDefault();
   935 		});
   955 		});
   936 	}
   956 	}
   937 
   957 
   938 	/**
   958 	/**
   939 	 * Handle the editing of the post_name. Create the required HTML elements and
   959 	 * Handle the editing of the post_name. Create the required HTML elements and
   940 	 * update the changes via AJAX.
   960 	 * update the changes via Ajax.
   941 	 *
   961 	 *
   942 	 * @global
   962 	 * @global
   943 	 *
   963 	 *
   944 	 * @returns void
   964 	 * @return {void}
   945 	 */
   965 	 */
   946 	function editPermalink() {
   966 	function editPermalink() {
   947 		var i, slug_value,
   967 		var i, slug_value,
   948 			$el, revert_e,
   968 			$el, revert_e,
   949 			c = 0,
   969 			c = 0,
   964 
   984 
   965 		// Save current content to revert to when cancelling.
   985 		// Save current content to revert to when cancelling.
   966 		$el = $( '#editable-post-name' );
   986 		$el = $( '#editable-post-name' );
   967 		revert_e = $el.html();
   987 		revert_e = $el.html();
   968 
   988 
   969 		buttons.html( '<button type="button" class="save button button-small">' + postL10n.ok + '</button> <button type="button" class="cancel button-link">' + postL10n.cancel + '</button>' );
   989 		buttons.html( '<button type="button" class="save button button-small">' + __( 'OK' ) + '</button> <button type="button" class="cancel button-link">' + __( 'Cancel' ) + '</button>' );
   970 
   990 
   971 		// Save permalink changes.
   991 		// Save permalink changes.
   972 		buttons.children( '.save' ).click( function() {
   992 		buttons.children( '.save' ).click( function() {
   973 			var new_slug = $el.children( 'input' ).val();
   993 			var new_slug = $el.children( 'input' ).val();
   974 
   994 
   997 
  1017 
   998 					buttons.html(buttonsOrig);
  1018 					buttons.html(buttonsOrig);
   999 					permalink.html(permalinkOrig);
  1019 					permalink.html(permalinkOrig);
  1000 					real_slug.val(new_slug);
  1020 					real_slug.val(new_slug);
  1001 					$( '.edit-slug' ).focus();
  1021 					$( '.edit-slug' ).focus();
  1002 					wp.a11y.speak( postL10n.permalinkSaved );
  1022 					wp.a11y.speak( __( 'Permalink saved' ) );
  1003 				}
  1023 				}
  1004 			);
  1024 			);
  1005 		});
  1025 		});
  1006 
  1026 
  1007 		// Cancel editing of permalink.
  1027 		// Cancel editing of permalink.
  1021 		}
  1041 		}
  1022 		slug_value = ( c > full.length / 4 ) ? '' : full;
  1042 		slug_value = ( c > full.length / 4 ) ? '' : full;
  1023 
  1043 
  1024 		$el.html( '<input type="text" id="new-post-slug" value="' + slug_value + '" autocomplete="off" />' ).children( 'input' ).keydown( function( e ) {
  1044 		$el.html( '<input type="text" id="new-post-slug" value="' + slug_value + '" autocomplete="off" />' ).children( 'input' ).keydown( function( e ) {
  1025 			var key = e.which;
  1045 			var key = e.which;
  1026 			// On [enter], just save the new slug, don't save the post.
  1046 			// On [Enter], just save the new slug, don't save the post.
  1027 			if ( 13 === key ) {
  1047 			if ( 13 === key ) {
  1028 				e.preventDefault();
  1048 				e.preventDefault();
  1029 				buttons.children( '.save' ).click();
  1049 				buttons.children( '.save' ).click();
  1030 			}
  1050 			}
  1031 			// On [esc] cancel the editing.
  1051 			// On [Esc] cancel the editing.
  1032 			if ( 27 === key ) {
  1052 			if ( 27 === key ) {
  1033 				buttons.children( '.cancel' ).click();
  1053 				buttons.children( '.cancel' ).click();
  1034 			}
  1054 			}
  1035 		} ).keyup( function() {
  1055 		} ).keyup( function() {
  1036 			real_slug.val( this.value );
  1056 			real_slug.val( this.value );
  1049 	 *
  1069 	 *
  1050 	 * @param {string} id Optional. HTML ID to add the screen reader helper text to.
  1070 	 * @param {string} id Optional. HTML ID to add the screen reader helper text to.
  1051 	 *
  1071 	 *
  1052 	 * @global
  1072 	 * @global
  1053 	 *
  1073 	 *
  1054 	 * @returns void
  1074 	 * @return {void}
  1055 	 */
  1075 	 */
  1056 	window.wptitlehint = function( id ) {
  1076 	window.wptitlehint = function( id ) {
  1057 		id = id || 'title';
  1077 		id = id || 'title';
  1058 
  1078 
  1059 		var title = $( '#' + id ), titleprompt = $( '#' + id + '-prompt-text' );
  1079 		var title = $( '#' + id ), titleprompt = $( '#' + id + '-prompt-text' );
  1171 				editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format );
  1191 				editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format );
  1172 				$( document ).trigger( 'editor-classchange' );
  1192 				$( document ).trigger( 'editor-classchange' );
  1173 			}
  1193 			}
  1174 		});
  1194 		});
  1175 
  1195 
  1176 		// When changing page template, change the editor body class
  1196 		// When changing page template, change the editor body class.
  1177 		$( '#page_template' ).on( 'change.set-editor-class', function() {
  1197 		$( '#page_template' ).on( 'change.set-editor-class', function() {
  1178 			var editor, body, pageTemplate = $( this ).val() || '';
  1198 			var editor, body, pageTemplate = $( this ).val() || '';
  1179 
  1199 
  1180 			pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length )
  1200 			pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length )
  1181 				.replace( /\.php$/, '' )
  1201 				.replace( /\.php$/, '' )
  1189 			}
  1209 			}
  1190 		});
  1210 		});
  1191 
  1211 
  1192 	}
  1212 	}
  1193 
  1213 
  1194 	// Save on pressing [ctrl]/[command] + [s] in the Text editor.
  1214 	// Save on pressing [Ctrl]/[Command] + [S] in the Text editor.
  1195 	$textarea.on( 'keydown.wp-autosave', function( event ) {
  1215 	$textarea.on( 'keydown.wp-autosave', function( event ) {
  1196 		// Key [s] has code 83.
  1216 		// Key [S] has code 83.
  1197 		if ( event.which === 83 ) {
  1217 		if ( event.which === 83 ) {
  1198 			if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) {
  1218 			if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) {
  1199 				return;
  1219 				return;
  1200 			}
  1220 			}
  1201 
  1221 
  1214 			location += 'wp-post-new-reload=true';
  1234 			location += 'wp-post-new-reload=true';
  1215 
  1235 
  1216 			window.history.replaceState( null, null, location );
  1236 			window.history.replaceState( null, null, location );
  1217 		});
  1237 		});
  1218 	}
  1238 	}
  1219 });
  1239 
       
  1240 	/**
       
  1241 	 * Copies the attachment URL in the Edit Media page to the clipboard.
       
  1242 	 *
       
  1243 	 * @since 5.5.0
       
  1244 	 *
       
  1245 	 * @param {MouseEvent} event A click event.
       
  1246 	 *
       
  1247 	 * @return {void}
       
  1248 	 */
       
  1249 	copyAttachmentURLClipboard.on( 'success', function( event ) {
       
  1250 		var triggerElement = $( event.trigger ),
       
  1251 			successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
       
  1252 
       
  1253 		// Clear the selection and move focus back to the trigger.
       
  1254 		event.clearSelection();
       
  1255 		// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
       
  1256 		triggerElement.focus();
       
  1257 
       
  1258 		// Show success visual feedback.
       
  1259 		clearTimeout( copyAttachmentURLSuccessTimeout );
       
  1260 		successElement.removeClass( 'hidden' );
       
  1261 
       
  1262 		// Hide success visual feedback after 3 seconds since last success.
       
  1263 		copyAttachmentURLSuccessTimeout = setTimeout( function() {
       
  1264 			successElement.addClass( 'hidden' );
       
  1265 		}, 3000 );
       
  1266 
       
  1267 		// Handle success audible feedback.
       
  1268 		wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
       
  1269 	} );
       
  1270 } );
  1220 
  1271 
  1221 /**
  1272 /**
  1222  * TinyMCE word count display
  1273  * TinyMCE word count display
  1223  */
  1274  */
  1224 ( function( $, counter ) {
  1275 ( function( $, counter ) {