[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/js/ -> post.js (source)

   1  /**
   2   * @file Contains all dynamic functionality needed on post and term pages.
   3   *
   4   * @output wp-admin/js/post.js
   5   */
   6  
   7   /* global ajaxurl, wpAjax, postboxes, pagenow, tinymce, alert, deleteUserSetting, ClipboardJS */
   8   /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */
   9   /* global WPSetThumbnailHTML, wptitlehint */
  10  
  11  // Backward compatibility: prevent fatal errors.
  12  window.makeSlugeditClickable = window.editPermalink = function(){};
  13  
  14  // Make sure the wp object exists.
  15  window.wp = window.wp || {};
  16  
  17  /**
  18   * Handles the dynamic functionality needed on post and term pages.
  19   *
  20   * @param {JQueryStatic} $ The jQuery object.
  21   */
  22  ( function( $ ) {
  23      var titleHasFocus = false,
  24          __ = wp.i18n.__;
  25  
  26      /**
  27       * Control loading of comments on the post and term edit pages.
  28       *
  29       * @type {{st: number, get: commentsBox.get, load: commentsBox.load}}
  30       *
  31       * @namespace commentsBox
  32       */
  33      window.commentsBox = {
  34          // Comment offset to use when fetching new comments.
  35          st : 0,
  36  
  37          /**
  38           * Fetch comments using Ajax and display them in the box.
  39           *
  40           * @memberof commentsBox
  41           *
  42           * @param {number} total Total number of comments for this post.
  43           * @param {number} num   Optional. Number of comments to fetch, defaults to 10.
  44           * @return {boolean} Always returns false.
  45           */
  46          get : function(total, num) {
  47              var st = this.st, data;
  48              if ( ! num )
  49                  num = 10;
  50  
  51              this.st += num;
  52              this.total = total;
  53              $( '#commentsdiv .spinner' ).addClass( 'is-active' );
  54  
  55              data = {
  56                  'action' : 'get-comments',
  57                  'mode' : 'single',
  58                  '_ajax_nonce' : $('#add_comment_nonce').val(),
  59                  'p' : $('#post_ID').val(),
  60                  'start' : st,
  61                  'number' : num
  62              };
  63  
  64              $.post(
  65                  ajaxurl,
  66                  data,
  67                  function(r) {
  68                      r = wpAjax.parseAjaxResponse(r);
  69                      $('#commentsdiv .widefat').show();
  70                      $( '#commentsdiv .spinner' ).removeClass( 'is-active' );
  71  
  72                      if ( 'object' == typeof r && r.responses[0] ) {
  73                          $('#the-comment-list').append( r.responses[0].data );
  74  
  75                          theList = theExtraList = null;
  76                          $( 'a[className*=\':\']' ).off();
  77  
  78                          // If the offset is over the total number of comments we cannot fetch any more, so hide the button.
  79                          if ( commentsBox.st > commentsBox.total )
  80                              $('#show-comments').hide();
  81                          else
  82                              $('#show-comments').show().children('a').text( __( 'Show more comments' ) );
  83  
  84                          return;
  85                      } else if ( 1 == r ) {
  86                          $('#show-comments').text( __( 'No more comments found.' ) );
  87                          return;
  88                      }
  89  
  90                      $('#the-comment-list').append('<tr><td colspan="2">'+wpAjax.broken+'</td></tr>');
  91                  }
  92              );
  93  
  94              return false;
  95          },
  96  
  97          /**
  98           * Load the next batch of comments.
  99           *
 100           * @memberof commentsBox
 101           *
 102           * @param {number} total Total number of comments to load.
 103           */
 104          load: function(total){
 105              this.st = jQuery('#the-comment-list tr[id^="comment-"]:visible').length;
 106              this.get(total);
 107          }
 108      };
 109  
 110      /**
 111       * Overwrite the content of the Featured Image postbox
 112       *
 113       * @param {string} html New HTML to be displayed in the content area of the postbox.
 114       *
 115       * @global
 116       */
 117      window.WPSetThumbnailHTML = function(html){
 118          $('.inside', '#postimagediv').html(html);
 119      };
 120  
 121      /**
 122       * Set the Image ID of the Featured Image
 123       *
 124       * @param {number} id The post_id of the image to use as Featured Image.
 125       *
 126       * @global
 127       */
 128      window.WPSetThumbnailID = function(id){
 129          var field = $('input[value="_thumbnail_id"]', '#list-table');
 130          if ( field.length > 0 ) {
 131              $('#meta\\[' + field.attr('id').match(/[0-9]+/) + '\\]\\[value\\]').text(id);
 132          }
 133      };
 134  
 135      /**
 136       * Remove the Featured Image
 137       *
 138       * @param {string} nonce Nonce to use in the request.
 139       *
 140       * @global
 141       */
 142      window.WPRemoveThumbnail = function(nonce){
 143          $.post(
 144              ajaxurl, {
 145                  action: 'set-post-thumbnail',
 146                  post_id: $( '#post_ID' ).val(),
 147                  thumbnail_id: -1,
 148                  _ajax_nonce: nonce,
 149                  cookie: encodeURIComponent( document.cookie )
 150              },
 151              /**
 152               * Handle server response
 153               *
 154               * @param {string} str Response, will be '0' when an error occurred otherwise contains link to add Featured Image.
 155               */
 156              function(str){
 157                  if ( str == '0' ) {
 158                      alert( __( 'Could not set that as the thumbnail image. Try a different attachment.' ) );
 159                  } else {
 160                      WPSetThumbnailHTML(str);
 161                  }
 162              }
 163          );
 164      };
 165  
 166      /**
 167       * Heartbeat locks.
 168       *
 169       * Used to lock editing of an object by only one user at a time.
 170       *
 171       * When the user does not send a heartbeat in a heartbeat-time
 172       * the user is no longer editing and another user can start editing.
 173       */
 174      $(document).on( 'heartbeat-send.refresh-lock', function( e, data ) {
 175          var lock = $('#active_post_lock').val(),
 176              post_id = $('#post_ID').val(),
 177              send = {};
 178  
 179          if ( ! post_id || ! $('#post-lock-dialog').length )
 180              return;
 181  
 182          send.post_id = post_id;
 183  
 184          if ( lock )
 185              send.lock = lock;
 186  
 187          data['wp-refresh-post-lock'] = send;
 188  
 189      }).on( 'heartbeat-tick.refresh-lock', function( e, data ) {
 190          // Post locks: update the lock string or show the dialog if somebody has taken over editing.
 191          var received, wrap, avatar;
 192  
 193          if ( data['wp-refresh-post-lock'] ) {
 194              received = data['wp-refresh-post-lock'];
 195  
 196              if ( received.lock_error ) {
 197                  // Show "editing taken over" message.
 198                  wrap = $('#post-lock-dialog');
 199  
 200                  if ( wrap.length && ! wrap.is(':visible') ) {
 201                      if ( wp.autosave ) {
 202                          // Save the latest changes and disable.
 203                          $(document).one( 'heartbeat-tick', function() {
 204                              wp.autosave.server.suspend();
 205                              wrap.removeClass('saving').addClass('saved');
 206                              $(window).off( 'beforeunload.edit-post' );
 207                          });
 208  
 209                          wrap.addClass('saving');
 210                          wp.autosave.server.triggerSave();
 211                      }
 212  
 213                      if ( received.lock_error.avatar_src ) {
 214                          avatar = $( '<img />', {
 215                              'class': 'avatar avatar-64 photo',
 216                              width: 64,
 217                              height: 64,
 218                              alt: '',
 219                              src: received.lock_error.avatar_src,
 220                              srcset: received.lock_error.avatar_src_2x ?
 221                                  received.lock_error.avatar_src_2x + ' 2x' :
 222                                  undefined
 223                          } );
 224                          wrap.find('div.post-locked-avatar').empty().append( avatar );
 225                      }
 226  
 227                      wrap.show().find('.currently-editing').text( received.lock_error.text );
 228                      wrap.find('.wp-tab-first').trigger( 'focus' );
 229                  }
 230              } else if ( received.new_lock ) {
 231                  $('#active_post_lock').val( received.new_lock );
 232              }
 233          }
 234      }).on( 'before-autosave.update-post-slug', function() {
 235          titleHasFocus = document.activeElement && document.activeElement.id === 'title';
 236      }).on( 'after-autosave.update-post-slug', function() {
 237  
 238          /*
 239           * Create slug area only if not already there
 240           * and the title field was not focused (user was not typing a title) when autosave ran.
 241           */
 242          if ( ! $('#edit-slug-box > *').length && ! titleHasFocus ) {
 243              $.post( ajaxurl, {
 244                      action: 'sample-permalink',
 245                      post_id: $('#post_ID').val(),
 246                      new_title: $('#title').val(),
 247                      samplepermalinknonce: $('#samplepermalinknonce').val()
 248                  },
 249                  function( data ) {
 250                      if ( data != '-1' ) {
 251                          $('#edit-slug-box').html(data);
 252                      }
 253                  }
 254              );
 255          }
 256      });
 257  
 258  }(jQuery));
 259  
 260  /**
 261   * Handles the Heartbeat refresh nonces.
 262   *
 263   * @param {JQueryStatic} $ The jQuery object.
 264   */
 265  (function($) {
 266      var check, timeout;
 267  
 268      /**
 269       * Only allow to check for nonce refresh every 30 seconds.
 270       */
 271  	function schedule() {
 272          check = false;
 273          window.clearTimeout( timeout );
 274          timeout = window.setTimeout( function(){ check = true; }, 300000 );
 275      }
 276  
 277      $( function() {
 278          schedule();
 279      }).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) {
 280          var post_id,
 281              $authCheck = $('#wp-auth-check-wrap');
 282  
 283          if ( check || ( $authCheck.length && ! $authCheck.hasClass( 'hidden' ) ) ) {
 284              if ( ( post_id = $('#post_ID').val() ) && $('#_wpnonce').val() ) {
 285                  data['wp-refresh-post-nonces'] = {
 286                      post_id: post_id
 287                  };
 288              }
 289          }
 290      }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) {
 291          var nonces = data['wp-refresh-post-nonces'];
 292  
 293          if ( nonces ) {
 294              schedule();
 295  
 296              if ( nonces.replace ) {
 297                  $.each( nonces.replace, function( selector, value ) {
 298                      $( '#' + selector ).val( value );
 299                  });
 300              }
 301  
 302              if ( nonces.heartbeatNonce )
 303                  window.heartbeatSettings.nonce = nonces.heartbeatNonce;
 304          }
 305      });
 306  }(jQuery));
 307  
 308  /**
 309   * Handles all post and postbox controls and functionality.
 310   *
 311   * @param {JQueryStatic} $ The jQuery object.
 312   */
 313  jQuery( function($) {
 314      var stamp, visibility, $submitButtons, updateVisibility, updateText,
 315          $textarea = $('#content'),
 316          $document = $(document),
 317          postId = $('#post_ID').val() || 0,
 318          $submitpost = $('#submitpost'),
 319          releaseLock = true,
 320          $postVisibilitySelect = $('#post-visibility-select'),
 321          $timestampdiv = $('#timestampdiv'),
 322          $postStatusSelect = $('#post-status-select'),
 323          isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false,
 324          copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.edit-media' ),
 325          copyAttachmentURLSuccessTimeout,
 326          __ = wp.i18n.__, _x = wp.i18n._x;
 327  
 328      postboxes.add_postbox_toggles(pagenow);
 329  
 330      /*
 331       * Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post,
 332       * and the first post is still being edited, clicking Preview there will use this window to show the preview.
 333       */
 334      window.name = '';
 335  
 336      // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
 337      $('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) {
 338          // Don't do anything when [Tab] is pressed.
 339          if ( e.which != 9 )
 340              return;
 341  
 342          var target = $(e.target);
 343  
 344          // [Shift] + [Tab] on first tab cycles back to last tab.
 345          if ( target.hasClass('wp-tab-first') && e.shiftKey ) {
 346              $(this).find('.wp-tab-last').trigger( 'focus' );
 347              e.preventDefault();
 348          // [Tab] on last tab cycles back to first tab.
 349          } else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) {
 350              $(this).find('.wp-tab-first').trigger( 'focus' );
 351              e.preventDefault();
 352          }
 353      }).filter(':visible').find('.wp-tab-first').trigger( 'focus' );
 354  
 355      // Set the heartbeat interval to 10 seconds if post lock dialogs are enabled.
 356      if ( wp.heartbeat && $('#post-lock-dialog').length ) {
 357          wp.heartbeat.interval( 10 );
 358      }
 359  
 360      // The form is being submitted by the user.
 361      $submitButtons = $submitpost.find( ':submit, a.submitdelete, #post-preview' ).on( 'click.edit-post', function( event ) {
 362          var $button = $(this);
 363  
 364          if ( $button.hasClass('disabled') ) {
 365              event.preventDefault();
 366              return;
 367          }
 368  
 369          if ( $button.hasClass('submitdelete') || $button.is( '#post-preview' ) ) {
 370              return;
 371          }
 372  
 373          // The form submission can be blocked from JS or by using HTML 5.0 validation on some fields.
 374          // Run this only on an actual 'submit'.
 375          $('form#post').off( 'submit.edit-post' ).on( 'submit.edit-post', function( event ) {
 376              if ( event.isDefaultPrevented() ) {
 377                  return;
 378              }
 379  
 380              // Stop auto save.
 381              if ( wp.autosave ) {
 382                  wp.autosave.server.suspend();
 383              }
 384  
 385              if ( typeof commentReply !== 'undefined' ) {
 386                  /*
 387                   * Warn the user they have an unsaved comment before submitting
 388                   * the post data for update.
 389                   */
 390                  if ( ! commentReply.discardCommentChanges() ) {
 391                      return false;
 392                  }
 393  
 394                  /*
 395                   * Close the comment edit/reply form if open to stop the form
 396                   * action from interfering with the post's form action.
 397                   */
 398                  commentReply.close();
 399              }
 400  
 401              releaseLock = false;
 402              $(window).off( 'beforeunload.edit-post' );
 403  
 404              $submitButtons.addClass( 'disabled' );
 405  
 406              if ( $button.attr('id') === 'publish' ) {
 407                  $submitpost.find( '#major-publishing-actions .spinner' ).addClass( 'is-active' );
 408              } else {
 409                  $submitpost.find( '#minor-publishing .spinner' ).addClass( 'is-active' );
 410              }
 411          });
 412      });
 413  
 414      // Submit the form saving a draft or an autosave, and show a preview in a new tab.
 415      $('#post-preview').on( 'click.post-preview', function( event ) {
 416          var $this = $(this),
 417              $form = $('form#post'),
 418              $previewField = $('input#wp-preview'),
 419              target = $this.attr('target') || 'wp-preview',
 420              ua = navigator.userAgent.toLowerCase();
 421  
 422          event.preventDefault();
 423  
 424          if ( $this.hasClass('disabled') ) {
 425              return;
 426          }
 427  
 428          if ( wp.autosave ) {
 429              wp.autosave.server.tempBlockSave();
 430          }
 431  
 432          $previewField.val('dopreview');
 433          $form.attr( 'target', target ).trigger( 'submit' ).attr( 'target', '' );
 434  
 435          // Workaround for WebKit bug preventing a form submitting twice to the same action.
 436          // https://bugs.webkit.org/show_bug.cgi?id=28633
 437          if ( ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1 ) {
 438              $form.attr( 'action', function( index, value ) {
 439                  return value + '?t=' + ( new Date() ).getTime();
 440              });
 441          }
 442  
 443          $previewField.val('');
 444      });
 445  
 446      // Auto save new posts after a title is typed.
 447      if ( $( '#auto_draft' ).val() ) {
 448          $( '#title' ).on( 'blur', function() {
 449              var cancel;
 450  
 451              if ( ! this.value || $('#edit-slug-box > *').length ) {
 452                  return;
 453              }
 454  
 455              // Cancel the auto save when the blur was triggered by the user submitting the form.
 456              $('form#post').one( 'submit', function() {
 457                  cancel = true;
 458              });
 459  
 460              window.setTimeout( function() {
 461                  if ( ! cancel && wp.autosave ) {
 462                      wp.autosave.server.triggerSave();
 463                  }
 464              }, 200 );
 465          });
 466      }
 467  
 468      $document.on( 'autosave-disable-buttons.edit-post', function() {
 469          $submitButtons.addClass( 'disabled' );
 470      }).on( 'autosave-enable-buttons.edit-post', function() {
 471          if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {
 472              $submitButtons.removeClass( 'disabled' );
 473          }
 474      }).on( 'before-autosave.edit-post', function() {
 475          $( '.autosave-message' ).text( __( 'Saving Draft…' ) );
 476      }).on( 'after-autosave.edit-post', function( event, data ) {
 477          $( '.autosave-message' ).text( data.message );
 478  
 479          if ( $( document.body ).hasClass( 'post-new-php' ) ) {
 480              $( '.submitbox .submitdelete' ).show();
 481          }
 482      });
 483  
 484      /*
 485       * When the user is trying to load another page, or reloads current page
 486       * show a confirmation dialog when there are unsaved changes.
 487       */
 488      $( window ).on( 'beforeunload.edit-post', function( event ) {
 489          var editor  = window.tinymce && window.tinymce.get( 'content' );
 490          var changed = false;
 491  
 492          if ( wp.autosave ) {
 493              changed = wp.autosave.server.postChanged();
 494          } else if ( editor ) {
 495              changed = ( ! editor.isHidden() && editor.isDirty() );
 496          }
 497  
 498          if ( changed ) {
 499              event.preventDefault();
 500              // The return string is needed for browser compat.
 501              // See https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event.
 502              return __( 'The changes you made will be lost if you navigate away from this page.' );
 503          }
 504      }).on( 'pagehide.edit-post', function( event ) {
 505          if ( ! releaseLock ) {
 506              return;
 507          }
 508  
 509          /*
 510           * Unload is triggered (by hand) on removing the Thickbox iframe.
 511           * Make sure we process only the main document unload.
 512           */
 513          if ( event.target && event.target.nodeName != '#document' ) {
 514              return;
 515          }
 516  
 517          var postID = $('#post_ID').val();
 518          var postLock = $('#active_post_lock').val();
 519  
 520          if ( ! postID || ! postLock ) {
 521              return;
 522          }
 523  
 524          var data = {
 525              action: 'wp-remove-post-lock',
 526              _wpnonce: $('#_wpnonce').val(),
 527              post_ID: postID,
 528              active_post_lock: postLock
 529          };
 530  
 531          if ( window.FormData && window.navigator.sendBeacon ) {
 532              var formData = new window.FormData();
 533  
 534              $.each( data, function( key, value ) {
 535                  formData.append( key, value );
 536              });
 537  
 538              if ( window.navigator.sendBeacon( ajaxurl, formData ) ) {
 539                  return;
 540              }
 541          }
 542  
 543          // Fall back to a synchronous POST request.
 544          // See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
 545          $.post({
 546              async: false,
 547              data: data,
 548              url: ajaxurl
 549          });
 550      });
 551  
 552      // Multiple taxonomies.
 553      if ( $('#tagsdiv-post_tag').length ) {
 554          window.tagBox && window.tagBox.init();
 555      } else {
 556          $('.meta-box-sortables').children('div.postbox').each(function(){
 557              if ( this.id.indexOf('tagsdiv-') === 0 ) {
 558                  window.tagBox && window.tagBox.init();
 559                  return false;
 560              }
 561          });
 562      }
 563  
 564      // Handle categories.
 565      $('.categorydiv').each( function(){
 566          var this_id = $(this).attr('id'), catAddBefore, catAddAfter, taxonomyParts, taxonomy, settingName;
 567  
 568          taxonomyParts = this_id.split('-');
 569          taxonomyParts.shift();
 570          taxonomy = taxonomyParts.join('-');
 571          settingName = taxonomy + '_tab';
 572  
 573          if ( taxonomy == 'category' ) {
 574              settingName = 'cats';
 575          }
 576  
 577          // @todo Move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js.
 578          $('a', '#' + taxonomy + '-tabs').on( 'click keyup keydown', function( event ) {
 579              var t = $(this).attr('href');
 580              if ( event.type === 'keydown' && event.key === ' ' ) {
 581                  event.preventDefault();
 582              }
 583              if ( ( event.type === 'keyup' && event.key === ' ' ) || ( event.type === 'keydown' && event.key === 'Enter' ) || event.type === 'click' ) {
 584                  event.preventDefault();
 585                  $('#' + taxonomy + '-tabs a').removeAttr( 'aria-selected' ).attr( 'tabindex', '-1' );
 586                  $(this).attr( 'aria-selected', 'true' ).removeAttr( 'tabindex' );
 587                  $(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
 588                  $('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide();
 589                  $(t).show();
 590                  if ( '#' + taxonomy + '-all' == t ) {
 591                      deleteUserSetting( settingName );
 592                  } else {
 593                      setUserSetting( settingName, 'pop' );
 594                  }
 595              }
 596              if ( event.type === 'keyup' && ( event.key === 'ArrowRight' || event.key === 'ArrowLeft' ) ) {
 597                  $(this).attr( 'tabindex', '-1' );
 598                  let next = $(this).parent('li').next();
 599                  let prev = $(this).parent('li').prev();
 600                  if ( next.length > 0 ) {
 601                      next.find('a').removeAttr( 'tabindex');
 602                      next.find('a').trigger( 'focus' );
 603                  } else {
 604                      prev.find('a').removeAttr( 'tabindex');
 605                      prev.find('a').trigger( 'focus' );
 606                  }
 607              }
 608          });
 609  
 610          if ( getUserSetting( settingName ) )
 611              $('a[href="#' + taxonomy + '-pop"]', '#' + taxonomy + '-tabs').trigger( 'click' );
 612  
 613          // Add category button controls.
 614          $('#new' + taxonomy).one( 'focus', function() {
 615              $( this ).val( '' ).removeClass( 'form-input-tip' );
 616          });
 617  
 618          // On [Enter] submit the taxonomy.
 619          $('#new' + taxonomy).on( 'keypress', function(event){
 620              if( 13 === event.keyCode ) {
 621                  event.preventDefault();
 622                  $('#' + taxonomy + '-add-submit').trigger( 'click' );
 623              }
 624          });
 625  
 626          // After submitting a new taxonomy, re-focus the input field.
 627          $('#' + taxonomy + '-add-submit').on( 'click', function() {
 628              $('#new' + taxonomy).trigger( 'focus' );
 629          });
 630  
 631          /**
 632           * Disables the submit button before adding a new taxonomy.
 633           *
 634           * @param {Object} s Taxonomy object which will be added.
 635           *
 636           * @return {Object} Taxonomy object with additional data to be sent to the server.
 637           */
 638          catAddBefore = function( s ) {
 639              if ( !$('#new'+taxonomy).val() ) {
 640                  return false;
 641              }
 642  
 643              s.data += '&' + $( ':checked', '#'+taxonomy+'checklist' ).serialize();
 644              $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', true );
 645              return s;
 646          };
 647  
 648          /**
 649           * Re-enable submit button after a taxonomy has been added.
 650           *
 651           * Re-enable submit button.
 652           * If the taxonomy has a parent place the taxonomy underneath the parent.
 653           *
 654           * @param {Object} r Response.
 655           * @param {Object} s Taxonomy data.
 656           *
 657           * @return {void}
 658           */
 659          catAddAfter = function( r, s ) {
 660              var sup, drop = $('#new'+taxonomy+'_parent');
 661  
 662              $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false );
 663              if ( 'undefined' != s.parsed.responses[0] && (sup = s.parsed.responses[0].supplemental.newcat_parent) ) {
 664                  drop.before(sup);
 665                  drop.remove();
 666              }
 667          };
 668  
 669          $('#' + taxonomy + 'checklist').wpList({
 670              alt: '',
 671              response: taxonomy + '-ajax-response',
 672              addBefore: catAddBefore,
 673              addAfter: catAddAfter
 674          });
 675  
 676          // Add new taxonomy button toggles input form visibility.
 677          $('#' + taxonomy + '-add-toggle').on( 'click', function( e ) {
 678              e.preventDefault();
 679              $('#' + taxonomy + '-adder').toggleClass( 'wp-hidden-children' );
 680              $('a[href="#' + taxonomy + '-all"]', '#' + taxonomy + '-tabs').trigger( 'click' );
 681              $('#new'+taxonomy).trigger( 'focus' );
 682          });
 683  
 684          // Sync checked items between "All {taxonomy}" and "Most used" lists.
 685          $('#' + taxonomy + 'checklist, #' + taxonomy + 'checklist-pop').on(
 686              'click',
 687              'li.popular-category > label input[type="checkbox"]',
 688              function() {
 689                  var t = $(this), c = t.is(':checked'), id = t.val();
 690                  if ( id && t.parents('#taxonomy-'+taxonomy).length ) {
 691                      $('input#in-' + taxonomy + '-' + id + ', input[id^="in-' + taxonomy + '-' + id + '-"]').prop('checked', c);
 692                      $('input#in-popular-' + taxonomy + '-' + id).prop('checked', c);
 693                  }
 694              }
 695          );
 696  
 697      }); // End cats.
 698  
 699      // Custom Fields postbox.
 700      if ( $('#postcustom').length ) {
 701          $( '#the-list' ).wpList( {
 702              /**
 703               * Add current post_ID to request to fetch custom fields
 704               *
 705               * @ignore
 706               *
 707               * @param {Object} s Request object.
 708               *
 709               * @return {Object} Data modified with post_ID attached.
 710               */
 711              addBefore: function( s ) {
 712                  s.data += '&post_id=' + $('#post_ID').val();
 713                  return s;
 714              },
 715              /**
 716               * Show the listing of custom fields after fetching.
 717               *
 718               * @ignore
 719               */
 720              addAfter: function() {
 721                  $('table#list-table').show();
 722              }
 723          });
 724      }
 725  
 726      /*
 727       * Publish Post box (#submitdiv)
 728       */
 729      if ( $('#submitdiv').length ) {
 730          stamp = $('#timestamp').html();
 731          visibility = $('#post-visibility-display').html();
 732  
 733          /**
 734           * When the visibility of a post changes sub-options should be shown or hidden.
 735           *
 736           * @ignore
 737           *
 738           * @return {void}
 739           */
 740          updateVisibility = function() {
 741              // Show sticky for public posts.
 742              if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
 743                  $('#sticky').prop('checked', false);
 744                  $('#sticky-span').hide();
 745              } else {
 746                  $('#sticky-span').show();
 747              }
 748  
 749              // Show password input field for password protected post.
 750              if ( $postVisibilitySelect.find('input:radio:checked').val() != 'password' ) {
 751                  $('#password-span').hide();
 752              } else {
 753                  $('#password-span').show();
 754              }
 755          };
 756  
 757          /**
 758           * Make sure all labels represent the current settings.
 759           *
 760           * @ignore
 761           *
 762           * @return {boolean} False when an invalid timestamp has been selected, otherwise True.
 763           */
 764          updateText = function() {
 765  
 766              if ( ! $timestampdiv.length )
 767                  return true;
 768  
 769              var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'),
 770                  optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(),
 771                  mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val();
 772  
 773              attemptedDate = new Date( aa, mm - 1, jj, hh, mn );
 774              originalDate = new Date(
 775                  $('#hidden_aa').val(),
 776                  $('#hidden_mm').val() -1,
 777                  $('#hidden_jj').val(),
 778                  $('#hidden_hh').val(),
 779                  $('#hidden_mn').val()
 780              );
 781              currentDate = new Date(
 782                  $('#cur_aa').val(),
 783                  $('#cur_mm').val() -1,
 784                  $('#cur_jj').val(),
 785                  $('#cur_hh').val(),
 786                  $('#cur_mn').val()
 787              );
 788  
 789              // Catch unexpected date problems.
 790              if (
 791                  attemptedDate.getFullYear() != aa ||
 792                  (1 + attemptedDate.getMonth()) != mm ||
 793                  attemptedDate.getDate() != jj ||
 794                  attemptedDate.getMinutes() != mn
 795              ) {
 796                  $timestampdiv.find('.timestamp-wrap').addClass('form-invalid');
 797                  return false;
 798              } else {
 799                  $timestampdiv.find('.timestamp-wrap').removeClass('form-invalid');
 800              }
 801  
 802              // Determine what the publish should be depending on the date and post status.
 803              if ( attemptedDate > currentDate ) {
 804                  publishOn = __( 'Schedule for:' );
 805                  $('#publish').val( _x( 'Schedule', 'post action/button label' ) );
 806              } else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) {
 807                  publishOn = __( 'Publish on:' );
 808                  $('#publish').val( __( 'Publish' ) );
 809              } else {
 810                  publishOn = __( 'Published on:' );
 811                  $('#publish').val( __( 'Update' ) );
 812              }
 813  
 814              // If the date is the same, set it to trigger update events.
 815              if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) {
 816                  // Re-set to the current value.
 817                  $('#timestamp').html(stamp);
 818              } else {
 819                  $('#timestamp').html(
 820                      '\n' + publishOn + ' <b>' +
 821                      // translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute.
 822                      __( '%1$s %2$s, %3$s at %4$s:%5$s' )
 823                          .replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) )
 824                          .replace( '%2$s', parseInt( jj, 10 ) )
 825                          .replace( '%3$s', aa )
 826                          .replace( '%4$s', ( '00' + hh ).slice( -2 ) )
 827                          .replace( '%5$s', ( '00' + mn ).slice( -2 ) ) +
 828                          '</b> '
 829                  );
 830              }
 831  
 832              // Add "privately published" to post status when applies.
 833              if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) {
 834                  $('#publish').val( __( 'Update' ) );
 835                  if ( 0 === optPublish.length ) {
 836                      postStatus.append('<option value="publish">' + __( 'Privately Published' ) + '</option>');
 837                  } else {
 838                      optPublish.html( __( 'Privately Published' ) );
 839                  }
 840                  $('option[value="publish"]', postStatus).prop('selected', true);
 841                  $('#misc-publishing-actions .edit-post-status').hide();
 842              } else {
 843                  if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
 844                      if ( optPublish.length ) {
 845                          optPublish.remove();
 846                          postStatus.val($('#hidden_post_status').val());
 847                      }
 848                  } else {
 849                      optPublish.html( __( 'Published' ) );
 850                  }
 851                  if ( postStatus.is(':hidden') )
 852                      $('#misc-publishing-actions .edit-post-status').show();
 853              }
 854  
 855              // Update "Status:" to currently selected status.
 856              $('#post-status-display').text(
 857                  // Remove any potential tags from post status text.
 858                  wp.sanitize.stripTagsAndEncodeText( $('option:selected', postStatus).text() )
 859              );
 860  
 861              // Show or hide the "Save Draft" button.
 862              if (
 863                  $('option:selected', postStatus).val() == 'private' ||
 864                  $('option:selected', postStatus).val() == 'publish'
 865              ) {
 866                  $('#save-post').hide();
 867              } else {
 868                  $('#save-post').show();
 869                  if ( $('option:selected', postStatus).val() == 'pending' ) {
 870                      $('#save-post').show().val( __( 'Save as Pending' ) );
 871                  } else {
 872                      $('#save-post').show().val( __( 'Save Draft' ) );
 873                  }
 874              }
 875              return true;
 876          };
 877  
 878          // Show the visibility options and hide the toggle button when opened.
 879          $( '#visibility .edit-visibility').on( 'click', function( e ) {
 880              e.preventDefault();
 881              if ( $postVisibilitySelect.is(':hidden') ) {
 882                  updateVisibility();
 883                  $postVisibilitySelect.slideDown( 'fast', function() {
 884                      $postVisibilitySelect.find( 'input[type="radio"]' ).first().trigger( 'focus' );
 885                  } );
 886                  $(this).hide();
 887              }
 888          });
 889  
 890          // Cancel visibility selection area and hide it from view.
 891          $postVisibilitySelect.find('.cancel-post-visibility').on( 'click', function( event ) {
 892              $postVisibilitySelect.slideUp('fast');
 893              $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true);
 894              $('#post_password').val($('#hidden-post-password').val());
 895              $('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked'));
 896              $('#post-visibility-display').html(visibility);
 897              $('#visibility .edit-visibility').show().trigger( 'focus' );
 898              updateText();
 899              event.preventDefault();
 900          });
 901  
 902          // Set the selected visibility as current.
 903          $postVisibilitySelect.find('.save-post-visibility').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels.
 904              var visibilityLabel = '', selectedVisibility = $postVisibilitySelect.find('input:radio:checked').val();
 905  
 906              $postVisibilitySelect.slideUp('fast');
 907              $('#visibility .edit-visibility').show().trigger( 'focus' );
 908              updateText();
 909  
 910              if ( 'public' !== selectedVisibility ) {
 911                  $('#sticky').prop('checked', false);
 912              }
 913  
 914              switch ( selectedVisibility ) {
 915                  case 'public':
 916                      visibilityLabel = $( '#sticky' ).prop( 'checked' ) ? __( 'Public, Sticky' ) : __( 'Public' );
 917                      break;
 918                  case 'private':
 919                      visibilityLabel = __( 'Private' );
 920                      break;
 921                  case 'password':
 922                      visibilityLabel = __( 'Password Protected' );
 923                      break;
 924              }
 925  
 926              $('#post-visibility-display').text( visibilityLabel );
 927              event.preventDefault();
 928          });
 929  
 930          // When the selection changes, update labels.
 931          $postVisibilitySelect.find('input:radio').on( 'change', function() {
 932              updateVisibility();
 933          });
 934  
 935          // Edit publish time click.
 936          $timestampdiv.siblings('a.edit-timestamp').on( 'click', function( event ) {
 937              if ( $timestampdiv.is( ':hidden' ) ) {
 938                  $timestampdiv.slideDown( 'fast', function() {
 939                      $( 'input, select', $timestampdiv.find( '.timestamp-wrap' ) ).first().trigger( 'focus' );
 940                  } );
 941                  $(this).hide();
 942              }
 943              event.preventDefault();
 944          });
 945  
 946          // Cancel editing the publish time and hide the settings.
 947          $timestampdiv.find('.cancel-timestamp').on( 'click', function( event ) {
 948              $timestampdiv.slideUp('fast').siblings('a.edit-timestamp').show().trigger( 'focus' );
 949              $('#mm').val($('#hidden_mm').val());
 950              $('#jj').val($('#hidden_jj').val());
 951              $('#aa').val($('#hidden_aa').val());
 952              $('#hh').val($('#hidden_hh').val());
 953              $('#mn').val($('#hidden_mn').val());
 954              updateText();
 955              event.preventDefault();
 956          });
 957  
 958          // Save the changed timestamp.
 959          $timestampdiv.find('.save-timestamp').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels.
 960              if ( updateText() ) {
 961                  $timestampdiv.slideUp('fast');
 962                  $timestampdiv.siblings('a.edit-timestamp').show().trigger( 'focus' );
 963              }
 964              event.preventDefault();
 965          });
 966  
 967          // Cancel submit when an invalid timestamp has been selected.
 968          $('#post').on( 'submit', function( event ) {
 969              if ( ! updateText() ) {
 970                  event.preventDefault();
 971                  $timestampdiv.show();
 972  
 973                  if ( wp.autosave ) {
 974                      wp.autosave.enableButtons();
 975                  }
 976  
 977                  $( '#publishing-action .spinner' ).removeClass( 'is-active' );
 978              }
 979          });
 980  
 981          // Post Status edit click.
 982          $postStatusSelect.siblings('a.edit-post-status').on( 'click', function( event ) {
 983              if ( $postStatusSelect.is( ':hidden' ) ) {
 984                  $postStatusSelect.slideDown( 'fast', function() {
 985                      $postStatusSelect.find('select').trigger( 'focus' );
 986                  } );
 987                  $(this).hide();
 988              }
 989              event.preventDefault();
 990          });
 991  
 992          // Save the Post Status changes and hide the options.
 993          $postStatusSelect.find('.save-post-status').on( 'click', function( event ) {
 994              $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().trigger( 'focus' );
 995              updateText();
 996              event.preventDefault();
 997          });
 998  
 999          // Cancel Post Status editing and hide the options.
