~canonical-sysadmins/wordpress/4.7.3

« back to all changes in this revision

Viewing changes to wp-admin/js/post.js

  • Committer: Haw Loeung
  • Date: 2016-12-13 06:56:21 UTC
  • mfrom: (1.1.20 upstream)
  • Revision ID: haw.loeung@canonical.com-20161213065621-8tcu7u7vlxgs2s81
Merge WP4.7 from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* global postL10n, ajaxurl, wpAjax, setPostThumbnailL10n, postboxes, pagenow, tinymce, alert, deleteUserSetting */
2
2
/* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply */
3
3
 
 
4
/**
 
5
 * Contains all dynamic functionality needed on post and term pages.
 
6
 *
 
7
 * @summary Control page and term functionality.
 
8
 */
 
9
 
4
10
var commentsBox, WPSetThumbnailHTML, WPSetThumbnailID, WPRemoveThumbnail, wptitlehint, makeSlugeditClickable, editPermalink;
5
 
// Back-compat: prevent fatal errors
 
11
// Backwards compatibility: prevent fatal errors.
6
12
makeSlugeditClickable = editPermalink = function(){};
7
13
 
 
14
// Make sure the wp object exists.
8
15
window.wp = window.wp || {};
9
16
 
10
17
( function( $ ) {
11
18
        var titleHasFocus = false;
12
19
 
13
 
commentsBox = {
14
 
        st : 0,
15
 
 
16
 
        get : function(total, num) {
17
 
                var st = this.st, data;
18
 
                if ( ! num )
19
 
                        num = 20;
20
 
 
21
 
                this.st += num;
22
 
                this.total = total;
23
 
                $( '#commentsdiv .spinner' ).addClass( 'is-active' );
24
 
 
25
 
                data = {
26
 
                        'action' : 'get-comments',
27
 
                        'mode' : 'single',
28
 
                        '_ajax_nonce' : $('#add_comment_nonce').val(),
29
 
                        'p' : $('#post_ID').val(),
30
 
                        'start' : st,
31
 
                        'number' : num
32
 
                };
33
 
 
34
 
                $.post(ajaxurl, data,
35
 
                        function(r) {
36
 
                                r = wpAjax.parseAjaxResponse(r);
37
 
                                $('#commentsdiv .widefat').show();
38
 
                                $( '#commentsdiv .spinner' ).removeClass( 'is-active' );
39
 
 
40
 
                                if ( 'object' == typeof r && r.responses[0] ) {
41
 
                                        $('#the-comment-list').append( r.responses[0].data );
42
 
 
43
 
                                        theList = theExtraList = null;
44
 
                                        $( 'a[className*=\':\']' ).unbind();
45
 
 
46
 
                                        if ( commentsBox.st > commentsBox.total )
47
 
                                                $('#show-comments').hide();
48
 
                                        else
49
 
                                                $('#show-comments').show().children('a').html(postL10n.showcomm);
50
 
 
51
 
                                        return;
52
 
                                } else if ( 1 == r ) {
53
 
                                        $('#show-comments').html(postL10n.endcomm);
54
 
                                        return;
55
 
                                }
56
 
 
57
 
                                $('#the-comment-list').append('<tr><td colspan="2">'+wpAjax.broken+'</td></tr>');
58
 
                        }
59
 
                );
60
 
 
61
 
                return false;
62
 
        },
63
 
 
64
 
        load: function(total){
65
 
                this.st = jQuery('#the-comment-list tr.comment:visible').length;
66
 
                this.get(total);
67
 
        }
68
 
};
69
 
 
70
 
WPSetThumbnailHTML = function(html){
71
 
        $('.inside', '#postimagediv').html(html);
72
 
};
73
 
 
74
 
WPSetThumbnailID = function(id){
75
 
        var field = $('input[value="_thumbnail_id"]', '#list-table');
76
 
        if ( field.length > 0 ) {
77
 
                $('#meta\\[' + field.attr('id').match(/[0-9]+/) + '\\]\\[value\\]').text(id);
78
 
        }
79
 
};
80
 
 
81
 
WPRemoveThumbnail = function(nonce){
82
 
        $.post(ajaxurl, {
83
 
                action: 'set-post-thumbnail', post_id: $( '#post_ID' ).val(), thumbnail_id: -1, _ajax_nonce: nonce, cookie: encodeURIComponent( document.cookie )
84
 
        }, function(str){
85
 
                if ( str == '0' ) {
86
 
                        alert( setPostThumbnailL10n.error );
87
 
                } else {
88
 
                        WPSetThumbnailHTML(str);
89
 
                }
90
 
        }
91
 
        );
92
 
};
93
 
 
94
 
$(document).on( 'heartbeat-send.refresh-lock', function( e, data ) {
95
 
        var lock = $('#active_post_lock').val(),
96
 
                post_id = $('#post_ID').val(),
97
 
                send = {};
98
 
 
99
 
        if ( ! post_id || ! $('#post-lock-dialog').length )
100
 
                return;
101
 
 
102
 
        send.post_id = post_id;
103
 
 
104
 
        if ( lock )
105
 
                send.lock = lock;
106
 
 
107
 
        data['wp-refresh-post-lock'] = send;
108
 
 
109
 
}).on( 'heartbeat-tick.refresh-lock', function( e, data ) {
110
 
        // Post locks: update the lock string or show the dialog if somebody has taken over editing
111
 
        var received, wrap, avatar;
112
 
 
113
 
        if ( data['wp-refresh-post-lock'] ) {
114
 
                received = data['wp-refresh-post-lock'];
115
 
 
116
 
                if ( received.lock_error ) {
117
 
                        // show "editing taken over" message
118
 
                        wrap = $('#post-lock-dialog');
119
 
 
120
 
                        if ( wrap.length && ! wrap.is(':visible') ) {
121
 
                                if ( wp.autosave ) {
122
 
                                        // Save the latest changes and disable
123
 
                                        $(document).one( 'heartbeat-tick', function() {
124
 
                                                wp.autosave.server.suspend();
125
 
                                                wrap.removeClass('saving').addClass('saved');
126
 
                                                $(window).off( 'beforeunload.edit-post' );
127
 
                                        });
128
 
 
129
 
                                        wrap.addClass('saving');
130
 
                                        wp.autosave.server.triggerSave();
131
 
                                }
132
 
 
133
 
                                if ( received.lock_error.avatar_src ) {
134
 
                                        avatar = $( '<img class="avatar avatar-64 photo" width="64" height="64" alt="" />' ).attr( 'src', received.lock_error.avatar_src.replace( /&amp;/g, '&' ) );
135
 
                                        wrap.find('div.post-locked-avatar').empty().append( avatar );
136
 
                                }
137
 
 
138
 
                                wrap.show().find('.currently-editing').text( received.lock_error.text );
139
 
                                wrap.find('.wp-tab-first').focus();
140
 
                        }
141
 
                } else if ( received.new_lock ) {
142
 
                        $('#active_post_lock').val( received.new_lock );
143
 
                }
144
 
        }
145
 
}).on( 'before-autosave.update-post-slug', function() {
146
 
        titleHasFocus = document.activeElement && document.activeElement.id === 'title';
147
 
}).on( 'after-autosave.update-post-slug', function() {
148
 
        // Create slug area only if not already there
149
 
        // and the title field was not focused (user was not typing a title) when autosave ran
150
 
        if ( ! $('#edit-slug-box > *').length && ! titleHasFocus ) {
151
 
                $.post( ajaxurl, {
152
 
                                action: 'sample-permalink',
153
 
                                post_id: $('#post_ID').val(),
154
 
                                new_title: $('#title').val(),
155
 
                                samplepermalinknonce: $('#samplepermalinknonce').val()
156
 
                        },
157
 
                        function( data ) {
158
 
                                if ( data != '-1' ) {
159
 
                                        $('#edit-slug-box').html(data);
160
 
                                }
161
 
                        }
162
 
                );
163
 
        }
164
 
});
 
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( /&amp;/g, '&' ) );
 
204
                                                wrap.find('div.post-locked-avatar').empty().append( avatar );
 
205
                                        }
 
