[ Index ]

PHP Cross Reference of WordPress

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


Generated: Sat Jul 4 01:00:03 2020 Cross-referenced by PHPXref 0.7.1