Diff: STRATO-apps/wordpress_03/app/wp-admin/js/post.js

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