206
 
 
207
                                        wrap.show().find('.currently-editing').text( received.lock_error.text );
 
208
                                        wrap.find('.wp-tab-first').focus();
 
209
                                }
 
210
                        } else if ( received.new_lock ) {
 
211
                                $('#active_post_lock').val( received.new_lock );
 
212
                        }
 
213
                }
 
214
        }).on( 'before-autosave.update-post-slug', function() {
 
215
                titleHasFocus = document.activeElement && document.activeElement.id === 'title';
 
216
        }).on( 'after-autosave.update-post-slug', function() {
 
217
 
 
218
                /*
 
219
                 * Create slug area only if not already there
 
220
                 * and the title field was not focused (user was not typing a title) when autosave ran.
 
221
                 */
 
222
                if ( ! $('#edit-slug-box > *').length && ! titleHasFocus ) {
 
223
                        $.post( ajaxurl, {
 
224
                                        action: 'sample-permalink',
 
225
                                        post_id: $('#post_ID').val(),
 
226
                                        new_title: $('#title').val(),
 
227
                                        samplepermalinknonce: $('#samplepermalinknonce').val()
 
228
                                },
 
229
                                function( data ) {
 
230
                                        if ( data != '-1' ) {
 
231
                                                $('#edit-slug-box').html(data);
 
232
                                        }
 
233
                                }
 
234
                        );
 
235
                }
 
236
        });
