wp/wp-admin/js/postbox.js
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
--- a/wp/wp-admin/js/postbox.js	Tue Jun 09 11:14:17 2015 +0000
+++ b/wp/wp-admin/js/postbox.js	Mon Oct 14 17:39:30 2019 +0200
@@ -1,77 +1,207 @@
-/* global ajaxurl */
+/**
+ * Contains the postboxes logic, opening and closing postboxes, reordering and saving
+ * the state and ordering to the database.
+ *
+ * @summary Contains postboxes logic
+ *
+ * @since 2.5.0
+ * @requires jQuery
+ */
 
+/* global ajaxurl, postBoxL10n */
+
+/**
+ * This object contains all function to handle the behaviour of the post boxes. The post boxes are the boxes you see
+ * around the content on the edit page.
+ *
+ * @since 2.7.0
+ *
+ * @namespace postboxes
+ *
+ * @type {Object}
+ */
 var postboxes;
 
 (function($) {
 	var $document = $( document );
 
 	postboxes = {
-		add_postbox_toggles : function(page, args) {
-			var self = this;
 
-			self.init(page, args);
+		/**
+		 * @summary Handles a click on either the postbox heading or the postbox open/close icon.
+		 *
+		 * Opens or closes the postbox. Expects `this` to equal the clicked element.
+		 * Calls postboxes.pbshow if the postbox has been opened, calls postboxes.pbhide
+		 * if the postbox has been closed.
+		 *
+		 * @since 4.4.0
+		 * @memberof postboxes
+		 * @fires postboxes#postbox-toggled
+		 *
+		 * @returns {void}
+		 */
+		handle_click : function () {
+			var $el = $( this ),
+				p = $el.parent( '.postbox' ),
+				id = p.attr( 'id' ),
+				ariaExpandedValue;
 
-			$('.postbox .hndle, .postbox .handlediv').bind('click.postboxes', function() {
-				var p = $(this).parent('.postbox'), id = p.attr('id');
+			if ( 'dashboard_browser_nag' === id ) {
+				return;
+			}
+
+			p.toggleClass( 'closed' );
+
+			ariaExpandedValue = ! p.hasClass( 'closed' );
 
-				if ( 'dashboard_browser_nag' == id )
-					return;
+			if ( $el.hasClass( 'handlediv' ) ) {
+				// The handle button was clicked.
+				$el.attr( 'aria-expanded', ariaExpandedValue );
+			} else {
+				// The handle heading was clicked.
+				$el.closest( '.postbox' ).find( 'button.handlediv' )
+					.attr( 'aria-expanded', ariaExpandedValue );
+			}
 
-				p.toggleClass('closed');
+			if ( postboxes.page !== 'press-this' ) {
+				postboxes.save_state( postboxes.page );
+			}
 
-				if ( page != 'press-this' )
-					self.save_state(page);
+			if ( id ) {
+				if ( !p.hasClass('closed') && $.isFunction( postboxes.pbshow ) ) {
+					postboxes.pbshow( id );
+				} else if ( p.hasClass('closed') && $.isFunction( postboxes.pbhide ) ) {
+					postboxes.pbhide( id );
+				}
+			}
+
+			/**
+			 * @summary Fires when a postbox has been opened or closed.
+			 *
+			 * Contains a jQuery object with the relevant postbox element.
+			 *
+			 * @since 4.0.0
+			 * @event postboxes#postbox-toggled
+			 * @type {Object}
+			 */
+			$document.trigger( 'postbox-toggled', p );
+		},
 
-				if ( id ) {
-					if ( !p.hasClass('closed') && $.isFunction(postboxes.pbshow) )
-						self.pbshow(id);
-					else if ( p.hasClass('closed') && $.isFunction(postboxes.pbhide) )
-						self.pbhide(id);
-				}
+		/**
+		 * Adds event handlers to all postboxes and screen option on the current page.
+		 *
+		 * @since 2.7.0
+		 * @memberof postboxes
+		 *
+		 * @param {string} page The page we are currently on.
+		 * @param {Object} [args]
+		 * @param {Function} args.pbshow A callback that is called when a postbox opens.
+		 * @param {Function} args.pbhide A callback that is called when a postbox closes.
+		 * @returns {void}
+		 */
+		add_postbox_toggles : function (page, args) {
+			var $handles = $( '.postbox .hndle, .postbox .handlediv' );
 
-				$document.trigger( 'postbox-toggled', p );
-			});
+			this.page = page;
+			this.init( page, args );
 
+			$handles.on( 'click.postboxes', this.handle_click );
+
+			/**
+			 * @since 2.7.0
+			 */
 			$('.postbox .hndle a').click( function(e) {
 				e.stopPropagation();
 			});
 
-			$( '.postbox a.dismiss' ).bind( 'click.postboxes', function() {
+			/**
+			 * @summary Hides a postbox.
+			 *
+			 * Event handler for the postbox dismiss button. After clicking the button
+			 * the postbox will be hidden.
+			 *
+			 * @since 3.2.0
+			 *
+			 * @returns {void}
+			 */
+			$( '.postbox a.dismiss' ).on( 'click.postboxes', function( e ) {
 				var hide_id = $(this).parents('.postbox').attr('id') + '-hide';
+				e.preventDefault();
 				$( '#' + hide_id ).prop('checked', false).triggerHandler('click');
-				return false;
 			});
 
+			/**
+			 * @summary Hides the postbox element
+			 *
+			 * Event handler for the screen options checkboxes. When a checkbox is
+			 * clicked this function will hide or show the relevant postboxes.
+			 *
+			 * @since 2.7.0
+			 * @fires postboxes#postbox-toggled
+			 *
+			 * @returns {void}
+			 */
 			$('.hide-postbox-tog').bind('click.postboxes', function() {
-				var boxId = $(this).val(),
+				var $el = $(this),
+					boxId = $el.val(),
 					$postbox = $( '#' + boxId );
 
-				if ( $(this).prop('checked') ) {
+				if ( $el.prop( 'checked' ) ) {
 					$postbox.show();
-					if ( $.isFunction( postboxes.pbshow ) )
-						self.pbshow( boxId );
+					if ( $.isFunction( postboxes.pbshow ) ) {
+						postboxes.pbshow( boxId );
+					}
 				} else {
 					$postbox.hide();
-					if ( $.isFunction( postboxes.pbhide ) )
-						self.pbhide( boxId );
+					if ( $.isFunction( postboxes.pbhide ) ) {
+						postboxes.pbhide( boxId );
+					}
 				}
-				self.save_state(page);
-				self._mark_area();
+
+				postboxes.save_state( page );
+				postboxes._mark_area();
+
+				/**
+				 * @since 4.0.0
+				 * @see postboxes.handle_click
+				 */
 				$document.trigger( 'postbox-toggled', $postbox );
 			});
 
+			/**
+			 * @summary Changes the amount of columns based on the layout preferences.
+			 *
+			 * @since 2.8.0
+			 *
+			 * @returns {void}
+			 */
 			$('.columns-prefs input[type="radio"]').bind('click.postboxes', function(){
 				var n = parseInt($(this).val(), 10);
 
 				if ( n ) {
-					self._pb_edit(n);
-					self.save_order(page);
+					postboxes._pb_edit(n);
+					postboxes.save_order( page );
 				}
 			});
 		},
 
+		/**
+		 * @summary Initializes all the postboxes, mainly their sortable behaviour.
+		 *
+		 * @since 2.7.0
+		 * @memberof postboxes
+		 *
+		 * @param {string} page The page we are currently on.
+		 * @param {Object} [args={}] The arguments for the postbox initializer.
+		 * @param {Function} args.pbshow A callback that is called when a postbox opens.
+		 * @param {Function} args.pbhide A callback that is called when a postbox
+		 *                               closes.
+		 *
+		 * @returns {void}
+		 */
 		init : function(page, args) {
-			var isMobile = $(document.body).hasClass('mobile');
+			var isMobile = $( document.body ).hasClass( 'mobile' ),
+				$handleButtons = $( '.postbox .handlediv' );
 
 			$.extend( this, args || {} );
 			$('#wpbody-content').css('overflow','hidden');
@@ -85,11 +215,27 @@
 				distance: 2,
 				tolerance: 'pointer',
 				forcePlaceholderSize: true,
-				helper: 'clone',
+				helper: function( event, element ) {
+					/* `helper: 'clone'` is equivalent to `return element.clone();`
+					 * Cloning a checked radio and then inserting that clone next to the original
+					 * radio unchecks the original radio (since only one of the two can be checked).
+					 * We get around this by renaming the helper's inputs' name attributes so that,
+					 * when the helper is inserted into the DOM for the sortable, no radios are
+					 * duplicated, and no original radio gets unchecked.
+					 */
+					return element.clone()
+						.find( ':input' )
+							.attr( 'name', function( i, currentName ) {
+								return 'sort_' + parseInt( Math.random() * 100000, 10 ).toString() + '_' + currentName;
+							} )
+						.end();
+				},
 				opacity: 0.65,
 				stop: function() {
-					if ( $(this).find('#dashboard_browser_nag').is(':visible') && 'dashboard_browser_nag' != this.firstChild.id ) {
-						$(this).sortable('cancel');
+					var $el = $( this );
+
+					if ( $el.find( '#dashboard_browser_nag' ).is( ':visible' ) && 'dashboard_browser_nag' != this.firstChild.id ) {
+						$el.sortable('cancel');
 						return;
 					}
 
@@ -100,6 +246,7 @@
 						$(ui.sender).sortable('cancel');
 
 					postboxes._mark_area();
+					$document.trigger( 'postbox-moved', ui.item );
 				}
 			});
 
@@ -109,11 +256,36 @@
 			}
 
 			this._mark_area();
+
+			// Set the handle buttons `aria-expanded` attribute initial value on page load.
+			$handleButtons.each( function () {
+				var $el = $( this );
+				$el.attr( 'aria-expanded', ! $el.parent( '.postbox' ).hasClass( 'closed' ) );
+			});
 		},
 
+		/**
+		 * @summary Saves the state of the postboxes to the server.
+		 *
+		 * Saves the state of the postboxes to the server. It sends two lists, one with
+		 * all the closed postboxes, one with all the hidden postboxes.
+		 *
+		 * @since 2.7.0
+		 * @memberof postboxes
+		 *
+		 * @param {string} page The page we are currently on.
+		 * @returns {void}
+		 */
 		save_state : function(page) {
-			var closed = $('.postbox').filter('.closed').map(function() { return this.id; }).get().join(','),
-				hidden = $('.postbox').filter(':hidden').map(function() { return this.id; }).get().join(',');
+			var closed, hidden;
+
+			// Return on the nav-menus.php screen, see #35112.
+			if ( 'nav-menus' === page ) {
+				return;
+			}
+
+			closed = $( '.postbox' ).filter( '.closed' ).map( function() { return this.id; } ).get().join( ',' );
+			hidden = $( '.postbox' ).filter( ':hidden' ).map( function() { return this.id; } ).get().join( ',' );
 
 			$.post(ajaxurl, {
 				action: 'closed-postboxes',
@@ -124,6 +296,18 @@
 			});
 		},
 
+		/**
+		 * @summary Saves the order of the postboxes to the server.
+		 *
+		 * Saves the order of the postboxes to the server. Sends a list of all postboxes
+		 * inside a sortable area to the server.
+		 *
+		 * @since 2.8.0
+		 * @memberof postboxes
+		 *
+		 * @param {string} page The page we are currently on.
+		 * @returns {void}
+		 */
 		save_order : function(page) {
 			var postVars, page_columns = $('.columns-prefs input:checked').val() || 0;
 
@@ -133,22 +317,40 @@
 				page_columns: page_columns,
 				page: page
 			};
+
 			$('.meta-box-sortables').each( function() {
 				postVars[ 'order[' + this.id.split( '-' )[0] + ']' ] = $( this ).sortable( 'toArray' ).join( ',' );
 			} );
+
 			$.post( ajaxurl, postVars );
 		},
 
+		/**
+		 * @summary Marks empty postbox areas.
+		 *
+		 * Adds a message to empty sortable areas on the dashboard page. Also adds a
+		 * border around the side area on the post edit screen if there are no postboxes
+		 * present.
+		 *
+		 * @since 3.3.0
+		 * @memberof postboxes
+		 * @access private
+		 *
+		 * @returns {void}
+		 */
 		_mark_area : function() {
 			var visible = $('div.postbox:visible').length, side = $('#post-body #side-sortables');
 
 			$( '#dashboard-widgets .meta-box-sortables:visible' ).each( function() {
 				var t = $(this);
 
-				if ( visible == 1 || t.children('.postbox:visible').length )
+				if ( visible == 1 || t.children('.postbox:visible').length ) {
 					t.removeClass('empty-container');
-				else
+				}
+				else {
 					t.addClass('empty-container');
+					t.attr('data-emptyString', postBoxL10n.postBoxEmptyString);
+				}
 			});
 
 			if ( side.length ) {
@@ -159,6 +361,17 @@
 			}
 		},
 
+		/**
+		 * @summary Changes the amount of columns on the post edit page.
+		 *
+		 * @since 3.3.0
+		 * @memberof postboxes
+		 * @fires postboxes#postboxes-columnchange
+		 * @access private
+		 *
+		 * @param {number} n The amount of columns to divide the post edit page in.
+		 * @returns {void}
+		 */
 		_pb_edit : function(n) {
 			var el = $('.metabox-holder').get(0);
 
@@ -166,9 +379,25 @@
 				el.className = el.className.replace(/columns-\d+/, 'columns-' + n);
 			}
 
+			/**
+			 * Fires when the amount of columns on the post edit page has been changed.
+			 *
+			 * @since 4.0.0
+			 * @event postboxes#postboxes-columnchange
+			 */
 			$( document ).trigger( 'postboxes-columnchange' );
 		},
 
+		/**
+		 * @summary Changes the amount of columns the postboxes are in based on the
+		 *          current orientation of the browser.
+		 *
+		 * @since 3.3.0
+		 * @memberof postboxes
+		 * @access private
+		 *
+		 * @returns {void}
+		 */
 		_pb_change : function() {
 			var check = $( 'label.columns-prefs-1 input[type="radio"]' );
 
@@ -191,8 +420,23 @@
 		},
 
 		/* Callbacks */
+
+		/**
+		 * @since 2.7.0
+		 * @memberof postboxes
+		 * @access public
+		 * @property {Function|boolean} pbshow A callback that is called when a postbox
+		 *                                     is opened.
+		 */
 		pbshow : false,
 
+		/**
+		 * @since 2.7.0
+		 * @memberof postboxes
+		 * @access public
+		 * @property {Function|boolean} pbhide A callback that is called when a postbox
+		 *                                     is closed.
+		 */
 		pbhide : false
 	};