[ 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 */
   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           * @returns {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           * @param {int} total Total number of comments to load.
  95           *
  96           * @memberof commentsBox
  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  
 302      postboxes.add_postbox_toggles(pagenow);
 303  
 304      /*
 305       * Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post,
 306       * and the first post is still being edited, clicking Preview there will use this window to show the preview.
 307       */
 308      window.name = '';
 309  
 310      // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
 311      $('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) {
 312          // Don't do anything when [tab] is pressed.
 313          if ( e.which != 9 )
 314              return;
 315  
 316          var target = $(e.target);
 317  
 318          // [shift] + [tab] on first tab cycles back to last tab.
 319          if ( target.hasClass('wp-tab-first') && e.shiftKey ) {
 320              $(this).find('.wp-tab-last').focus();
 321              e.preventDefault();
 322          // [tab] on last tab cycles back to first tab.
 323          } else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) {
 324              $(this).find('.wp-tab-first').focus();
 325              e.preventDefault();
 326          }
 327      }).filter(':visible').find('.wp-tab-first').focus();
 328  
 329      // Set the heartbeat interval to 15 sec. if post lock dialogs are enabled.
 330      if ( wp.heartbeat && $('#post-lock-dialog').length ) {
 331          wp.heartbeat.interval( 15 );
 332      }
 333  
 334      // The form is being submitted by the user.
 335      $submitButtons = $submitpost.find( ':submit, a.submitdelete, #post-preview' ).on( 'click.edit-post', function( event ) {
 336          var $button = $(this);
 337  
 338          if ( $button.hasClass('disabled') ) {
 339              event.preventDefault();
 340              return;
 341          }
 342  
 343          if ( $button.hasClass('submitdelete') || $button.is( '#post-preview' ) ) {
 344              return;
 345          }
 346  
 347          // The form submission can be blocked from JS or by using HTML 5.0 validation on some fields.
 348          // Run this only on an actual 'submit'.
 349          $('form#post').off( 'submit.edit-post' ).on( 'submit.edit-post', function( event ) {
 350              if ( event.isDefaultPrevented() ) {
 351                  return;
 352              }
 353  
 354              // Stop auto save.
 355              if ( wp.autosave ) {
 356                  wp.autosave.server.suspend();
 357              }
 358  
 359              if ( typeof commentReply !== 'undefined' ) {
 360                  /*
 361                   * Warn the user they have an unsaved comment before submitting
 362                   * the post data for update.
 363                   */
 364                  if ( ! commentReply.discardCommentChanges() ) {
 365                      return false;
 366                  }
 367  
 368                  /*
 369                   * Close the comment edit/reply form if open to stop the form
 370                   * action from interfering with the post's form action.
 371                   */
 372                  commentReply.close();
 373              }
 374  
 375              releaseLock = false;
 376              $(window).off( 'beforeunload.edit-post' );
 377  
 378              $submitButtons.addClass( 'disabled' );
 379  
 380              if ( $button.attr('id') === 'publish' ) {
 381                  $submitpost.find( '#major-publishing-actions .spinner' ).addClass( 'is-active' );
 382              } else {
 383                  $submitpost.find( '#minor-publishing .spinner' ).addClass( 'is-active' );
 384              }
 385          });
 386      });
 387  
 388      // Submit the form saving a draft or an autosave, and show a preview in a new tab
 389      $('#post-preview').on( 'click.post-preview', function( event ) {
 390          var $this = $(this),
 391              $form = $('form#post'),
 392              $previewField = $('input#wp-preview'),
 393              target = $this.attr('target') || 'wp-preview',
 394              ua = navigator.userAgent.toLowerCase();
 395  
 396          event.preventDefault();
 397  
 398          if ( $this.hasClass('disabled') ) {
 399              return;
 400          }
 401  
 402          if ( wp.autosave ) {
 403              wp.autosave.server.tempBlockSave();
 404          }
 405  
 406          $previewField.val('dopreview');
 407          $form.attr( 'target', target ).submit().attr( 'target', '' );
 408  
 409          // Workaround for WebKit bug preventing a form submitting twice to the same action.
 410          // https://bugs.webkit.org/show_bug.cgi?id=28633
 411          if ( ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1 ) {
 412              $form.attr( 'action', function( index, value ) {
 413                  return value + '?t=' + ( new Date() ).getTime();
 414              });
 415          }
 416  
 417          $previewField.val('');
 418      });
 419  
 420      // This code is meant to allow tabbing from Title to Post content.
 421      $('#title').on( 'keydown.editor-focus', function( event ) {
 422          var editor;
 423  
 424          if ( event.keyCode === 9 && ! event.ctrlKey && ! event.altKey && ! event.shiftKey ) {
 425              editor = typeof tinymce != 'undefined' && tinymce.get('content');
 426  
 427              if ( editor && ! editor.isHidden() ) {
 428                  editor.focus();
 429              } else if ( $textarea.length ) {
 430                  $textarea.focus();
 431              } else {
 432                  return;
 433              }
 434  
 435              event.preventDefault();
 436          }
 437      });
 438  
 439      // Auto save new posts after a title is typed.
 440      if ( $( '#auto_draft' ).val() ) {
 441          $( '#title' ).blur( function() {
 442              var cancel;
 443  
 444              if ( ! this.value || $('#edit-slug-box > *').length ) {
 445                  return;
 446              }
 447  
 448              // Cancel the auto save when the blur was triggered by the user submitting the form.
 449              $('form#post').one( 'submit', function() {
 450                  cancel = true;
 451              });
 452  
 453              window.setTimeout( function() {
 454                  if ( ! cancel && wp.autosave ) {
 455                      wp.autosave.server.triggerSave();
 456                  }
 457              }, 200 );
 458          });
 459      }
 460  
 461      $document.on( 'autosave-disable-buttons.edit-post', function() {
 462          $submitButtons.addClass( 'disabled' );
 463      }).on( 'autosave-enable-buttons.edit-post', function() {
 464          if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {
 465              $submitButtons.removeClass( 'disabled' );
 466          }
 467      }).on( 'before-autosave.edit-post', function() {
 468          $( '.autosave-message' ).text( postL10n.savingText );
 469      }).on( 'after-autosave.edit-post', function( event, data ) {
 470          $( '.autosave-message' ).text( data.message );
 471  
 472          if ( $( document.body ).hasClass( 'post-new-php' ) ) {
 473              $( '.submitbox .submitdelete' ).show();
 474          }
 475      });
 476  
 477      /*
 478       * When the user is trying to load another page, or reloads current page
 479       * show a confirmation dialog when there are unsaved changes.
 480       */
 481      $(window).on( 'beforeunload.edit-post', function() {
 482          var editor = typeof tinymce !== 'undefined' && tinymce.get('content');
 483  
 484          if ( ( editor && ! editor.isHidden() && editor.isDirty() ) ||
 485              ( wp.autosave && wp.autosave.server.postChanged() ) ) {
 486  
 487              return postL10n.saveAlert;
 488          }
 489      }).on( 'unload.edit-post', function( event ) {
 490          if ( ! releaseLock ) {
 491              return;
 492          }
 493  
 494          /*
 495           * Unload is triggered (by hand) on removing the Thickbox iframe.
 496           * Make sure we process only the main document unload.
 497           */
 498          if ( event.target && event.target.nodeName != '#document' ) {
 499              return;
 500          }
 501  
 502          var postID = $('#post_ID').val();
 503          var postLock = $('#active_post_lock').val();
 504  
 505          if ( ! postID || ! postLock ) {
 506              return;
 507          }
 508  
 509          var data = {
 510              action: 'wp-remove-post-lock',
 511              _wpnonce: $('#_wpnonce').val(),
 512              post_ID: postID,
 513              active_post_lock: postLock
 514          };
 515  
 516          if ( window.FormData && window.navigator.sendBeacon ) {
 517              var formData = new window.FormData();
 518  
 519              $.each( data, function( key, value ) {
 520                  formData.append( key, value );
 521              });
 522  
 523              if ( window.navigator.sendBeacon( ajaxurl, formData ) ) {
 524                  return;
 525              }
 526          }
 527  
 528          // Fall back to a synchronous POST request.
 529          // See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
 530          $.post({
 531              async: false,
 532              data: data,
 533              url: ajaxurl
 534          });
 535      });
 536  
 537      // Multiple Taxonomies.
 538      if ( $('#tagsdiv-post_tag').length ) {
 539          window.tagBox && window.tagBox.init();
 540      } else {
 541          $('.meta-box-sortables').children('div.postbox').each(function(){
 542              if ( this.id.indexOf('tagsdiv-') === 0 ) {
 543                  window.tagBox && window.tagBox.init();
 544                  return false;
 545              }
 546          });
 547      }
 548  
 549      // Handle categories.
 550      $('.categorydiv').each( function(){
 551          var this_id = $(this).attr('id'), catAddBefore, catAddAfter, taxonomyParts, taxonomy, settingName;
 552  
 553          taxonomyParts = this_id.split('-');
 554          taxonomyParts.shift();
 555          taxonomy = taxonomyParts.join('-');
 556          settingName = taxonomy + '_tab';
 557  
 558          if ( taxonomy == 'category' ) {
 559              settingName = 'cats';
 560          }
 561  
 562          // TODO: move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js
 563          $('a', '#' + taxonomy + '-tabs').click( function( e ) {
 564              e.preventDefault();
 565              var t = $(this).attr('href');
 566              $(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
 567              $('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide();
 568              $(t).show();
 569              if ( '#' + taxonomy + '-all' == t ) {
 570                  deleteUserSetting( settingName );
 571              } else {
 572                  setUserSetting( settingName, 'pop' );
 573              }
 574          });
 575  
 576          if ( getUserSetting( settingName ) )
 577              $('a[href="#' + taxonomy + '-pop"]', '#' + taxonomy + '-tabs').click();
 578  
 579          // Add category button controls.
 580          $('#new' + taxonomy).one( 'focus', function() {
 581              $( this ).val( '' ).removeClass( 'form-input-tip' );
 582          });
 583  
 584          // On [enter] submit the taxonomy.
 585          $('#new' + taxonomy).keypress( function(event){
 586              if( 13 === event.keyCode ) {
 587                  event.preventDefault();
 588                  $('#' + taxonomy + '-add-submit').click();
 589              }
 590          });
 591  
 592          // After submitting a new taxonomy, re-focus the input field.
 593          $('#' + taxonomy + '-add-submit').click( function() {
 594              $('#new' + taxonomy).focus();
 595          });
 596  
 597          /**
 598           * Before adding a new taxonomy, disable submit button.
 599           *
 600           * @param {Object} s Taxonomy object which will be added.
 601           *
 602           * @returns {Object}
 603           */
 604          catAddBefore = function( s ) {
 605              if ( !$('#new'+taxonomy).val() ) {
 606                  return false;
 607              }
 608  
 609              s.data += '&' + $( ':checked', '#'+taxonomy+'checklist' ).serialize();
 610              $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', true );
 611              return s;
 612          };
 613  
 614          /**
 615           * Re-enable submit button after a taxonomy has been added.
 616           *
 617           * Re-enable submit button.
 618           * If the taxonomy has a parent place the taxonomy underneath the parent.
 619           *
 620           * @param {Object} r Response.
 621           * @param {Object} s Taxonomy data.
 622           *
 623           * @returns void
 624           */
 625          catAddAfter = function( r, s ) {
 626              var sup, drop = $('#new'+taxonomy+'_parent');
 627  
 628              $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false );
 629              if ( 'undefined' != s.parsed.responses[0] && (sup = s.parsed.responses[0].supplemental.newcat_parent) ) {
 630                  drop.before(sup);
 631                  drop.remove();
 632              }
 633          };
 634  
 635          $('#' + taxonomy + 'checklist').wpList({
 636              alt: '',
 637              response: taxonomy + '-ajax-response',
 638              addBefore: catAddBefore,
 639              addAfter: catAddAfter
 640          });
 641  
 642          // Add new taxonomy button toggles input form visibility.
 643          $('#' + taxonomy + '-add-toggle').click( function( e ) {
 644              e.preventDefault();
 645              $('#' + taxonomy + '-adder').toggleClass( 'wp-hidden-children' );
 646              $('a[href="#' + taxonomy + '-all"]', '#' + taxonomy + '-tabs').click();
 647              $('#new'+taxonomy).focus();
 648          });
 649  
 650          // Sync checked items between "All {taxonomy}" and "Most used" lists.
 651          $('#' + taxonomy + 'checklist, #' + taxonomy + 'checklist-pop').on( 'click', 'li.popular-category > label input[type="checkbox"]', function() {
 652              var t = $(this), c = t.is(':checked'), id = t.val();
 653              if ( id && t.parents('#taxonomy-'+taxonomy).length )
 654                  $('#in-' + taxonomy + '-' + id + ', #in-popular-' + taxonomy + '-' + id).prop( 'checked', c );
 655          });
 656  
 657      }); // end cats
 658  
 659      // Custom Fields postbox.
 660      if ( $('#postcustom').length ) {
 661          $( '#the-list' ).wpList( {
 662              /**
 663               * Add current post_ID to request to fetch custom fields
 664               *
 665               * @ignore
 666               *
 667               * @param {Object} s Request object.
 668               *
 669               * @returns {Object} Data modified with post_ID attached.
 670               */
 671              addBefore: function( s ) {
 672                  s.data += '&post_id=' + $('#post_ID').val();
 673                  return s;
 674              },
 675              /**
 676               * Show the listing of custom fields after fetching.
 677               *
 678               * @ignore
 679               */
 680              addAfter: function() {
 681                  $('table#list-table').show();
 682              }
 683          });
 684      }
 685  
 686      /*
 687       * Publish Post box (#submitdiv)
 688       */
 689      if ( $('#submitdiv').length ) {
 690          stamp = $('#timestamp').html();
 691          visibility = $('#post-visibility-display').html();
 692  
 693          /**
 694           * When the visibility of a post changes sub-options should be shown or hidden.
 695           *
 696           * @ignore
 697           *
 698           * @returns void
 699           */
 700          updateVisibility = function() {
 701              // Show sticky for public posts.
 702              if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
 703                  $('#sticky').prop('checked', false);
 704                  $('#sticky-span').hide();
 705              } else {
 706                  $('#sticky-span').show();
 707              }
 708  
 709              // Show password input field for password protected post.
 710              if ( $postVisibilitySelect.find('input:radio:checked').val() != 'password' ) {
 711                  $('#password-span').hide();
 712              } else {
 713                  $('#password-span').show();
 714              }
 715          };
 716  
 717          /**
 718           * Make sure all labels represent the current settings.
 719           *
 720           * @ignore
 721           *
 722           * @returns {boolean} False when an invalid timestamp has been selected, otherwise True.
 723           */
 724          updateText = function() {
 725  
 726              if ( ! $timestampdiv.length )
 727                  return true;
 728  
 729              var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'),
 730                  optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(),
 731                  mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val();
 732  
 733              attemptedDate = new Date( aa, mm - 1, jj, hh, mn );
 734              originalDate = new Date( $('#hidden_aa').val(), $('#hidden_mm').val() -1, $('#hidden_jj').val(), $('#hidden_hh').val(), $('#hidden_mn').val() );
 735              currentDate = new Date( $('#cur_aa').val(), $('#cur_mm').val() -1, $('#cur_jj').val(), $('#cur_hh').val(), $('#cur_mn').val() );
 736  
 737              // Catch unexpected date problems.
 738              if ( attemptedDate.getFullYear() != aa || (1 + attemptedDate.getMonth()) != mm || attemptedDate.getDate() != jj || attemptedDate.getMinutes() != mn ) {
 739                  $timestampdiv.find('.timestamp-wrap').addClass('form-invalid');
 740                  return false;
 741              } else {
 742                  $timestampdiv.find('.timestamp-wrap').removeClass('form-invalid');
 743              }
 744  
 745              // Determine what the publish should be depending on the date and post status.
 746              if ( attemptedDate > currentDate && $('#original_post_status').val() != 'future' ) {
 747                  publishOn = postL10n.publishOnFuture;
 748                  $('#publish').val( postL10n.schedule );
 749              } else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) {
 750                  publishOn = postL10n.publishOn;
 751                  $('#publish').val( postL10n.publish );
 752              } else {
 753                  publishOn = postL10n.publishOnPast;
 754                  $('#publish').val( postL10n.update );
 755              }
 756  
 757              // If the date is the same, set it to trigger update events.
 758              if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) {
 759                  // Re-set to the current value.
 760                  $('#timestamp').html(stamp);
 761              } else {
 762                  $('#timestamp').html(
 763                      '\n' + publishOn + ' <b>' +
 764                      postL10n.dateFormat
 765                          .replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) )
 766                          .replace( '%2$s', parseInt( jj, 10 ) )
 767                          .replace( '%3$s', aa )
 768                          .replace( '%4$s', ( '00' + hh ).slice( -2 ) )
 769                          .replace( '%5$s', ( '00' + mn ).slice( -2 ) ) +
 770                          '</b> '
 771                  );
 772              }
 773  
 774              // Add "privately published" to post status when applies.
 775              if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) {
 776                  $('#publish').val( postL10n.update );
 777                  if ( 0 === optPublish.length ) {
 778                      postStatus.append('<option value="publish">' + postL10n.privatelyPublished + '</option>');
 779                  } else {
 780                      optPublish.html( postL10n.privatelyPublished );
 781                  }
 782                  $('option[value="publish"]', postStatus).prop('selected', true);
 783                  $('#misc-publishing-actions .edit-post-status').hide();
 784              } else {
 785                  if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
 786                      if ( optPublish.length ) {
 787                          optPublish.remove();
 788                          postStatus.val($('#hidden_post_status').val());
 789                      }
 790                  } else {
 791                      optPublish.html( postL10n.published );
 792                  }
 793                  if ( postStatus.is(':hidden') )
 794                      $('#misc-publishing-actions .edit-post-status').show();
 795              }
 796  
 797              // Update "Status:" to currently selected status.
 798              $('#post-status-display').text(
 799                  wp.sanitize.stripTagsAndEncodeText( $('option:selected', postStatus).text() ) // Remove any potential tags from post status text.
 800              );
 801  
 802              // Show or hide the "Save Draft" button.
 803              if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
 804                  $('#save-post').hide();
 805              } else {
 806                  $('#save-post').show();
 807                  if ( $('option:selected', postStatus).val() == 'pending' ) {
 808                      $('#save-post').show().val( postL10n.savePending );
 809                  } else {
 810                      $('#save-post').show().val( postL10n.saveDraft );
 811                  }
 812              }
 813              return true;
 814          };
 815  
 816          // Show the visibility options and hide the toggle button when opened.
 817          $( '#visibility .edit-visibility').click( function( e ) {
 818              e.preventDefault();
 819              if ( $postVisibilitySelect.is(':hidden') ) {
 820                  updateVisibility();
 821                  $postVisibilitySelect.slideDown( 'fast', function() {
 822                      $postVisibilitySelect.find( 'input[type="radio"]' ).first().focus();
 823                  } );
 824                  $(this).hide();
 825              }
 826          });
 827  
 828          // Cancel visibility selection area and hide it from view.
 829          $postVisibilitySelect.find('.cancel-post-visibility').click( function( event ) {
 830              $postVisibilitySelect.slideUp('fast');
 831              $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true);
 832              $('#post_password').val($('#hidden-post-password').val());
 833              $('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked'));
 834              $('#post-visibility-display').html(visibility);
 835              $('#visibility .edit-visibility').show().focus();
 836              updateText();
 837              event.preventDefault();
 838          });
 839  
 840          // Set the selected visibility as current.
 841          $postVisibilitySelect.find('.save-post-visibility').click( function( event ) { // crazyhorse - multiple ok cancels
 842              $postVisibilitySelect.slideUp('fast');
 843              $('#visibility .edit-visibility').show().focus();
 844              updateText();
 845  
 846              if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
 847                  $('#sticky').prop('checked', false);
 848              }
 849  
 850              if ( $('#sticky').prop('checked') ) {
 851                  sticky = 'Sticky';
 852              } else {
 853                  sticky = '';
 854              }
 855  
 856              $('#post-visibility-display').html(    postL10n[ $postVisibilitySelect.find('input:radio:checked').val() + sticky ]    );
 857              event.preventDefault();
 858          });
 859  
 860          // When the selection changes, update labels.
 861          $postVisibilitySelect.find('input:radio').change( function() {
 862              updateVisibility();
 863          });
 864  
 865          // Edit publish time click.
 866          $timestampdiv.siblings('a.edit-timestamp').click( function( event ) {
 867              if ( $timestampdiv.is( ':hidden' ) ) {
 868                  $timestampdiv.slideDown( 'fast', function() {
 869                      $( 'input, select', $timestampdiv.find( '.timestamp-wrap' ) ).first().focus();
 870                  } );
 871                  $(this).hide();
 872              }
 873              event.preventDefault();
 874          });
 875  
 876          // Cancel editing the publish time and hide the settings.
 877          $timestampdiv.find('.cancel-timestamp').click( function( event ) {
 878              $timestampdiv.slideUp('fast').siblings('a.edit-timestamp').show().focus();
 879              $('#mm').val($('#hidden_mm').val());
 880              $('#jj').val($('#hidden_jj').val());
 881              $('#aa').val($('#hidden_aa').val());
 882              $('#hh').val($('#hidden_hh').val());
 883              $('#mn').val($('#hidden_mn').val());
 884              updateText();
 885              event.preventDefault();
 886          });
 887  
 888          // Save the changed timestamp.
 889          $timestampdiv.find('.save-timestamp').click( function( event ) { // crazyhorse - multiple ok cancels
 890              if ( updateText() ) {
 891                  $timestampdiv.slideUp('fast');
 892                  $timestampdiv.siblings('a.edit-timestamp').show().focus();
 893              }
 894              event.preventDefault();
 895          });
 896  
 897          // Cancel submit when an invalid timestamp has been selected.
 898          $('#post').on( 'submit', function( event ) {
 899              if ( ! updateText() ) {
 900                  event.preventDefault();
 901                  $timestampdiv.show();
 902  
 903                  if ( wp.autosave ) {
 904                      wp.autosave.enableButtons();
 905                  }
 906  
 907                  $( '#publishing-action .spinner' ).removeClass( 'is-active' );
 908              }
 909          });
 910  
 911          // Post Status edit click.
 912          $postStatusSelect.siblings('a.edit-post-status').click( function( event ) {
 913              if ( $postStatusSelect.is( ':hidden' ) ) {
 914                  $postStatusSelect.slideDown( 'fast', function() {
 915                      $postStatusSelect.find('select').focus();
 916                  } );
 917                  $(this).hide();
 918              }
 919              event.preventDefault();
 920          });
 921  
 922          // Save the Post Status changes and hide the options.
 923          $postStatusSelect.find('.save-post-status').click( function( event ) {
 924              $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().focus();
 925              updateText();
 926              event.preventDefault();
 927          });
 928  
 929          // Cancel Post Status editing and hide the options.
 930          $postStatusSelect.find('.cancel-post-status').click( function( event ) {
 931              $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().focus();
 932              $('#post_status').val( $('#hidden_post_status').val() );
 933              updateText();
 934              event.preventDefault();
 935          });
 936      }
 937  
 938      /**
 939       * Handle the editing of the post_name. Create the required HTML elements and
 940       * update the changes via AJAX.
 941       *
 942       * @global
 943       *
 944       * @returns void
 945       */
 946  	function editPermalink() {
 947          var i, slug_value,
 948              $el, revert_e,
 949              c = 0,
 950              real_slug = $('#post_name'),
 951              revert_slug = real_slug.val(),
 952              permalink = $( '#sample-permalink' ),
 953              permalinkOrig = permalink.html(),
 954              permalinkInner = $( '#sample-permalink a' ).html(),
 955              buttons = $('#edit-slug-buttons'),
 956              buttonsOrig = buttons.html(),
 957              full = $('#editable-post-name-full');
 958  
 959          // Deal with Twemoji in the post-name.
 960          full.find( 'img' ).replaceWith( function() { return this.alt; } );
 961          full = full.html();
 962  
 963          permalink.html( permalinkInner );
 964  
 965          // Save current content to revert to when cancelling.
 966          $el = $( '#editable-post-name' );
 967          revert_e = $el.html();
 968  
 969          buttons.html( '<button type="button" class="save button button-small">' + postL10n.ok + '</button> <button type="button" class="cancel button-link">' + postL10n.cancel + '</button>' );
 970  
 971          // Save permalink changes.
 972          buttons.children( '.save' ).click( function() {
 973              var new_slug = $el.children( 'input' ).val();
 974  
 975              if ( new_slug == $('#editable-post-name-full').text() ) {
 976                  buttons.children('.cancel').click();
 977                  return;
 978              }
 979  
 980              $.post(
 981                  ajaxurl,
 982                  {
 983                      action: 'sample-permalink',
 984                      post_id: postId,
 985                      new_slug: new_slug,
 986                      new_title: $('#title').val(),
 987                      samplepermalinknonce: $('#samplepermalinknonce').val()
 988                  },
 989                  function(data) {
 990                      var box = $('#edit-slug-box');
 991                      box.html(data);
 992                      if (box.hasClass('hidden')) {
 993                          box.fadeIn('fast', function () {
 994                              box.removeClass('hidden');
 995                          });
 996                      }
 997  
 998                      buttons.html(buttonsOrig);
 999                      permalink.html(permalinkOrig);
1000                      real_slug.val(new_slug);
1001                      $( '.edit-slug' ).focus();
1002                      wp.a11y.speak( postL10n.permalinkSaved );
1003                  }
1004              );
1005          });
1006  
1007          // Cancel editing of permalink.
1008          buttons.children( '.cancel' ).click( function() {
1009              $('#view-post-btn').show();
1010              $el.html(revert_e);
1011              buttons.html(buttonsOrig);
1012              permalink.html(permalinkOrig);
1013              real_slug.val(revert_slug);
1014              $( '.edit-slug' ).focus();
1015          });
1016  
1017          // If more than 1/4th of 'full' is '%', make it empty.
1018          for ( i = 0; i < full.length; ++i ) {
1019              if ( '%' == full.charAt(i) )
1020                  c++;
1021          }
1022          slug_value = ( c > full.length / 4 ) ? '' : full;
1023  
1024          $el.html( '<input type="text" id="new-post-slug" value="' + slug_value + '" autocomplete="off" />' ).children( 'input' ).keydown( function( e ) {
1025              var key = e.which;
1026              // On [enter], just save the new slug, don't save the post.
1027              if ( 13 === key ) {
1028                  e.preventDefault();
1029                  buttons.children( '.save' ).click();
1030              }
1031              // On [esc] cancel the editing.
1032              if ( 27 === key ) {
1033                  buttons.children( '.cancel' ).click();
1034              }
1035          } ).keyup( function() {
1036              real_slug.val( this.value );
1037          }).focus();
1038      }
1039  
1040      $( '#titlediv' ).on( 'click', '.edit-slug', function() {
1041          editPermalink();
1042      });
1043  
1044      /**
1045       * Adds screen reader text to the title label when needed.
1046       *
1047       * Use the 'screen-reader-text' class to emulate a placeholder attribute
1048       * and hide the label when entering a value.
1049       *
1050       * @param {string} id Optional. HTML ID to add the screen reader helper text to.
1051       *
1052       * @global
1053       *
1054       * @returns void
1055       */
1056      window.wptitlehint = function( id ) {
1057          id = id || 'title';
1058  
1059          var title = $( '#' + id ), titleprompt = $( '#' + id + '-prompt-text' );
1060  
1061          if ( '' === title.val() ) {
1062              titleprompt.removeClass( 'screen-reader-text' );
1063          }
1064  
1065          title.on( 'input', function() {
1066              if ( '' === this.value ) {
1067                  titleprompt.removeClass( 'screen-reader-text' );
1068                  return;
1069              }
1070  
1071              titleprompt.addClass( 'screen-reader-text' );
1072          } );
1073      };
1074  
1075      wptitlehint();
1076  
1077      // Resize the WYSIWYG and plain text editors.
1078      ( function() {
1079          var editor, offset, mce,
1080              $handle = $('#post-status-info'),
1081              $postdivrich = $('#postdivrich');
1082  
1083          // If there are no textareas or we are on a touch device, we can't do anything.
1084          if ( ! $textarea.length || 'ontouchstart' in window ) {
1085              // Hide the resize handle.
1086              $('#content-resize-handle').hide();
1087              return;
1088          }
1089  
1090          /**
1091           * Handle drag event.
1092           *
1093           * @param {Object} event Event containing details about the drag.
1094           */
1095  		function dragging( event ) {
1096              if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
1097                  return;
1098              }
1099  
1100              if ( mce ) {
1101                  editor.theme.resizeTo( null, offset + event.pageY );
1102              } else {
1103                  $textarea.height( Math.max( 50, offset + event.pageY ) );
1104              }
1105  
1106              event.preventDefault();
1107          }
1108  
1109          /**
1110           * When the dragging stopped make sure we return focus and do a sanity check on the height.
1111           */
1112  		function endDrag() {
1113              var height, toolbarHeight;
1114  
1115              if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
1116                  return;
1117              }
1118  
1119              if ( mce ) {
1120                  editor.focus();
1121                  toolbarHeight = parseInt( $( '#wp-content-editor-container .mce-toolbar-grp' ).height(), 10 );
1122  
1123                  if ( toolbarHeight < 10 || toolbarHeight > 200 ) {
1124                      toolbarHeight = 30;
1125                  }
1126  
1127                  height = parseInt( $('#content_ifr').css('height'), 10 ) + toolbarHeight - 28;
1128              } else {
1129                  $textarea.focus();
1130                  height = parseInt( $textarea.css('height'), 10 );
1131              }
1132  
1133              $document.off( '.wp-editor-resize' );
1134  
1135              // Sanity check: normalize height to stay within acceptable ranges.
1136              if ( height && height > 50 && height < 5000 ) {
1137                  setUserSetting( 'ed_size', height );
1138              }
1139          }
1140  
1141          $handle.on( 'mousedown.wp-editor-resize', function( event ) {
1142              if ( typeof tinymce !== 'undefined' ) {
1143                  editor = tinymce.get('content');
1144              }
1145  
1146              if ( editor && ! editor.isHidden() ) {
1147                  mce = true;
1148                  offset = $('#content_ifr').height() - event.pageY;
1149              } else {
1150                  mce = false;
1151                  offset = $textarea.height() - event.pageY;
1152                  $textarea.blur();
1153              }
1154  
1155              $document.on( 'mousemove.wp-editor-resize', dragging )
1156                  .on( 'mouseup.wp-editor-resize mouseleave.wp-editor-resize', endDrag );
1157  
1158              event.preventDefault();
1159          }).on( 'mouseup.wp-editor-resize', endDrag );
1160      })();
1161  
1162      // TinyMCE specific handling of Post Format changes to reflect in the editor.
1163      if ( typeof tinymce !== 'undefined' ) {
1164          // When changing post formats, change the editor body class.
1165          $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() {
1166              var editor, body, format = this.id;
1167  
1168              if ( format && $( this ).prop( 'checked' ) && ( editor = tinymce.get( 'content' ) ) ) {
1169                  body = editor.getBody();
1170                  body.className = body.className.replace( /\bpost-format-[^ ]+/, '' );
1171                  editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format );
1172                  $( document ).trigger( 'editor-classchange' );
1173              }
1174          });
1175  
1176          // When changing page template, change the editor body class
1177          $( '#page_template' ).on( 'change.set-editor-class', function() {
1178              var editor, body, pageTemplate = $( this ).val() || '';
1179  
1180              pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length )
1181                  .replace( /\.php$/, '' )
1182                  .replace( /\./g, '-' );
1183  
1184              if ( pageTemplate && ( editor = tinymce.get( 'content' ) ) ) {
1185                  body = editor.getBody();
1186                  body.className = body.className.replace( /\bpage-template-[^ ]+/, '' );
1187                  editor.dom.addClass( body, 'page-template-' + pageTemplate );
1188                  $( document ).trigger( 'editor-classchange' );
1189              }
1190          });
1191  
1192      }
1193  
1194      // Save on pressing [ctrl]/[command] + [s] in the Text editor.
1195      $textarea.on( 'keydown.wp-autosave', function( event ) {
1196          // Key [s] has code 83.
1197          if ( event.which === 83 ) {
1198              if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) {
1199                  return;
1200              }
1201  
1202              wp.autosave && wp.autosave.server.triggerSave();
1203              event.preventDefault();
1204          }
1205      });
1206  
1207      // If the last status was auto-draft and the save is triggered, edit the current URL.
1208      if ( $( '#original_post_status' ).val() === 'auto-draft' && window.history.replaceState ) {
1209          var location;
1210  
1211          $( '#publish' ).on( 'click', function() {
1212              location = window.location.href;
1213              location += ( location.indexOf( '?' ) !== -1 ) ? '&' : '?';
1214              location += 'wp-post-new-reload=true';
1215  
1216              window.history.replaceState( null, null, location );
1217          });
1218      }
1219  });
1220  
1221  /**
1222   * TinyMCE word count display
1223   */
1224  ( function( $, counter ) {
1225      $( function() {
1226          var $content = $( '#content' ),
1227              $count = $( '#wp-word-count' ).find( '.word-count' ),
1228              prevCount = 0,
1229              contentEditor;
1230  
1231          /**
1232           * Get the word count from TinyMCE and display it
1233           */
1234  		function update() {
1235              var text, count;
1236  
1237              if ( ! contentEditor || contentEditor.isHidden() ) {
1238                  text = $content.val();
1239              } else {
1240                  text = contentEditor.getContent( { format: 'raw' } );
1241              }
1242  
1243              count = counter.count( text );
1244  
1245              if ( count !== prevCount ) {
1246                  $count.text( count );
1247              }
1248  
1249              prevCount = count;
1250          }
1251  
1252          /**
1253           * Bind the word count update triggers.
1254           *
1255           * When a node change in the main TinyMCE editor has been triggered.
1256           * When a key has been released in the plain text content editor.
1257           */
1258          $( document ).on( 'tinymce-editor-init', function( event, editor ) {
1259              if ( editor.id !== 'content' ) {
1260                  return;
1261              }
1262  
1263              contentEditor = editor;
1264  
1265              editor.on( 'nodechange keyup', _.debounce( update, 1000 ) );
1266          } );
1267  
1268          $content.on( 'input keyup', _.debounce( update, 1000 ) );
1269  
1270          update();
1271      } );
1272  
1273  } )( jQuery, new wp.utils.WordCounter() );


Generated: Mon Nov 18 01:00:04 2019 Cross-referenced by PHPXref 0.7.1