165
237
 
166
238
}(jQuery));
167
239
 
 
240
/**
 
241
 * Heartbeat refresh nonces.
 
242
 */
168
243
(function($) {
169
244
        var check, timeout;
170
245
 
 
246
        /**
 
247
         * Only allow to check for nonce refresh every 30 seconds.
 
248
         */
171
249
        function schedule() {
172
250
                check = false;
173
251
                window.clearTimeout( timeout );
205
283
        });
206
284
}(jQuery));
207
285
 
 
286
/**
 
287
 * All post and postbox controls and functionality.
 
288
 */
208
289
jQuery(document).ready( function($) {
209
290
        var stamp, visibility, $submitButtons, updateVisibility, updateText,
210
291
                sticky = '',
220
301
 
221
302
        postboxes.add_postbox_toggles(pagenow);
222
303
 
223
 
        // Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post,
224
 
        // and the first post is still being edited, clicking Preview there will use this window to show the preview.
 
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
         */
225
308
        window.name = '';
226
309
 
227
310
        // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
228
311
        $('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) {
 
312
                // Don't do anything when [tab] is pressed.
229
313
                if ( e.which != 9 )
230
314
                        return;
231
315
 
232
316
                var target = $(e.target);
233
317
 
 
318
                // [shift] + [tab] on first tab cycles back to last tab.
234
319
                if ( target.hasClass('wp-tab-first') && e.shiftKey ) {
235
320
                        $(this).find('.wp-tab-last').focus();
236
321
                        e.preventDefault();
 
322
                // [tab] on last tab cycles back to first tab.
237
323
                } else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) {
238
324
                        $(this).find('.wp-tab-first').focus();
239
325
                        e.preventDefault();
240
326
                }
241
327
        }).filter(':visible').find('.wp-tab-first').focus();
242
328
 
243
 
        // Set the heartbeat interval to 15 sec. if post lock dialogs are enabled
 
329
        // Set the heartbeat interval to 15 sec. if post lock dialogs are enabled.
244
330
        if ( wp.heartbeat && $('#post-lock-dialog').length ) {
245
331
                wp.heartbeat.interval( 15 );
246
332
        }
247
333
 
248
 
        // The form is being submitted by the user
 
334
        // The form is being submitted by the user.
249
335
        $submitButtons = $submitpost.find( ':submit, a.submitdelete, #post-preview' ).on( 'click.edit-post', function( event ) {
250
336
                var $button = $(this);
251
337
 
265
351
                                return;
266
352
                        }
267
353
 
268
 
                        // Stop autosave
 
354
                        // Stop auto save.
269
355
                        if ( wp.autosave ) {
270
356
                                wp.autosave.server.suspend();
271
357
                        }
350
436
                }
351
437
        });
352
438
 
353
 
        // Autosave new posts after a title is typed
 
439
        // Auto save new posts after a title is typed.
