home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-admin / js / post.js < prev    next >
Encoding:
JavaScript  |  2016-10-24  |  36.5 KB  |  1,268 lines

  1. /* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting */
  2. /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply */
  3.  
  4. /**
  5.  * Contains all dynamic functionality needed on post and term pages.
  6.  *
  7.  * @summary Control page and term functionality.
  8.  */
  9.  
  10. var commentsBox, WPSetThumbnailHTML, WPSetThumbnailID, WPRemoveThumbnail, wptitlehint, makeSlugeditClickable, editPermalink;
  11. // Backwards compatibility: prevent fatal errors.
  12. makeSlugeditClickable = 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.     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.          * @param {int} total Total number of comments for this post.
  35.          * @param {int} num   Optional. Number of comments to fetch, defaults to 20.
  36.          * @returns {boolean} Always returns false.
  37.          *
  38.          * @memberof commentsBox
  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.     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.     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.     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( /&/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.              * @param {Object} s Request object.
  666.              *
  667.              * @returns {Object} Data modified with post_ID attached.
  668.              */
  669.             addBefore: function( s ) {
  670.                 s.data += '&post_id=' + $('#post_ID').val();
  671.                 return s;
  672.             },
  673.             /**
  674.              * Show the listing of custom fields after fetching.
  675.              */
  676.             addAfter: function() {
  677.                 $('table#list-table').show();
  678.             }
  679.         });
  680.     }
  681.  
  682.     /*
  683.      * Publish Post box (#submitdiv)
  684.      */
  685.     if ( $('#submitdiv').length ) {
  686.         stamp = $('#timestamp').html();
  687.         visibility = $('#post-visibility-display').html();
  688.  
  689.         /**
  690.          * When the visibility of a post changes sub-options should be shown or hidden.
  691.          *
  692.          * @returns void
  693.          */
  694.         updateVisibility = function() {
  695.             // Show sticky for public posts.
  696.             if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
  697.                 $('#sticky').prop('checked', false);
  698.                 $('#sticky-span').hide();
  699.             } else {
  700.                 $('#sticky-span').show();
  701.             }
  702.  
  703.             // Show password input field for password protected post.
  704.             if ( $postVisibilitySelect.find('input:radio:checked').val() != 'password' ) {
  705.                 $('#password-span').hide();
  706.             } else {
  707.                 $('#password-span').show();
  708.             }
  709.         };
  710.  
  711.         /**
  712.          * Make sure all labels represent the current settings.
  713.          *
  714.          * @returns {boolean} False when an invalid timestamp has been selected, otherwise True.
  715.          */
  716.         updateText = function() {
  717.  
  718.             if ( ! $timestampdiv.length )
  719.                 return true;
  720.  
  721.             var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'),
  722.                 optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(),
  723.                 mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val();
  724.  
  725.             attemptedDate = new Date( aa, mm - 1, jj, hh, mn );
  726.             originalDate = new Date( $('#hidden_aa').val(), $('#hidden_mm').val() -1, $('#hidden_jj').val(), $('#hidden_hh').val(), $('#hidden_mn').val() );
  727.             currentDate = new Date( $('#cur_aa').val(), $('#cur_mm').val() -1, $('#cur_jj').val(), $('#cur_hh').val(), $('#cur_mn').val() );
  728.  
  729.             // Catch unexpected date problems.
  730.             if ( attemptedDate.getFullYear() != aa || (1 + attemptedDate.getMonth()) != mm || attemptedDate.getDate() != jj || attemptedDate.getMinutes() != mn ) {
  731.                 $timestampdiv.find('.timestamp-wrap').addClass('form-invalid');
  732.                 return false;
  733.             } else {
  734.                 $timestampdiv.find('.timestamp-wrap').removeClass('form-invalid');
  735.             }
  736.  
  737.             // Determine what the publish should be depending on the date and post status.
  738.             if ( attemptedDate > currentDate && $('#original_post_status').val() != 'future' ) {
  739.                 publishOn = postL10n.publishOnFuture;
  740.                 $('#publish').val( postL10n.schedule );
  741.             } else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) {
  742.                 publishOn = postL10n.publishOn;
  743.                 $('#publish').val( postL10n.publish );
  744.             } else {
  745.                 publishOn = postL10n.publishOnPast;
  746.                 $('#publish').val( postL10n.update );
  747.             }
  748.  
  749.             // If the date is the same, set it to trigger update events.
  750.             if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) {
  751.                 // Re-set to the current value.
  752.                 $('#timestamp').html(stamp);
  753.             } else {
  754.                 $('#timestamp').html(
  755.                     '\n' + publishOn + ' <b>' +
  756.                     postL10n.dateFormat
  757.                         .replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) )
  758.                         .replace( '%2$s', parseInt( jj, 10 ) )
  759.                         .replace( '%3$s', aa )
  760.                         .replace( '%4$s', ( '00' + hh ).slice( -2 ) )
  761.                         .replace( '%5$s', ( '00' + mn ).slice( -2 ) ) +
  762.                         '</b> '
  763.                 );
  764.             }
  765.  
  766.             // Add "privately published" to post status when applies.
  767.             if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) {
  768.                 $('#publish').val( postL10n.update );
  769.                 if ( 0 === optPublish.length ) {
  770.                     postStatus.append('<option value="publish">' + postL10n.privatelyPublished + '</option>');
  771.                 } else {
  772.                     optPublish.html( postL10n.privatelyPublished );
  773.                 }
  774.                 $('option[value="publish"]', postStatus).prop('selected', true);
  775.                 $('#misc-publishing-actions .edit-post-status').hide();
  776.             } else {
  777.                 if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
  778.                     if ( optPublish.length ) {
  779.                         optPublish.remove();
  780.                         postStatus.val($('#hidden_post_status').val());
  781.                     }
  782.                 } else {
  783.                     optPublish.html( postL10n.published );
  784.                 }
  785.                 if ( postStatus.is(':hidden') )
  786.                     $('#misc-publishing-actions .edit-post-status').show();
  787.             }
  788.  
  789.             // Update "Status:" to currently selected status.
  790.             $('#post-status-display').html($('option:selected', postStatus).text());
  791.  
  792.             // Show or hide the "Save Draft" button.
  793.             if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
  794.                 $('#save-post').hide();
  795.             } else {
  796.                 $('#save-post').show();
  797.                 if ( $('option:selected', postStatus).val() == 'pending' ) {
  798.                     $('#save-post').show().val( postL10n.savePending );
  799.                 } else {
  800.                     $('#save-post').show().val( postL10n.saveDraft );
  801.                 }
  802.             }
  803.             return true;
  804.         };
  805.  
  806.         // Show the visibility options and hide the toggle button when opened.
  807.         $( '#visibility .edit-visibility').click( function( e ) {
  808.             e.preventDefault();
  809.             if ( $postVisibilitySelect.is(':hidden') ) {
  810.                 updateVisibility();
  811.                 $postVisibilitySelect.slideDown( 'fast', function() {
  812.                     $postVisibilitySelect.find( 'input[type="radio"]' ).first().focus();
  813.                 } );
  814.                 $(this).hide();
  815.             }
  816.         });
  817.  
  818.         // Cancel visibility selection area and hide it from view.
  819.         $postVisibilitySelect.find('.cancel-post-visibility').click( function( event ) {
  820.             $postVisibilitySelect.slideUp('fast');
  821.             $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true);
  822.             $('#post_password').val($('#hidden-post-password').val());
  823.             $('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked'));
  824.             $('#post-visibility-display').html(visibility);
  825.             $('#visibility .edit-visibility').show().focus();
  826.             updateText();
  827.             event.preventDefault();
  828.         });
  829.  
  830.         // Set the selected visibility as current.
  831.         $postVisibilitySelect.find('.save-post-visibility').click( function( event ) { // crazyhorse - multiple ok cancels
  832.             $postVisibilitySelect.slideUp('fast');
  833.             $('#visibility .edit-visibility').show().focus();
  834.             updateText();
  835.  
  836.             if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
  837.                 $('#sticky').prop('checked', false);
  838.             }
  839.  
  840.             if ( $('#sticky').prop('checked') ) {
  841.                 sticky = 'Sticky';
  842.             } else {
  843.                 sticky = '';
  844.             }
  845.  
  846.             $('#post-visibility-display').html(    postL10n[ $postVisibilitySelect.find('input:radio:checked').val() + sticky ]    );
  847.             event.preventDefault();
  848.         });
  849.  
  850.         // When the selection changes, update labels.
  851.         $postVisibilitySelect.find('input:radio').change( function() {
  852.             updateVisibility();
  853.         });
  854.  
  855.         // Edit publish time click.
  856.         $timestampdiv.siblings('a.edit-timestamp').click( function( event ) {
  857.             if ( $timestampdiv.is( ':hidden' ) ) {
  858.                 $timestampdiv.slideDown( 'fast', function() {
  859.                     $( 'input, select', $timestampdiv.find( '.timestamp-wrap' ) ).first().focus();
  860.                 } );
  861.                 $(this).hide();
  862.             }
  863.             event.preventDefault();
  864.         });
  865.  
  866.         // Cancel editing the publish time and hide the settings.
  867.         $timestampdiv.find('.cancel-timestamp').click( function( event ) {
  868.             $timestampdiv.slideUp('fast').siblings('a.edit-timestamp').show().focus();
  869.             $('#mm').val($('#hidden_mm').val());
  870.             $('#jj').val($('#hidden_jj').val());
  871.             $('#aa').val($('#hidden_aa').val());
  872.             $('#hh').val($('#hidden_hh').val());
  873.             $('#mn').val($('#hidden_mn').val());
  874.             updateText();
  875.             event.preventDefault();
  876.         });
  877.  
  878.         // Save the changed timestamp.
  879.         $timestampdiv.find('.save-timestamp').click( function( event ) { // crazyhorse - multiple ok cancels
  880.             if ( updateText() ) {
  881.                 $timestampdiv.slideUp('fast');
  882.                 $timestampdiv.siblings('a.edit-timestamp').show().focus();
  883.             }
  884.             event.preventDefault();
  885.         });
  886.  
  887.         // Cancel submit when an invalid timestamp has been selected.
  888.         $('#post').on( 'submit', function( event ) {
  889.             if ( ! updateText() ) {
  890.                 event.preventDefault();
  891.                 $timestampdiv.show();
  892.  
  893.                 if ( wp.autosave ) {
  894.                     wp.autosave.enableButtons();
  895.                 }
  896.  
  897.                 $( '#publishing-action .spinner' ).removeClass( 'is-active' );
  898.             }
  899.         });
  900.  
  901.         // Post Status edit click.
  902.         $postStatusSelect.siblings('a.edit-post-status').click( function( event ) {
  903.             if ( $postStatusSelect.is( ':hidden' ) ) {
  904.                 $postStatusSelect.slideDown( 'fast', function() {
  905.                     $postStatusSelect.find('select').focus();
  906.                 } );
  907.                 $(this).hide();
  908.             }
  909.             event.preventDefault();
  910.         });
  911.  
  912.         // Save the Post Status changes and hide the options.
  913.         $postStatusSelect.find('.save-post-status').click( function( event ) {
  914.             $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().focus();
  915.             updateText();
  916.             event.preventDefault();
  917.         });
  918.  
  919.         // Cancel Post Status editing and hide the options.
  920.         $postStatusSelect.find('.cancel-post-status').click( function( event ) {
  921.             $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().focus();
  922.             $('#post_status').val( $('#hidden_post_status').val() );
  923.             updateText();
  924.             event.preventDefault();
  925.         });
  926.     }
  927.  
  928.     /**
  929.      * Handle the editing of the post_name. Create the required HTML elements and update the changes via AJAX.
  930.      *
  931.      * @summary Permalink aka slug aka post_name editing
  932.      *
  933.      * @global
  934.      *
  935.      * @returns void
  936.      */
  937.     function editPermalink() {
  938.         var i, slug_value,
  939.             $el, revert_e,
  940.             c = 0,
  941.             real_slug = $('#post_name'),
  942.             revert_slug = real_slug.val(),
  943.             permalink = $( '#sample-permalink' ),
  944.             permalinkOrig = permalink.html(),
  945.             permalinkInner = $( '#sample-permalink a' ).html(),
  946.             buttons = $('#edit-slug-buttons'),
  947.             buttonsOrig = buttons.html(),
  948.             full = $('#editable-post-name-full');
  949.  
  950.         // Deal with Twemoji in the post-name.
  951.         full.find( 'img' ).replaceWith( function() { return this.alt; } );
  952.         full = full.html();
  953.  
  954.         permalink.html( permalinkInner );
  955.  
  956.         // Save current content to revert to when cancelling.
  957.         $el = $( '#editable-post-name' );
  958.         revert_e = $el.html();
  959.  
  960.         buttons.html( '<button type="button" class="save button button-small">' + postL10n.ok + '</button> <button type="button" class="cancel button-link">' + postL10n.cancel + '</button>' );
  961.  
  962.         // Save permalink changes.
  963.         buttons.children( '.save' ).click( function() {
  964.             var new_slug = $el.children( 'input' ).val();
  965.  
  966.             if ( new_slug == $('#editable-post-name-full').text() ) {
  967.                 buttons.children('.cancel').click();
  968.                 return;
  969.             }
  970.  
  971.             $.post(
  972.                 ajaxurl,
  973.                 {
  974.                     action: 'sample-permalink',
  975.                     post_id: postId,
  976.                     new_slug: new_slug,
  977.                     new_title: $('#title').val(),
  978.                     samplepermalinknonce: $('#samplepermalinknonce').val()
  979.                 },
  980.                 function(data) {
  981.                     var box = $('#edit-slug-box');
  982.                     box.html(data);
  983.                     if (box.hasClass('hidden')) {
  984.                         box.fadeIn('fast', function () {
  985.                             box.removeClass('hidden');
  986.                         });
  987.                     }
  988.  
  989.                     buttons.html(buttonsOrig);
  990.                     permalink.html(permalinkOrig);
  991.                     real_slug.val(new_slug);
  992.                     $( '.edit-slug' ).focus();
  993.                     wp.a11y.speak( postL10n.permalinkSaved );
  994.                 }
  995.             );
  996.         });
  997.  
  998.         // Cancel editing of permalink.
  999.         buttons.children( '.cancel' ).click( function() {
  1000.             $('#view-post-btn').show();
  1001.             $el.html(revert_e);
  1002.             buttons.html(buttonsOrig);
  1003.             permalink.html(permalinkOrig);
  1004.             real_slug.val(revert_slug);
  1005.             $( '.edit-slug' ).focus();
  1006.         });
  1007.  
  1008.         // If more than 1/4th of 'full' is '%', make it empty.
  1009.         for ( i = 0; i < full.length; ++i ) {
  1010.             if ( '%' == full.charAt(i) )
  1011.                 c++;
  1012.         }
  1013.         slug_value = ( c > full.length / 4 ) ? '' : full;
  1014.  
  1015.         $el.html( '<input type="text" id="new-post-slug" value="' + slug_value + '" autocomplete="off" />' ).children( 'input' ).keydown( function( e ) {
  1016.             var key = e.which;
  1017.             // On [enter], just save the new slug, don't save the post.
  1018.             if ( 13 === key ) {
  1019.                 e.preventDefault();
  1020.                 buttons.children( '.save' ).click();
  1021.             }
  1022.             // On [esc] cancel the editing.
  1023.             if ( 27 === key ) {
  1024.                 buttons.children( '.cancel' ).click();
  1025.             }
  1026.         } ).keyup( function() {
  1027.             real_slug.val( this.value );
  1028.         }).focus();
  1029.     }
  1030.  
  1031.     $( '#titlediv' ).on( 'click', '.edit-slug', function() {
  1032.         editPermalink();
  1033.     });
  1034.  
  1035.     /**
  1036.      * Add screen reader text to the title prompt when needed.
  1037.      *
  1038.      * @summary Title screen reader text handler.
  1039.      *
  1040.      * @param {string} id Optional. HTML ID to add the screen reader helper text to.
  1041.      *
  1042.      * @global
  1043.      *
  1044.      * @returns void
  1045.      */
  1046.     wptitlehint = function(id) {
  1047.         id = id || 'title';
  1048.  
  1049.         var title = $('#' + id), titleprompt = $('#' + id + '-prompt-text');
  1050.  
  1051.         if ( '' === title.val() )
  1052.             titleprompt.removeClass('screen-reader-text');
  1053.  
  1054.         titleprompt.click(function(){
  1055.             $(this).addClass('screen-reader-text');
  1056.             title.focus();
  1057.         });
  1058.  
  1059.         title.blur(function(){
  1060.             if ( '' === this.value )
  1061.                 titleprompt.removeClass('screen-reader-text');
  1062.         }).focus(function(){
  1063.             titleprompt.addClass('screen-reader-text');
  1064.         }).keydown(function(e){
  1065.             titleprompt.addClass('screen-reader-text');
  1066.             $(this).unbind(e);
  1067.         });
  1068.     };
  1069.  
  1070.     wptitlehint();
  1071.  
  1072.     // Resize the WYSIWYG and plain text editors.
  1073.     ( function() {
  1074.         var editor, offset, mce,
  1075.             $handle = $('#post-status-info'),
  1076.             $postdivrich = $('#postdivrich');
  1077.  
  1078.         // If there are no textareas or we are on a touch device, we can't do anything.
  1079.         if ( ! $textarea.length || 'ontouchstart' in window ) {
  1080.             // Hide the resize handle.
  1081.             $('#content-resize-handle').hide();
  1082.             return;
  1083.         }
  1084.  
  1085.         /**
  1086.          * Handle drag event.
  1087.          *
  1088.          * @param {Object} event Event containing details about the drag.
  1089.          */
  1090.         function dragging( event ) {
  1091.             if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
  1092.                 return;
  1093.             }
  1094.  
  1095.             if ( mce ) {
  1096.                 editor.theme.resizeTo( null, offset + event.pageY );
  1097.             } else {
  1098.                 $textarea.height( Math.max( 50, offset + event.pageY ) );
  1099.             }
  1100.  
  1101.             event.preventDefault();
  1102.         }
  1103.  
  1104.         /**
  1105.          * When the dragging stopped make sure we return focus and do a sanity check on the height.
  1106.          */
  1107.         function endDrag() {
  1108.             var height, toolbarHeight;
  1109.  
  1110.             if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
  1111.                 return;
  1112.             }
  1113.  
  1114.             if ( mce ) {
  1115.                 editor.focus();
  1116.                 toolbarHeight = parseInt( $( '#wp-content-editor-container .mce-toolbar-grp' ).height(), 10 );
  1117.  
  1118.                 if ( toolbarHeight < 10 || toolbarHeight > 200 ) {
  1119.                     toolbarHeight = 30;
  1120.                 }
  1121.  
  1122.                 height = parseInt( $('#content_ifr').css('height'), 10 ) + toolbarHeight - 28;
  1123.             } else {
  1124.                 $textarea.focus();
  1125.                 height = parseInt( $textarea.css('height'), 10 );
  1126.             }
  1127.  
  1128.             $document.off( '.wp-editor-resize' );
  1129.  
  1130.             // Sanity check: normalize height to stay within acceptable ranges.
  1131.             if ( height && height > 50 && height < 5000 ) {
  1132.                 setUserSetting( 'ed_size', height );
  1133.             }
  1134.         }
  1135.  
  1136.         $handle.on( 'mousedown.wp-editor-resize', function( event ) {
  1137.             if ( typeof tinymce !== 'undefined' ) {
  1138.                 editor = tinymce.get('content');
  1139.             }
  1140.  
  1141.             if ( editor && ! editor.isHidden() ) {
  1142.                 mce = true;
  1143.                 offset = $('#content_ifr').height() - event.pageY;
  1144.             } else {
  1145.                 mce = false;
  1146.                 offset = $textarea.height() - event.pageY;
  1147.                 $textarea.blur();
  1148.             }
  1149.  
  1150.             $document.on( 'mousemove.wp-editor-resize', dragging )
  1151.                 .on( 'mouseup.wp-editor-resize mouseleave.wp-editor-resize', endDrag );
  1152.  
  1153.             event.preventDefault();
  1154.         }).on( 'mouseup.wp-editor-resize', endDrag );
  1155.     })();
  1156.  
  1157.     // TinyMCE specific handling of Post Format changes to reflect in the editor.
  1158.     if ( typeof tinymce !== 'undefined' ) {
  1159.         // When changing post formats, change the editor body class.
  1160.         $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() {
  1161.             var editor, body, format = this.id;
  1162.  
  1163.             if ( format && $( this ).prop( 'checked' ) && ( editor = tinymce.get( 'content' ) ) ) {
  1164.                 body = editor.getBody();
  1165.                 body.className = body.className.replace( /\bpost-format-[^ ]+/, '' );
  1166.                 editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format );
  1167.                 $( document ).trigger( 'editor-classchange' );
  1168.             }
  1169.         });
  1170.  
  1171.         // When changing page template, change the editor body class
  1172.         $( '#page_template' ).on( 'change.set-editor-class', function() {
  1173.             var editor, body, pageTemplate = $( this ).val() || '';
  1174.  
  1175.             pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length )
  1176.                 .replace( /\.php$/, '' )
  1177.                 .replace( /\./g, '-' );
  1178.  
  1179.             if ( pageTemplate && ( editor = tinymce.get( 'content' ) ) ) {
  1180.                 body = editor.getBody();
  1181.                 body.className = body.className.replace( /\bpage-template-[^ ]+/, '' );
  1182.                 editor.dom.addClass( body, 'page-template-' + pageTemplate );
  1183.                 $( document ).trigger( 'editor-classchange' );
  1184.             }
  1185.         });
  1186.  
  1187.     }
  1188.  
  1189.     // Save on pressing [ctrl]/[command] + [s] in the Text editor.
  1190.     $textarea.on( 'keydown.wp-autosave', function( event ) {
  1191.         // Key [s] has code 83.
  1192.         if ( event.which === 83 ) {
  1193.             if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) {
  1194.                 return;
  1195.             }
  1196.  
  1197.             wp.autosave && wp.autosave.server.triggerSave();
  1198.             event.preventDefault();
  1199.         }
  1200.     });
  1201.  
  1202.     // If the last status was auto-draft and the save is triggered, edit the current URL.
  1203.     if ( $( '#original_post_status' ).val() === 'auto-draft' && window.history.replaceState ) {
  1204.         var location;
  1205.  
  1206.         $( '#publish' ).on( 'click', function() {
  1207.             location = window.location.href;
  1208.             location += ( location.indexOf( '?' ) !== -1 ) ? '&' : '?';
  1209.             location += 'wp-post-new-reload=true';
  1210.  
  1211.             window.history.replaceState( null, null, location );
  1212.         });
  1213.     }
  1214. });
  1215.  
  1216. /**
  1217.  * TinyMCE word count display
  1218.  */
  1219. ( function( $, counter ) {
  1220.     $( function() {
  1221.         var $content = $( '#content' ),
  1222.             $count = $( '#wp-word-count' ).find( '.word-count' ),
  1223.             prevCount = 0,
  1224.             contentEditor;
  1225.  
  1226.         /**
  1227.          * Get the word count from TinyMCE and display it
  1228.          */
  1229.         function update() {
  1230.             var text, count;
  1231.  
  1232.             if ( ! contentEditor || contentEditor.isHidden() ) {
  1233.                 text = $content.val();
  1234.             } else {
  1235.                 text = contentEditor.getContent( { format: 'raw' } );
  1236.             }
  1237.  
  1238.             count = counter.count( text );
  1239.  
  1240.             if ( count !== prevCount ) {
  1241.                 $count.text( count );
  1242.             }
  1243.  
  1244.             prevCount = count;
  1245.         }
  1246.  
  1247.         /**
  1248.          * Bind the word count update triggers.
  1249.          *
  1250.          * When a node change in the main TinyMCE editor has been triggered.
  1251.          * When a key has been released in the plain text content editor.
  1252.          */
  1253.         $( document ).on( 'tinymce-editor-init', function( event, editor ) {
  1254.             if ( editor.id !== 'content' ) {
  1255.                 return;
  1256.             }
  1257.  
  1258.             contentEditor = editor;
  1259.  
  1260.             editor.on( 'nodechange keyup', _.debounce( update, 1000 ) );
  1261.         } );
  1262.  
  1263.         $content.on( 'input keyup', _.debounce( update, 1000 ) );
  1264.  
  1265.         update();
  1266.     } );
  1267. } )( jQuery, new wp.utils.WordCounter() );
  1268.