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

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + /**
2 + * Contains the postboxes logic, opening and closing postboxes, reordering and saving
3 + * the state and ordering to the database.
4 + *
5 + * @since 2.5.0
6 + * @requires jQuery
7 + * @output wp-admin/js/postbox.js
8 + */
9 +
10 + /* global ajaxurl, postboxes */
11 +
12 + (function($) {
13 + var $document = $( document ),
14 + __ = wp.i18n.__;
15 +
16 + /**
17 + * This object contains all function to handle the behavior of the post boxes. The post boxes are the boxes you see
18 + * around the content on the edit page.
19 + *
20 + * @since 2.7.0
21 + *
22 + * @namespace postboxes
23 + *
24 + * @type {Object}
25 + */
26 + window.postboxes = {
27 +
28 + /**
29 + * Handles a click on either the postbox heading or the postbox open/close icon.
30 + *
31 + * Opens or closes the postbox. Expects `this` to equal the clicked element.
32 + * Calls postboxes.pbshow if the postbox has been opened, calls postboxes.pbhide
33 + * if the postbox has been closed.
34 + *
35 + * @since 4.4.0
36 + *
37 + * @memberof postboxes
38 + *
39 + * @fires postboxes#postbox-toggled
40 + *
41 + * @return {void}
42 + */
43 + handle_click : function () {
44 + var $el = $( this ),
45 + p = $el.closest( '.postbox' ),
46 + id = p.attr( 'id' ),
47 + ariaExpandedValue;
48 +
49 + if ( 'dashboard_browser_nag' === id ) {
50 + return;
51 + }
52 +
53 + p.toggleClass( 'closed' );
54 + ariaExpandedValue = ! p.hasClass( 'closed' );
55 +
56 + if ( $el.hasClass( 'handlediv' ) ) {
57 + // The handle button was clicked.
58 + $el.attr( 'aria-expanded', ariaExpandedValue );
59 + } else {
60 + // The handle heading was clicked.
61 + $el.closest( '.postbox' ).find( 'button.handlediv' )
62 + .attr( 'aria-expanded', ariaExpandedValue );
63 + }
64 +
65 + if ( postboxes.page !== 'press-this' ) {
66 + postboxes.save_state( postboxes.page );
67 + }
68 +
69 + if ( id ) {
70 + if ( !p.hasClass('closed') && typeof postboxes.pbshow === 'function' ) {
71 + postboxes.pbshow( id );
72 + } else if ( p.hasClass('closed') && typeof postboxes.pbhide === 'function' ) {
73 + postboxes.pbhide( id );
74 + }
75 + }
76 +
77 + /**
78 + * Fires when a postbox has been opened or closed.
79 + *
80 + * Contains a jQuery object with the relevant postbox element.
81 + *
82 + * @since 4.0.0
83 + * @ignore
84 + *
85 + * @event postboxes#postbox-toggled
86 + * @type {Object}
87 + */
88 + $document.trigger( 'postbox-toggled', p );
89 + },
90 +
91 + /**
92 + * Handles clicks on the move up/down buttons.
93 + *
94 + * @since 5.5.0
95 + *
96 + * @return {void}
97 + */
98 + handleOrder: function() {
99 + var button = $( this ),
100 + postbox = button.closest( '.postbox' ),
101 + postboxId = postbox.attr( 'id' ),
102 + postboxesWithinSortables = postbox.closest( '.meta-box-sortables' ).find( '.postbox:visible' ),
103 + postboxesWithinSortablesCount = postboxesWithinSortables.length,
104 + postboxWithinSortablesIndex = postboxesWithinSortables.index( postbox ),
105 + firstOrLastPositionMessage;
106 +
107 + if ( 'dashboard_browser_nag' === postboxId ) {
108 + return;
109 + }
110 +
111 + // If on the first or last position, do nothing and send an audible message to screen reader users.
112 + if ( 'true' === button.attr( 'aria-disabled' ) ) {
113 + firstOrLastPositionMessage = button.hasClass( 'handle-order-higher' ) ?
114 + __( 'The box is on the first position' ) :
115 + __( 'The box is on the last position' );
116 +
117 + wp.a11y.speak( firstOrLastPositionMessage );
118 + return;
119 + }
120 +
121 + // Move a postbox up.
122 + if ( button.hasClass( 'handle-order-higher' ) ) {
123 + // If the box is first within a sortable area, move it to the previous sortable area.
124 + if ( 0 === postboxWithinSortablesIndex ) {
125 + postboxes.handleOrderBetweenSortables( 'previous', button, postbox );
126 + return;
127 + }
128 +
129 + postbox.prevAll( '.postbox:visible' ).eq( 0 ).before( postbox );
130 + button.trigger( 'focus' );
131 + postboxes.updateOrderButtonsProperties();
132 + postboxes.save_order( postboxes.page );
133 + }
134 +
135 + // Move a postbox down.
136 + if ( button.hasClass( 'handle-order-lower' ) ) {
137 + // If the box is last within a sortable area, move it to the next sortable area.
138 + if ( postboxWithinSortablesIndex + 1 === postboxesWithinSortablesCount ) {
139 + postboxes.handleOrderBetweenSortables( 'next', button, postbox );
140 + return;
141 + }
142 +
143 + postbox.nextAll( '.postbox:visible' ).eq( 0 ).after( postbox );
144 + button.trigger( 'focus' );
145 + postboxes.updateOrderButtonsProperties();
146 + postboxes.save_order( postboxes.page );
147 + }
148 +
149 + },
150 +
151 + /**
152 + * Moves postboxes between the sortables areas.
153 + *
154 + * @since 5.5.0
155 + *
156 + * @param {string} position The "previous" or "next" sortables area.
157 + * @param {Object} button The jQuery object representing the button that was clicked.
158 + * @param {Object} postbox The jQuery object representing the postbox to be moved.
159 + *
160 + * @return {void}
161 + */
162 + handleOrderBetweenSortables: function( position, button, postbox ) {
163 + var closestSortablesId = button.closest( '.meta-box-sortables' ).attr( 'id' ),
164 + sortablesIds = [],
165 + sortablesIndex,
166 + detachedPostbox;
167 +
168 + // Get the list of sortables within the page.
169 + $( '.meta-box-sortables:visible' ).each( function() {
170 + sortablesIds.push( $( this ).attr( 'id' ) );
171 + });
172 +
173 + // Return if there's only one visible sortables area, e.g. in the block editor page.
174 + if ( 1 === sortablesIds.length ) {
175 + return;
176 + }
177 +
178 + // Find the index of the current sortables area within all the sortable areas.
179 + sortablesIndex = $.inArray( closestSortablesId, sortablesIds );
180 + // Detach the postbox to be moved.
181 + detachedPostbox = postbox.detach();
182 +
183 + // Move the detached postbox to its new position.
184 + if ( 'previous' === position ) {
185 + $( detachedPostbox ).appendTo( '#' + sortablesIds[ sortablesIndex - 1 ] );
186 + }
187 +
188 + if ( 'next' === position ) {
189 + $( detachedPostbox ).prependTo( '#' + sortablesIds[ sortablesIndex + 1 ] );
190 + }
191 +
192 + postboxes._mark_area();
193 + button.focus();
194 + postboxes.updateOrderButtonsProperties();
195 + postboxes.save_order( postboxes.page );
196 + },
197 +
198 + /**
199 + * Update the move buttons properties depending on the postbox position.
200 + *
201 + * @since 5.5.0
202 + *
203 + * @return {void}
204 + */
205 + updateOrderButtonsProperties: function() {
206 + var firstSortablesId = $( '.meta-box-sortables:visible:first' ).attr( 'id' ),
207 + lastSortablesId = $( '.meta-box-sortables:visible:last' ).attr( 'id' ),
208 + firstPostbox = $( '.postbox:visible:first' ),
209 + lastPostbox = $( '.postbox:visible:last' ),
210 + firstPostboxId = firstPostbox.attr( 'id' ),
211 + lastPostboxId = lastPostbox.attr( 'id' ),
212 + firstPostboxSortablesId = firstPostbox.closest( '.meta-box-sortables' ).attr( 'id' ),
213 + lastPostboxSortablesId = lastPostbox.closest( '.meta-box-sortables' ).attr( 'id' ),
214 + moveUpButtons = $( '.handle-order-higher' ),
215 + moveDownButtons = $( '.handle-order-lower' );
216 +
217 + // Enable all buttons as a reset first.
218 + moveUpButtons
219 + .attr( 'aria-disabled', 'false' )
220 + .removeClass( 'hidden' );
221 + moveDownButtons
222 + .attr( 'aria-disabled', 'false' )
223 + .removeClass( 'hidden' );
224 +
225 + // When there's only one "sortables" area (e.g. in the block editor) and only one visible postbox, hide the buttons.
226 + if ( firstSortablesId === lastSortablesId && firstPostboxId === lastPostboxId ) {
227 + moveUpButtons.addClass( 'hidden' );
228 + moveDownButtons.addClass( 'hidden' );
229 + }
230 +
231 + // Set an aria-disabled=true attribute on the first visible "move" buttons.
232 + if ( firstSortablesId === firstPostboxSortablesId ) {
233 + $( firstPostbox ).find( '.handle-order-higher' ).attr( 'aria-disabled', 'true' );
234 + }
235 +
236 + // Set an aria-disabled=true attribute on the last visible "move" buttons.
237 + if ( lastSortablesId === lastPostboxSortablesId ) {
238 + $( '.postbox:visible .handle-order-lower' ).last().attr( 'aria-disabled', 'true' );
239 + }
240 + },
241 +
242 + /**
243 + * Adds event handlers to all postboxes and screen option on the current page.
244 + *
245 + * @since 2.7.0
246 + *
247 + * @memberof postboxes
248 + *
249 + * @param {string} page The page we are currently on.
250 + * @param {Object} [args]
251 + * @param {Function} args.pbshow A callback that is called when a postbox opens.
252 + * @param {Function} args.pbhide A callback that is called when a postbox closes.
253 + * @return {void}
254 + */
255 + add_postbox_toggles : function (page, args) {
256 + var $handles = $( '.postbox .hndle, .postbox .handlediv' ),
257 + $orderButtons = $( '.postbox .handle-order-higher, .postbox .handle-order-lower' );
258 +
259 + this.page = page;
260 + this.init( page, args );
261 +
262 + $handles.on( 'click.postboxes', this.handle_click );
263 +
264 + // Handle the order of the postboxes.
265 + $orderButtons.on( 'click.postboxes', this.handleOrder );
266 +
267 + /**
268 + * @since 2.7.0
269 + */
270 + $('.postbox .hndle a').on( 'click', function(e) {
271 + e.stopPropagation();
272 + });
273 +
274 + /**
275 + * Hides a postbox.
276 + *
277 + * Event handler for the postbox dismiss button. After clicking the button
278 + * the postbox will be hidden.
279 + *
280 + * As of WordPress 5.5, this is only used for the browser update nag.
281 + *
282 + * @since 3.2.0
283 + *
284 + * @return {void}
285 + */
286 + $( '.postbox a.dismiss' ).on( 'click.postboxes', function( e ) {
287 + var hide_id = $(this).parents('.postbox').attr('id') + '-hide';
288 + e.preventDefault();
289 + $( '#' + hide_id ).prop('checked', false).triggerHandler('click');
290 + });
291 +
292 + /**
293 + * Hides the postbox element
294 + *
295 + * Event handler for the screen options checkboxes. When a checkbox is
296 + * clicked this function will hide or show the relevant postboxes.
297 + *
298 + * @since 2.7.0
299 + * @ignore
300 + *
301 + * @fires postboxes#postbox-toggled
302 + *
303 + * @return {void}
304 + */
305 + $('.hide-postbox-tog').on('click.postboxes', function() {
306 + var $el = $(this),
307 + boxId = $el.val(),
308 + $postbox = $( '#' + boxId );
309 +
310 + if ( $el.prop( 'checked' ) ) {
311 + $postbox.show();
312 + if ( typeof postboxes.pbshow === 'function' ) {
313 + postboxes.pbshow( boxId );
314 + }
315 + } else {
316 + $postbox.hide();
317 + if ( typeof postboxes.pbhide === 'function' ) {
318 + postboxes.pbhide( boxId );
319 + }
320 + }
321 +
322 + postboxes.save_state( page );
323 + postboxes._mark_area();
324 +
325 + /**
326 + * @since 4.0.0
327 + * @see postboxes.handle_click
328 + */
329 + $document.trigger( 'postbox-toggled', $postbox );
330 + });
331 +
332 + /**
333 + * Changes the amount of columns based on the layout preferences.
334 + *
335 + * @since 2.8.0
336 + *
337 + * @return {void}
338 + */
339 + $('.columns-prefs input[type="radio"]').on('click.postboxes', function(){
340 + var n = parseInt($(this).val(), 10);
341 +
342 + if ( n ) {
343 + postboxes._pb_edit(n);
344 + postboxes.save_order( page );
345 + }
346 + });
347 + },
348 +
349 + /**
350 + * Initializes all the postboxes, mainly their sortable behavior.
351 + *
352 + * @since 2.7.0
353 + *
354 + * @memberof postboxes
355 + *
356 + * @param {string} page The page we are currently on.
357 + * @param {Object} [args={}] The arguments for the postbox initializer.
358 + * @param {Function} args.pbshow A callback that is called when a postbox opens.
359 + * @param {Function} args.pbhide A callback that is called when a postbox
360 + * closes.
361 + *
362 + * @return {void}
363 + */
364 + init : function(page, args) {
365 + var isMobile = $( document.body ).hasClass( 'mobile' ),
366 + $handleButtons = $( '.postbox .handlediv' );
367 +
368 + $.extend( this, args || {} );
369 + $('.meta-box-sortables').sortable({
370 + placeholder: 'sortable-placeholder',
371 + connectWith: '.meta-box-sortables',
372 + items: '.postbox',
373 + handle: '.hndle',
374 + cursor: 'move',
375 + delay: ( isMobile ? 200 : 0 ),
376 + distance: 2,
377 + tolerance: 'pointer',
378 + forcePlaceholderSize: true,
379 + helper: function( event, element ) {
380 + /* `helper: 'clone'` is equivalent to `return element.clone();`
381 + * Cloning a checked radio and then inserting that clone next to the original
382 + * radio unchecks the original radio (since only one of the two can be checked).
383 + * We get around this by renaming the helper's inputs' name attributes so that,
384 + * when the helper is inserted into the DOM for the sortable, no radios are
385 + * duplicated, and no original radio gets unchecked.
386 + */
387 + return element.clone()
388 + .find( ':input' )
389 + .attr( 'name', function( i, currentName ) {
390 + return 'sort_' + parseInt( Math.random() * 100000, 10 ).toString() + '_' + currentName;
391 + } )
392 + .end();
393 + },
394 + opacity: 0.65,
395 + start: function() {
396 + $( 'body' ).addClass( 'is-dragging-metaboxes' );
397 + // Refresh the cached positions of all the sortable items so that the min-height set while dragging works.
398 + $( '.meta-box-sortables' ).sortable( 'refreshPositions' );
399 + },
400 + stop: function() {
401 + var $el = $( this );
402 +
403 + $( 'body' ).removeClass( 'is-dragging-metaboxes' );
404 +
405 + if ( $el.find( '#dashboard_browser_nag' ).is( ':visible' ) && 'dashboard_browser_nag' != this.firstChild.id ) {
406 + $el.sortable('cancel');
407 + return;
408 + }
409 +
410 + postboxes.updateOrderButtonsProperties();
411 + postboxes.save_order(page);
412 + },
413 + receive: function(e,ui) {
414 + if ( 'dashboard_browser_nag' == ui.item[0].id )
415 + $(ui.sender).sortable('cancel');
416 +
417 + postboxes._mark_area();
418 + $document.trigger( 'postbox-moved', ui.item );
419 + }
420 + });
421 +
422 + if ( isMobile ) {
423 + $(document.body).on('orientationchange.postboxes', function(){ postboxes._pb_change(); });
424 + this._pb_change();
425 + }
426 +
427 + this._mark_area();
428 +
429 + // Update the "move" buttons properties.
430 + this.updateOrderButtonsProperties();
431 + $document.on( 'postbox-toggled', this.updateOrderButtonsProperties );
432 +
433 + // Set the handle buttons `aria-expanded` attribute initial value on page load.
434 + $handleButtons.each( function () {
435 + var $el = $( this );
436 + $el.attr( 'aria-expanded', ! $el.closest( '.postbox' ).hasClass( 'closed' ) );
437 + });
438 + },
439 +
440 + /**
441 + * Saves the state of the postboxes to the server.
442 + *
443 + * It sends two lists, one with all the closed postboxes, one with all the
444 + * hidden postboxes.
445 + *
446 + * @since 2.7.0
447 + *
448 + * @memberof postboxes
449 + *
450 + * @param {string} page The page we are currently on.
451 + * @return {void}
452 + */
453 + save_state : function(page) {
454 + var closed, hidden;
455 +
456 + // Return on the nav-menus.php screen, see #35112.
457 + if ( 'nav-menus' === page ) {
458 + return;
459 + }
460 +
461 + closed = $( '.postbox' ).filter( '.closed' ).map( function() { return this.id; } ).get().join( ',' );
462 + hidden = $( '.postbox' ).filter( ':hidden' ).map( function() { return this.id; } ).get().join( ',' );
463 +
464 + $.post(
465 + ajaxurl,
466 + {
467 + action: 'closed-postboxes',
468 + closed: closed,
469 + hidden: hidden,
470 + closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
471 + page: page
472 + },
473 + function() {
474 + wp.a11y.speak( __( 'Screen Options updated.' ) );
475 + }
476 + );
477 + },
478 +
479 + /**
480 + * Saves the order of the postboxes to the server.
481 + *
482 + * Sends a list of all postboxes inside a sortable area to the server.
483 + *
484 + * @since 2.8.0
485 + *
486 + * @memberof postboxes
487 + *
488 + * @param {string} page The page we are currently on.
489 + * @return {void}
490 + */
491 + save_order : function(page) {
492 + var postVars, page_columns = $('.columns-prefs input:checked').val() || 0;
493 +
494 + postVars = {
495 + action: 'meta-box-order',
496 + _ajax_nonce: $('#meta-box-order-nonce').val(),
497 + page_columns: page_columns,
498 + page: page
499 + };
500 +
501 + $('.meta-box-sortables').each( function() {
502 + postVars[ 'order[' + this.id.split( '-' )[0] + ']' ] = $( this ).sortable( 'toArray' ).join( ',' );
503 + } );
504 +
505 + $.post(
506 + ajaxurl,
507 + postVars,
508 + function( response ) {
509 + if ( response.success ) {
510 + wp.a11y.speak( __( 'The boxes order has been saved.' ) );
511 + }
512 + }
513 + );
514 + },
515 +
516 + /**
517 + * Marks empty postbox areas.
518 + *
519 + * Adds a message to empty sortable areas on the dashboard page. Also adds a
520 + * border around the side area on the post edit screen if there are no postboxes
521 + * present.
522 + *
523 + * @since 3.3.0
524 + * @access private
525 + *
526 + * @memberof postboxes
527 + *
528 + * @return {void}
529 + */
530 + _mark_area : function() {
531 + var visible = $( 'div.postbox:visible' ).length,
532 + visibleSortables = $( '#dashboard-widgets .meta-box-sortables:visible, #post-body .meta-box-sortables:visible' ),
533 + areAllVisibleSortablesEmpty = true;
534 +
535 + visibleSortables.each( function() {
536 + var t = $(this);
537 +
538 + if ( visible == 1 || t.children( '.postbox:visible' ).length ) {
539 + t.removeClass('empty-container');
540 + areAllVisibleSortablesEmpty = false;
541 + }
542 + else {
543 + t.addClass('empty-container');
544 + }
545 + });
546 +
547 + postboxes.updateEmptySortablesText( visibleSortables, areAllVisibleSortablesEmpty );
548 + },
549 +
550 + /**
551 + * Updates the text for the empty sortable areas on the Dashboard.
552 + *
553 + * @since 5.5.0
554 + *
555 + * @param {Object} visibleSortables The jQuery object representing the visible sortable areas.
556 + * @param {boolean} areAllVisibleSortablesEmpty Whether all the visible sortable areas are "empty".
557 + *
558 + * @return {void}
559 + */
560 + updateEmptySortablesText: function( visibleSortables, areAllVisibleSortablesEmpty ) {
561 + var isDashboard = $( '#dashboard-widgets' ).length,
562 + emptySortableText = areAllVisibleSortablesEmpty ? __( 'Add boxes from the Screen Options menu' ) : __( 'Drag boxes here' );
563 +
564 + if ( ! isDashboard ) {
565 + return;
566 + }
567 +
568 + visibleSortables.each( function() {
569 + if ( $( this ).hasClass( 'empty-container' ) ) {
570 + $( this ).attr( 'data-emptyString', emptySortableText );
571 + }
572 + } );
573 + },
574 +
575 + /**
576 + * Changes the amount of columns on the post edit page.
577 + *
578 + * @since 3.3.0
579 + * @access private
580 + *
581 + * @memberof postboxes
582 + *
583 + * @fires postboxes#postboxes-columnchange
584 + *
585 + * @param {number} n The amount of columns to divide the post edit page in.
586 + * @return {void}
587 + */
588 + _pb_edit : function(n) {
589 + var el = $('.metabox-holder').get(0);
590 +
591 + if ( el ) {
592 + el.className = el.className.replace(/columns-\d+/, 'columns-' + n);
593 + }
594 +
595 + /**
596 + * Fires when the amount of columns on the post edit page has been changed.
597 + *
598 + * @since 4.0.0
599 + * @ignore
600 + *
601 + * @event postboxes#postboxes-columnchange
602 + */
603 + $( document ).trigger( 'postboxes-columnchange' );
604 + },
605 +
606 + /**
607 + * Changes the amount of columns the postboxes are in based on the current
608 + * orientation of the browser.
609 + *
610 + * @since 3.3.0
611 + * @access private
612 + *
613 + * @memberof postboxes
614 + *
615 + * @return {void}
616 + */
617 + _pb_change : function() {
618 + var check = $( 'label.columns-prefs-1 input[type="radio"]' );
619 +
620 + switch ( window.orientation ) {
621 + case 90:
622 + case -90:
623 + if ( !check.length || !check.is(':checked') )
624 + this._pb_edit(2);
625 + break;
626 + case 0:
627 + case 180:
628 + if ( $( '#poststuff' ).length ) {
629 + this._pb_edit(1);
630 + } else {
631 + if ( !check.length || !check.is(':checked') )
632 + this._pb_edit(2);
633 + }
634 + break;
635 + }
636 + },
637 +
638 + /* Callbacks */
639 +
640 + /**
641 + * @since 2.7.0
642 + * @access public
643 + *
644 + * @property {Function|boolean} pbshow A callback that is called when a postbox
645 + * is opened.
646 + * @memberof postboxes
647 + */
648 + pbshow : false,
649 +
650 + /**
651 + * @since 2.7.0
652 + * @access public
653 + * @property {Function|boolean} pbhide A callback that is called when a postbox
654 + * is closed.
655 + * @memberof postboxes
656 + */
657 + pbhide : false
658 + };
659 +
660 + }(jQuery));
661 +