354
440
        if ( $( '#auto_draft' ).val() ) {
355
441
                $( '#title' ).blur( function() {
356
442
                        var cancel;
359
445
                                return;
360
446
                        }
361
447
 
362
 
                        // Cancel the autosave when the blur was triggered by the user submitting the form
 
448
                        // Cancel the auto save when the blur was triggered by the user submitting the form.
363
449
                        $('form#post').one( 'submit', function() {
364
450
                                cancel = true;
365
451
                        });
388
474
                }
389
475
        });
390
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
         */
391
481
        $(window).on( 'beforeunload.edit-post', function() {
392
482
                var editor = typeof tinymce !== 'undefined' && tinymce.get('content');
393
483
 
401
491
                        return;
402
492
                }
403
493
 
404
 
                // Unload is triggered (by hand) on removing the Thickbox iframe.
405
 
                // Make sure we process only the main document unload.
 
494
                /*
 
495
                 * Unload is triggered (by hand) on removing the Thickbox iframe.
 
496
                 * Make sure we process only the main document unload.
 
497
                 */
406
498
                if ( event.target && event.target.nodeName != '#document' ) {
407
499
                        return;
408
500
                }
409
501
 
410
 
                $.ajax({
411
 
                        type: 'POST',
412
 
                        url: ajaxurl,
 
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({
413
531
                        async: false,
414
 
                        data: {
415
 
                                action: 'wp-remove-post-lock',
416
 
                                _wpnonce: $('#_wpnonce').val(),
417
 
                                post_ID: $('#post_ID').val(),
418
 
                                active_post_lock: $('#active_post_lock').val()
419
 
                        }
 
532
                        data: data,
 
533
                        url: ajaxurl
420
534
                });
421
535
        });
422
536
 
423
 
        // multi-taxonomies
 
537
        // Multiple Taxonomies.
424
538
        if ( $('#tagsdiv-post_tag').length ) {
425
539
                window.tagBox && window.tagBox.init();
426
540
        } else {
432
546
                });
433
547
        }
434
548
 
435
 
        // categories
 
549
        // Handle categories.