1000          $postStatusSelect.find('.cancel-post-status').on( 'click', function( event ) {
1001              $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().trigger( 'focus' );
1002              $('#post_status').val( $('#hidden_post_status').val() );
1003              updateText();
1004              event.preventDefault();
1005          });
1006      }
1007  
1008      /**
1009       * Handle the editing of the post_name. Create the required HTML elements and
1010       * update the changes via Ajax.
1011       *
1012       * @global
1013       *
1014       * @return {void}
1015       */
1016  	function editPermalink() {
1017          var i, slug_value, slug_label,
1018              $el, revert_e,
1019              c = 0,
1020              real_slug = $('#post_name'),
1021              revert_slug = real_slug.val(),
1022              permalink = $( '#sample-permalink' ),
1023              permalinkOrig = permalink.html(),
1024              permalinkInner = $( '#sample-permalink a' ).html(),
1025              buttons = $('#edit-slug-buttons'),
1026              buttonsOrig = buttons.html(),
1027              full = $('#editable-post-name-full');
1028  
1029          // Deal with Twemoji in the post-name.
1030          full.find( 'img' ).replaceWith( function() { return this.alt; } );
1031          full = full.html();
1032  
1033          permalink.html( permalinkInner );
1034  
1035          // Save current content to revert to when cancelling.
1036          $el = $( '#editable-post-name' );
1037          revert_e = $el.html();
1038  
1039          buttons.html(
1040              '<button type="button" class="save button button-compact">' + __( 'OK' ) + '</button> ' +
1041              '<button type="button" class="cancel button-link">' + __( 'Cancel' ) + '</button>'
1042          );
1043  
1044          // Save permalink changes.
1045          buttons.children( '.save' ).on( 'click', function() {
1046              var new_slug = $el.children( 'input' ).val();
1047  
1048              if ( new_slug == $('#editable-post-name-full').text() ) {
1049                  buttons.children('.cancel').trigger( 'click' );
1050                  return;
1051              }
1052  
1053              $.post(
1054                  ajaxurl,
1055                  {
1056                      action: 'sample-permalink',
1057                      post_id: postId,
1058                      new_slug: new_slug,
1059                      new_title: $('#title').val(),
1060                      samplepermalinknonce: $('#samplepermalinknonce').val()
1061                  },
1062                  function(data) {
1063                      var box = $('#edit-slug-box');
1064                      box.html(data);
1065                      if (box.hasClass('hidden')) {
1066                          box.fadeIn('fast', function () {
1067                              box.removeClass('hidden');
1068                          });
1069                      }
1070  
1071                      buttons.html(buttonsOrig);
1072                      permalink.html(permalinkOrig);
1073                      real_slug.val(new_slug);
1074                      $( '.edit-slug' ).trigger( 'focus' );
1075                      wp.a11y.speak( __( 'Permalink saved' ) );
1076                  }
1077              );
1078          });
1079  
1080          // Cancel editing of permalink.
1081          buttons.children( '.cancel' ).on( 'click', function() {
1082              $('#view-post-btn').show();
1083              $el.html(revert_e);
1084              buttons.html(buttonsOrig);
1085              permalink.html(permalinkOrig);
1086              real_slug.val(revert_slug);
1087              $( '.edit-slug' ).trigger( 'focus' );
1088          });
1089  
1090          // If more than 1/4th of 'full' is '%', make it empty.
1091          for ( i = 0; i < full.length; ++i ) {
1092              if ( '%' == full.charAt(i) )
1093                  c++;
1094          }
1095          slug_value = ( c > full.length / 4 ) ? '' : full;
1096          slug_label = __( 'URL Slug' );
1097  
1098          $el.html(
1099              '<label for="new-post-slug" class="screen-reader-text">' + slug_label + '</label>' +
1100              '<input type="text" id="new-post-slug" value="' + slug_value + '" autocomplete="off" spellcheck="false" />'
1101          ).children( 'input' ).on( 'keydown', function( e ) {
1102              var key = e.which;
1103              // On [Enter], just save the new slug, don't save the post.
1104              if ( 13 === key ) {
1105                  e.preventDefault();
1106                  buttons.children( '.save' ).trigger( 'click' );
1107              }
1108              // On [Esc] cancel the editing.
1109              if ( 27 === key ) {
1110                  buttons.children( '.cancel' ).trigger( 'click' );
1111              }
1112          } ).on( 'keyup', function() {
1113              real_slug.val( this.value );
1114          }).trigger( 'focus' );
1115      }
1116  
1117      $( '#titlediv' ).on( 'click', '.edit-slug', function() {
1118          editPermalink();
1119      });
1120  
1121      /**
1122       * Adds screen reader text to the title label when needed.
1123       *
1124       * Use the 'screen-reader-text' class to emulate a placeholder attribute
1125       * and hide the label when entering a value.
1126       *
1127       * @param {string} id Optional. HTML ID to add the screen reader helper text to.
1128       *
1129       * @global
1130       *
1131       * @return {void}
1132       */
1133      window.wptitlehint = function( id ) {
1134          id = id || 'title';
1135  
1136          var title = $( '#' + id ), titleprompt = $( '#' + id + '-prompt-text' );
1137  
1138          if ( '' === title.val() ) {
1139              titleprompt.removeClass( 'screen-reader-text' );
1140          }
1141  
1142          title.on( 'input', function() {
1143              if ( '' === this.value ) {
1144                  titleprompt.removeClass( 'screen-reader-text' );
1145                  return;
1146              }
1147  
1148              titleprompt.addClass( 'screen-reader-text' );
1149          } );
1150      };
1151  
1152      wptitlehint();
1153  
1154      // Resize the WYSIWYG and plain text editors.
1155      ( function() {
1156          var editor, offset, mce,
1157              $handle = $('#post-status-info'),
1158              $postdivrich = $('#postdivrich');
1159  
1160          // If there are no textareas or we are on a touch device, we can't do anything.
1161          if ( ! $textarea.length || 'ontouchstart' in window ) {
1162              // Hide the resize handle.
1163              $('#content-resize-handle').hide();
1164              return;
1165          }
1166  
1167          /**
1168           * Handle drag event.
1169           *
1170           * @param {Object} event Event containing details about the drag.
1171           */
1172  		function dragging( event ) {
1173              if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
1174                  return;
1175              }
1176  
1177              if ( mce ) {
1178                  editor.theme.resizeTo( null, offset + event.pageY );
1179              } else {
1180                  $textarea.height( Math.max( 50, offset + event.pageY ) );
1181              }
1182  
1183              event.preventDefault();
1184          }
1185  
1186          /**
1187           * When the dragging stopped make sure we return focus and do a confidence check on the height.
1188           */
1189  		function endDrag() {
1190              var height, toolbarHeight;
1191  
1192              if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
1193                  return;
1194              }
1195  
1196              if ( mce ) {
1197                  editor.focus();
1198                  toolbarHeight = parseInt( $( '#wp-content-editor-container .mce-toolbar-grp' ).height(), 10 );
1199  
1200                  if ( toolbarHeight < 10 || toolbarHeight > 200 ) {
1201                      toolbarHeight = 30;
1202                  }
1203  
1204                  height = parseInt( $('#content_ifr').css('height'), 10 ) + toolbarHeight - 28;
1205              } else {
1206                  $textarea.trigger( 'focus' );
1207                  height = parseInt( $textarea.css('height'), 10 );
1208              }
1209  
1210              $document.off( '.wp-editor-resize' );
1211  
1212              // Confidence check: normalize height to stay within acceptable ranges.
1213              if ( height && height > 50 && height < 5000 ) {
1214                  setUserSetting( 'ed_size', height );
1215              }
1216          }
1217  
1218          $handle.on( 'mousedown.wp-editor-resize', function( event ) {
1219              if ( typeof tinymce !== 'undefined' ) {
1220                  editor = tinymce.get('content');
1221              }
1222  
1223              if ( editor && ! editor.isHidden() ) {
1224                  mce = true;
1225                  offset = $('#content_ifr').height() - event.pageY;
1226              } else {
1227                  mce = false;
1228                  offset = $textarea.height() - event.pageY;
1229                  $textarea.trigger( 'blur' );
1230              }
1231  
1232              $document.on( 'mousemove.wp-editor-resize', dragging )
1233                  .on( 'mouseup.wp-editor-resize mouseleave.wp-editor-resize', endDrag );
1234  
1235              event.preventDefault();
1236          }).on( 'mouseup.wp-editor-resize', endDrag );
1237      })();
1238  
1239      // TinyMCE specific handling of Post Format changes to reflect in the editor.
1240      if ( typeof tinymce !== 'undefined' ) {
1241          // When changing post formats, change the editor body class.
1242          $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() {
1243              var editor, body, format = this.id;
1244  
1245              if ( format && $( this ).prop( 'checked' ) && ( editor = tinymce.get( 'content' ) ) ) {
1246                  body = editor.getBody();
1247                  body.className = body.className.replace( /\bpost-format-[^ ]+/, '' );
1248                  editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format );
1249                  $( document ).trigger( 'editor-classchange' );
1250              }
1251          });
1252  
1253          // When changing page template, change the editor body class.
1254          $( '#page_template' ).on( 'change.set-editor-class', function() {
1255              var editor, body, pageTemplate = $( this ).val() || '';
1256  
1257              pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length )
1258                  .replace( /\.php$/, '' )
1259                  .replace( /\./g, '-' );
1260  
1261              if ( pageTemplate && ( editor = tinymce.get( 'content' ) ) ) {
1262                  body = editor.getBody();
1263                  body.className = body.className.replace( /\bpage-template-[^ ]+/, '' );
1264                  editor.dom.addClass( body, 'page-template-' + pageTemplate );
1265                  $( document ).trigger( 'editor-classchange' );
1266              }
1267          });
1268  
1269      }
1270  
1271      // Save on pressing [Ctrl]/[Command] + [S] in the Text editor.
1272      $textarea.on( 'keydown.wp-autosave', function( event ) {
1273          // Key [S] has code 83.
1274          if ( event.which === 83 ) {
1275              if (
1276                  event.shiftKey ||
1277                  event.altKey ||
1278                  ( isMac && ( ! event.metaKey || event.ctrlKey ) ) ||
1279                  ( ! isMac && ! event.ctrlKey )
1280              ) {
1281                  return;
1282              }
1283  
1284              wp.autosave && wp.autosave.server.triggerSave();
1285              event.preventDefault();
1286          }
1287      });
1288  
1289      // If the last status was auto-draft and the save is triggered, edit the current URL.
1290      if ( $( '#original_post_status' ).val() === 'auto-draft' && window.history.replaceState ) {
1291          var location;
1292  
1293          $( '#publish' ).on( 'click', function() {
1294              location = window.location.href;
1295              location += ( location.indexOf( '?' ) !== -1 ) ? '&' : '?';
1296              location += 'wp-post-new-reload=true';
1297  
1298              window.history.replaceState( null, null, location );
1299          });
1300      }
1301  
1302      /**
1303       * Copies the attachment URL in the Edit Media page to the clipboard.
1304       *
1305       * @since 5.5.0
1306       *
1307       * @param {MouseEvent} event A click event.
1308       *
1309       * @return {void}
1310       */
1311      copyAttachmentURLClipboard.on( 'success', function( event ) {
1312          var triggerElement = $( event.trigger ),
1313              successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
1314  
1315          // Clear the selection and move focus back to the trigger.
1316          event.clearSelection();
1317  
1318          // Show success visual feedback.
1319          clearTimeout( copyAttachmentURLSuccessTimeout );
1320          successElement.removeClass( 'hidden' );
1321  
1322          // Hide success visual feedback after 3 seconds since last success.
1323          copyAttachmentURLSuccessTimeout = setTimeout( function() {
1324              successElement.addClass( 'hidden' );
1325          }, 3000 );
1326  
1327          // Handle success audible feedback.
1328          wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
1329      } );
1330  } );
1331  
1332  /**
1333   * Handles the TinyMCE word count display.
1334   *
1335   * @param {JQueryStatic}         $       The jQuery object.
1336   * @param {wp.utils.WordCounter} counter The WordCounter object.
1337   */
1338  ( function( $, counter ) {
1339      $( function() {
1340          var $content = $( '#content' ),
1341              $count = $( '#wp-word-count' ).find( '.word-count' ),
1342              prevCount = 0,
1343              contentEditor;
1344  
1345          /**
1346           * Get the word count from TinyMCE and display it
1347           */
1348  		function update() {
1349              var text, count;
1350  
1351              if ( ! contentEditor || contentEditor.isHidden() ) {
1352                  text = $content.val();
1353              } else {
1354                  text = contentEditor.getContent( { format: 'raw' } );
1355              }
1356  
1357              count = counter.count( text );
1358  
1359              if ( count !== prevCount ) {
1360                  $count.text( count );
1361              }
1362  
1363              prevCount = count;
1364          }
1365  
1366          /**
1367           * Bind the word count update triggers.
1368           *
1369           * When a node change in the main TinyMCE editor has been triggered.
1370           * When a key has been released in the plain text content editor.
1371           */
1372          $( document ).on( 'tinymce-editor-init', function( event, editor ) {
1373              if ( editor.id !== 'content' ) {
1374                  return;
1375              }
1376  
1377              contentEditor = editor;
1378  
1379              editor.on( 'nodechange keyup', _.debounce( update, 1000 ) );
1380          } );
1381  
1382          $content.on( 'input keyup', _.debounce( update, 1000 ) );
1383  
1384          update();
1385      } );
1386  
1387  } )( jQuery, new wp.utils.WordCounter() );


Generated : Fri Sep 18 08:20:28 2026 Cross-referenced by PHPXref