436
550
        $('.categorydiv').each( function(){
437
551
                var this_id = $(this).attr('id'), catAddBefore, catAddAfter, taxonomyParts, taxonomy, settingName;
438
552
 
440
554
                taxonomyParts.shift();
441
555
                taxonomy = taxonomyParts.join('-');
442
556
                settingName = taxonomy + '_tab';
443
 
                if ( taxonomy == 'category' )
 
557
 
 
558
                if ( taxonomy == 'category' ) {
444
559
                        settingName = 'cats';
 
560
                }
445
561
 
446
562
                // TODO: move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js
447
563
                $('a', '#' + taxonomy + '-tabs').click( function( e ) {
450
566
                        $(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
451
567
                        $('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide();
452
568
                        $(t).show();
453
 
                        if ( '#' + taxonomy + '-all' == t )
 
569
                        if ( '#' + taxonomy + '-all' == t ) {
454
570
                                deleteUserSetting( settingName );
455
 
                        else
 
571
                        } else {
456
572
                                setUserSetting( settingName, 'pop' );
 
573
                        }
457
574
                });
458
575
 
459
576
                if ( getUserSetting( settingName ) )
460
577
                        $('a[href="#' + taxonomy + '-pop"]', '#' + taxonomy + '-tabs').click();
461
578
 
462
 
                // Ajax Cat
463
 
                $( '#new' + taxonomy ).one( 'focus', function() { $( this ).val( '' ).removeClass( 'form-input-tip' ); } );
 
579
                // Add category button controls.
 
580
                $('#new' + taxonomy).one( 'focus', function() {
 
581
                        $( this ).val( '' ).removeClass( 'form-input-tip' );
 
582
                });
464
583
 
 
584
                // On [enter] submit the taxonomy.
465
585
                $('#new' + taxonomy).keypress( function(event){
466
586
                        if( 13 === event.keyCode ) {
467
587
                                event.preventDefault();
468
588
                                $('#' + taxonomy + '-add-submit').click();
469
589
                        }
470
590
                });
471
 
                $('#' + taxonomy + '-add-submit').click( function(){ $('#new' + taxonomy).focus(); });
472
 
 
 
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
                 */
473
604
                catAddBefore = function( s ) {
474
 
                        if ( !$('#new'+taxonomy).val() )
 
605
                        if ( !$('#new'+taxonomy).val() ) {
475
606
                                return false;
 
607
                        }
 
608
 
476
609
                        s.data += '&' + $( ':checked', '#'+taxonomy+'checklist' ).serialize();
477
610
                        $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', true );
478
611
                        return s;
479
612
                };
480
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
                 */
481
625
                catAddAfter = function( r, s ) {
482
626
                        var sup, drop = $('#new'+taxonomy+'_parent');
483
627
 
495
639
                        addAfter: catAddAfter
496
640
                });
497
641
 
 
642
                // Add new taxonomy button toggles input form visibility.
498
643
                $('#' + taxonomy + '-add-toggle').click( function( e ) {
499
644
                        e.preventDefault();
500
645
                        $('#' + taxonomy + '-adder').toggleClass( 'wp-hidden-children' );
502
647
                        $('#new'+taxonomy).focus();
503
648
                });
504
649
 
 
650
                // Sync checked items between "All {taxonomy}" and "Most used" lists.
505
651
                $('#' + taxonomy + 'checklist, #' + taxonomy + 'checklist-pop').on( 'click', 'li.popular-category > label input[type="checkbox"]', function() {
506
652
                        var t = $(this), c = t.is(':checked'), id = t.val();
507
653
                        if ( id && t.parents('#taxonomy-'+taxonomy).length )
510
656
 
511
657
        }); // end cats
512
658
 
513
 
        // Custom Fields
 
659
        // Custom Fields postbox.
514
660
        if ( $('#postcustom').length ) {
515
 
                $( '#the-list' ).wpList( { addAfter: function() {
516
 
                        $('table#list-table').show();
517
 
                }, addBefore: function( s ) {
518
 
                        s.data += '&post_id=' + $('#post_ID').val();
519
 
                        return s;
520
 
                }
 
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
                        }
521
679
                });
522
680
        }
523
681
 
524
 
        // submitdiv
 
682
        /*
 
683
         * Publish Post box (#submitdiv)
 
684
         */
525
685
        if ( $('#submitdiv').length ) {
526
686
                stamp = $('#timestamp').html();
527
687
                visibility = $('#post-visibility-display').html();
528
688
 
 
689
                /**
 
690
                 * When the visibility of a post changes sub-options should be shown or hidden.
 
691
                 *
 
692
                 * @returns void
 
693
                 */
529
694
                updateVisibility = function() {
 
695
                        // Show sticky for public posts.
530
696
                        if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
531
697
                                $('#sticky').prop('checked', false);
532
698
                                $('#sticky-span').hide();
533
699
                        } else {
534
700
                                $('#sticky-span').show();
535
701
                        }
 
702
 
 
703
                        // Show password input field for password protected post.
536
704
                        if ( $postVisibilitySelect.find('input:radio:checked').val() != 'password' ) {
537
705
                                $('#password-span').hide();
538
706
                        } else {
540
708
                        }
541
709
                };
542
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
                 */
543
716
                updateText = function() {
544
717
 
545
718
                        if ( ! $timestampdiv.length )
553
726
                        originalDate = new Date( $('#hidden_aa').val(), $('#hidden_mm').val() -1, $('#hidden_jj').val(), $('#hidden_hh').val(), $('#hidden_mn').val() );
554
727
                        currentDate = new Date( $('#cur_aa').val(), $('#cur_mm').val() -1, $('#cur_jj').val(), $('#cur_hh').val(), $('#cur_mn').val() );
555
728
 
 
729
                        // Catch unexpected date problems.
556
730
                        if ( attemptedDate.getFullYear() != aa || (1 + attemptedDate.getMonth()) != mm || attemptedDate.getDate() != jj || attemptedDate.getMinutes() != mn ) {
557
731
                                $timestampdiv.find('.timestamp-wrap').addClass('form-invalid');
558
732
                                return false;
560
734
                                $timestampdiv.find('.timestamp-wrap').removeClass('form-invalid');
561
735
                        }
562
736
 
 
737
                        // Determine what the publish should be depending on the date and post status.
563
738
                        if ( attemptedDate > currentDate && $('#original_post_status').val() != 'future' ) {
564
739
                                publishOn = postL10n.publishOnFuture;
565
740
                                $('#publish').val( postL10n.schedule );
570
745
                                publishOn = postL10n.publishOnPast;
571
746
                                $('#publish').val( postL10n.update );
572
747
                        }
573
 
                        if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) { //hack
 
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.
574
752
                                $('#timestamp').html(stamp);
575
753
                        } else {
576
754
                                $('#timestamp').html(
585
763
                                );
586
764
                        }
587
765
 
 
766
                        // Add "privately published" to post status when applies.
588
767
                        if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) {
589
768
                                $('#publish').val( postL10n.update );
590
769
                                if ( 0 === optPublish.length ) {
606
785
                                if ( postStatus.is(':hidden') )
607
786
                                        $('#misc-publishing-actions .edit-post-status').show();
608
787
                        }
 
788
 
 
789
                        // Update "Status:" to currently selected status.
609
790
                        $('#post-status-display').html($('option:selected', postStatus).text());
 
791
 
 
792
                        // Show or hide the "Save Draft" button.
610
793
                        if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
611
794
                                $('#save-post').hide();
612
795
                        } else {
620
803
                        return true;
621
804
                };
622
805
 
 
806
                // Show the visibility options and hide the toggle button when opened.
623
807
                $( '#visibility .edit-visibility').click( function( e ) {
624
808
                        e.preventDefault();
625
809
                        if ( $postVisibilitySelect.is(':hidden') ) {
631
815
                        }
632
816
                });
633
817
 
 
818
                // Cancel visibility selection area and hide it from view.
634
819
                $postVisibilitySelect.find('.cancel-post-visibility').click( function( event ) {
635
820
                        $postVisibilitySelect.slideUp('fast');
636
821
                        $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true);
642
827
                        event.preventDefault();
643
828
                });
644
829
 
 
830
                // Set the selected visibility as current.
645
831
                $postVisibilitySelect.find('.save-post-visibility').click( function( event ) { // crazyhorse - multiple ok cancels
646
832
                        $postVisibilitySelect.slideUp('fast');
647
833
                        $('#visibility .edit-visibility').show().focus();
649
835
 
650
836
                        if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) {
651
837
                                $('#sticky').prop('checked', false);
652
 
                        } // WEAPON LOCKED
 
838
                        }
653
839
 
654
840
                        if ( $('#sticky').prop('checked') ) {
655
841
                                sticky = 'Sticky';
661
847
                        event.preventDefault();
662
848
                });
663
849
 
 
850
                // When the selection changes, update labels.
664
851
                $postVisibilitySelect.find('input:radio').change( function() {
665
852
                        updateVisibility();
666
853
                });
667
854
 
 
855
                // Edit publish time click.
668
856
                $timestampdiv.siblings('a.edit-timestamp').click( function( event ) {
669
857
                        if ( $timestampdiv.is( ':hidden' ) ) {
670
858
                                $timestampdiv.slideDown( 'fast', function() {
675
863
                        event.preventDefault();
676
864
                });
677
865
 
 
866
                // Cancel editing the publish time and hide the settings.
678
867
                $timestampdiv.find('.cancel-timestamp').click( function( event ) {
679
868
                        $timestampdiv.slideUp('fast').siblings('a.edit-timestamp').show().focus();
680
869
                        $('#mm').val($('#hidden_mm').val());
686
875
                        event.preventDefault();
687
876
                });
688
877
 
 
878
                // Save the changed timestamp.
689
879
                $timestampdiv.find('.save-timestamp').click( function( event ) { // crazyhorse - multiple ok cancels
690
880
                        if ( updateText() ) {
691
881
                                $timestampdiv.slideUp('fast');
694
884
                        event.preventDefault();
695
885
                });
696
886
 
 
887
                // Cancel submit when an invalid timestamp has been selected.
697
888
                $('#post').on( 'submit', function( event ) {
698
889
                        if ( ! updateText() ) {
699
890
                                event.preventDefault();
707
898
                        }
708
899
                });
709
900
 
 
901
                // Post Status edit click.
710
902
                $postStatusSelect.siblings('a.edit-post-status').click( function( event ) {
711
903
                        if ( $postStatusSelect.is( ':hidden' ) ) {
712
904
                                $postStatusSelect.slideDown( 'fast', function() {
717
909
                        event.preventDefault();
718
910
                });
719
911
 
 
912
                // Save the Post Status changes and hide the options.
720
913
                $postStatusSelect.find('.save-post-status').click( function( event ) {
721
914
                        $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().focus();
722
915
                        updateText();
723
916
                        event.preventDefault();
724
917
                });
725
918
 
 
919
                // Cancel Post Status editing and hide the options.
726
920
                $postStatusSelect.find('.cancel-post-status').click( function( event ) {
727
921
                        $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().focus();
728
922
                        $('#post_status').val( $('#hidden_post_status').val() );
729
923
                        updateText();
730
924
                        event.preventDefault();
731
925
                });
732
 
        } // end submitdiv
 
926
        }
733
927
 
734
 
        // permalink
 
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
         */
735
937
        function editPermalink() {
736
938
                var i, slug_value,
737
939
                        $el, revert_e,
745
947
                        buttonsOrig = buttons.html(),
746
948
                        full = $('#editable-post-name-full');
747
949
 
748
 
                // Deal with Twemoji in the post-name
 
950
                // Deal with Twemoji in the post-name.
749
951
                full.find( 'img' ).replaceWith( function() { return this.alt; } );
750
952
                full = full.html();
751
953
 
752
954
                permalink.html( permalinkInner );
 
955
 
 
956
                // Save current content to revert to when cancelling.
753
957
                $el = $( '#editable-post-name' );
754
958
                revert_e = $el.html();
755
959
 
756
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.
757
963
                buttons.children( '.save' ).click( function() {
758
964
                        var new_slug = $el.children( 'input' ).val();
759
965
 
761
967
                                buttons.children('.cancel').click();
762
968
                                return;
763
969
                        }
764
 
                        $.post(ajaxurl, {
765
 
                                action: 'sample-permalink',
766
 
                                post_id: postId,
767
 
                                new_slug: new_slug,
768
 
                                new_title: $('#title').val(),
769
 
                                samplepermalinknonce: $('#samplepermalinknonce').val()
770
 
                        }, function(data) {
771
 
                                var box = $('#edit-slug-box');
772
 
                                box.html(data);
773
 
                                if (box.hasClass('hidden')) {
774
 
                                        box.fadeIn('fast', function () {
775
 
                                                box.removeClass('hidden');
776
 
                                        });
 
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 );
777
994
                                }
778
 
 
779
 
                                buttons.html(buttonsOrig);
780
 
                                permalink.html(permalinkOrig);
781
 
                                real_slug.val(new_slug);
782
 
                                $( '.edit-slug' ).focus();
783
 
                                wp.a11y.speak( postL10n.permalinkSaved );
784
 
                        });
 
995
                        );
785
996
                });
786
997
 
 
998
                // Cancel editing of permalink.
787
999
                buttons.children( '.cancel' ).click( function() {
788
1000
                        $('#view-post-btn').show();
789
1001
                        $el.html(revert_e);
793
1005
                        $( '.edit-slug' ).focus();
794
1006
                });
795
1007
 
 
1008
                // If more than 1/4th of 'full' is '%', make it empty.
796
1009
                for ( i = 0; i < full.length; ++i ) {
797
1010
                        if ( '%' == full.charAt(i) )
798
1011
                                c++;
799
1012
                }
800
 
 
801
1013
                slug_value = ( c > full.length / 4 ) ? '' : full;
 
1014
 
802
1015
                $el.html( '<input type="text" id="new-post-slug" value="' + slug_value + '" autocomplete="off" />' ).children( 'input' ).keydown( function( e ) {
803
1016
                        var key = e.which;
804
 
                        // On enter, just save the new slug, don't save the post.
 
1017
                        // On [enter], just save the new slug, don't save the post.
805
1018
                        if ( 13 === key ) {
806
1019
                                e.preventDefault();
807
1020
                                buttons.children( '.save' ).click();
808
1021
                        }
 
1022
                        // On [esc] cancel the editing.
809
1023
                        if ( 27 === key ) {
810
1024
                                buttons.children( '.cancel' ).click();
811
1025
                        }
818
1032
                editPermalink();
819
1033
        });
820
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
         */
821
1046
        wptitlehint = function(id) {
822
1047
                id = id || 'title';
823
1048
 
844
1069
 
845
1070
        wptitlehint();
846
1071
 
847
 
        // Resize the visual and text editors
 
1072
        // Resize the WYSIWYG and plain text editors.
848
1073
        ( function() {
849
1074
                var editor, offset, mce,
850
1075
                        $handle = $('#post-status-info'),
851
1076
                        $postdivrich = $('#postdivrich');
852
1077
 
853
 
                // No point for touch devices
 
1078
                // If there are no textareas or we are on a touch device, we can't do anything.
854
1079
                if ( ! $textarea.length || 'ontouchstart' in window ) {
855
 
                        // Hide the resize handle
 
1080
                        // Hide the resize handle.
856
1081
                        $('#content-resize-handle').hide();
857
1082
                        return;
858
1083
                }
859
1084
 
 
1085
                /**
 
1086
                 * Handle drag event.
 
1087
                 *
 
1088
                 * @param {Object} event Event containing details about the drag.
 
1089
                 */
860
1090
                function dragging( event ) {
861
1091
                        if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) {
862
1092
                                return;
871
1101
                        event.preventDefault();
872
1102
                }
873
1103
 
 
1104
                /**
 
1105
                 * When the dragging stopped make sure we return focus and do a sanity check on the height.
 
1106
                 */
874
1107
                function endDrag() {
875
1108
                        var height, toolbarHeight;
876
1109
 
894
1127
 
895
1128
                        $document.off( '.wp-editor-resize' );
896
1129
 
897
 
                        // sanity check
 
1130
                        // Sanity check: normalize height to stay within acceptable ranges.
898
1131
                        if ( height && height > 50 && height < 5000 ) {
899
1132
                                setUserSetting( 'ed_size', height );
900
1133
                        }
921
1154
                }).on( 'mouseup.wp-editor-resize', endDrag );
922
1155
        })();
923
1156
 
 
1157
        // TinyMCE specific handling of Post Format changes to reflect in the editor.
924
1158
        if ( typeof tinymce !== 'undefined' ) {
925
 
                // When changing post formats, change the editor body class
 
1159
                // When changing post formats, change the editor body class.
926
1160
                $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() {
927
1161
                        var editor, body, format = this.id;
928
1162
 
933
1167
                                $( document ).trigger( 'editor-classchange' );
934
1168
                        }
935
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
 
936
1187
        }
937
1188
 
938
 
        // Save on pressing Ctrl/Command + S in the Text editor
 
1189
        // Save on pressing [ctrl]/[command] + [s] in the Text editor.
939
1190
        $textarea.on( 'keydown.wp-autosave', function( event ) {
 
1191
                // Key [s] has code 83.
940
1192
                if ( event.which === 83 ) {
941
1193
                        if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) {
942
1194
                                return;
947
1199
                }
948
1200
        });
949
1201
 
 
1202
        // If the last status was auto-draft and the save is triggered, edit the current URL.
950
1203
        if ( $( '#original_post_status' ).val() === 'auto-draft' && window.history.replaceState ) {
951
1204
                var location;
952
1205
 
960
1213
        }
961
1214
});
962
1215
 
 
1216
/**
 
1217
 * TinyMCE word count display
 
1218
 */
963
1219
( function( $, counter ) {
964
1220
        $( function() {
965
1221
                var $content = $( '#content' ),
967
1223
                        prevCount = 0,
968
1224
                        contentEditor;
969
1225
 
 
1226
                /**
 
1227
                 * Get the word count from TinyMCE and display it
 
1228
                 */
970
1229
                function update() {
971
1230
                        var text, count;
972
1231
 
985
1244
                        prevCount = count;
986
1245
                }
987
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
                 */
988
1253
                $( document ).on( 'tinymce-editor-init', function( event, editor ) {
989
1254
                        if ( editor.id !== 'content' ) {
990
1255
                                return;