]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-admin/js/customize-nav-menus.js
WordPress 4.7
[autoinstalls/wordpress.git] / wp-admin / js / customize-nav-menus.js
index 25090359512f60be57689e66f9555463d316b67c..b7556f6702ccaae7dd34f5ac0e962054943fc293 100644 (file)
        });
        api.Menus.availableMenuItems = new api.Menus.AvailableItemCollection( api.Menus.data.availableMenuItems );
 
+       /**
+        * Insert a new `auto-draft` post.
+        *
+        * @since 4.7.0
+        * @access public
+        *
+        * @param {object} params - Parameters for the draft post to create.
+        * @param {string} params.post_type - Post type to add.
+        * @param {string} params.post_title - Post title to use.
+        * @return {jQuery.promise} Promise resolved with the added post.
+        */
+       api.Menus.insertAutoDraftPost = function insertAutoDraftPost( params ) {
+               var request, deferred = $.Deferred();
+
+               request = wp.ajax.post( 'customize-nav-menus-insert-auto-draft', {
+                       'customize-menus-nonce': api.settings.nonce['customize-menus'],
+                       'wp_customize': 'on',
+                       'params': params
+               } );
+
+               request.done( function( response ) {
+                       if ( response.post_id ) {
+                               api( 'nav_menus_created_posts' ).set(
+                                       api( 'nav_menus_created_posts' ).get().concat( [ response.post_id ] )
+                               );
+
+                               if ( 'page' === params.post_type ) {
+
+                                       // Activate static front page controls as this could be the first page created.
+                                       if ( api.section.has( 'static_front_page' ) ) {
+                                               api.section( 'static_front_page' ).activate();
+                                       }
+
+                                       // Add new page to dropdown-pages controls.
+                                       api.control.each( function( control ) {
+                                               var select;
+                                               if ( 'dropdown-pages' === control.params.type ) {
+                                                       select = control.container.find( 'select[name^="_customize-dropdown-pages-"]' );
+                                                       select.append( new Option( params.post_title, response.post_id ) );
+                                               }
+                                       } );
+                               }
+                               deferred.resolve( response );
+                       }
+               } );
+
+               request.fail( function( response ) {
+                       var error = response || '';
+
+                       if ( 'undefined' !== typeof response.message ) {
+                               error = response.message;
+                       }
+
+                       console.error( error );
+                       deferred.rejectWith( error );
+               } );
+
+               return deferred.promise();
+       };
+
        /**
         * wp.customize.Menus.AvailableMenuItemsPanelView
         *
                        'click .menu-item-tpl': '_submit',
                        'click #custom-menu-item-submit': '_submitLink',
                        'keypress #custom-menu-item-name': '_submitLink',
+                       'click .new-content-item .add-content': '_submitNew',
+                       'keypress .create-item-input': '_submitNew',
                        'keydown': 'keyboardAccessible'
                },
 
                currentMenuControl: null,
                debounceSearch: null,
                $search: null,
+               $clearResults: null,
                searchTerm: '',
                rendered: false,
                pages: {},
                sectionContent: '',
                loading: false,
+               addingNew: false,
 
                initialize: function() {
                        var self = this;
                        }
 
                        this.$search = $( '#menu-items-search' );
-                       this.sectionContent = this.$el.find( '.accordion-section-content' );
+                       this.$clearResults = this.$el.find( '.clear-results' );
+                       this.sectionContent = this.$el.find( '.available-menu-items-list' );
 
                        this.debounceSearch = _.debounce( self.search, 500 );
 
                                }
                        } );
 
-                       // Clear the search results.
-                       $( '.clear-results' ).on( 'click', function() {
+                       // Clear the search results and trigger a `keyup` event to fire a new search.
+                       this.$clearResults.on( 'click', function() {
                                self.$search.val( '' ).focus().trigger( 'keyup' );
                        } );
 
 
                        // Load more items.
                        this.sectionContent.scroll( function() {
-                               var totalHeight = self.$el.find( '.accordion-section.open .accordion-section-content' ).prop( 'scrollHeight' ),
+                               var totalHeight = self.$el.find( '.accordion-section.open .available-menu-items-list' ).prop( 'scrollHeight' ),
                                        visibleHeight = self.$el.find( '.accordion-section.open' ).height();
 
                                if ( ! self.loading && $( this ).scrollTop() > 3 / 4 * totalHeight - visibleHeight ) {
                                                        self.doSearch( self.pages.search );
                                                }
                                        } else {
-                                               self.loadItems( type, object );
+                                               self.loadItems( [
+                                                       { type: type, object: object }
+                                               ] );
                                        }
                                }
                        });
                                $otherSections.fadeOut( 100 );
                                $searchSection.find( '.accordion-section-content' ).slideDown( 'fast' );
                                $searchSection.addClass( 'open' );
-                               $searchSection.find( '.clear-results' ).addClass( 'is-visible' );
+                               this.$clearResults.addClass( 'is-visible' );
                        } else if ( '' === event.target.value ) {
                                $searchSection.removeClass( 'open' );
                                $otherSections.show();
-                               $searchSection.find( '.clear-results' ).removeClass( 'is-visible' );
+                               this.$clearResults.removeClass( 'is-visible' );
                        }
 
                        this.searchTerm = event.target.value;
 
                        $section.addClass( 'loading' );
                        self.loading = true;
-                       params = {
+
+                       params = api.previewer.query( { excludeCustomizedSaved: true } );
+                       _.extend( params, {
                                'customize-menus-nonce': api.settings.nonce['customize-menus'],
                                'wp_customize': 'on',
                                'search': self.searchTerm,
                                'page': page
-                       };
+                       } );
 
                        self.currentRequest = wp.ajax.post( 'search-available-menu-items-customizer', params );
 
                        self.currentRequest.fail(function( data ) {
                                // data.message may be undefined, for example when typing slow and the request is aborted.
                                if ( data.message ) {
-                                       $content.empty().append( $( '<p class="nothing-found"></p>' ).text( data.message ) );
+                                       $content.empty().append( $( '<li class="nothing-found"></li>' ).text( data.message ) );
                                        wp.a11y.speak( data.message );
                                }
                                self.pages.search = -1;
                        // Render the template for each item by type.
                        _.each( api.Menus.data.itemTypes, function( itemType ) {
                                self.pages[ itemType.type + ':' + itemType.object ] = 0;
-                               self.loadItems( itemType.type, itemType.object ); // @todo we need to combine these Ajax requests.
                        } );
+                       self.loadItems( api.Menus.data.itemTypes );
                },
 
-               // Load available menu items.
-               loadItems: function( type, object ) {
-                       var self = this, params, request, itemTemplate, availableMenuItemContainer;
+               /**
+                * Load available nav menu items.
+                *
+                * @since 4.3.0
+                * @since 4.7.0 Changed function signature to take list of item types instead of single type/object.
+                * @access private
+                *
+                * @param {Array.<object>} itemTypes List of objects containing type and key.
+                * @param {string} deprecated Formerly the object parameter.
+                * @returns {void}
+                */
+               loadItems: function( itemTypes, deprecated ) {
+                       var self = this, _itemTypes, requestItemTypes = [], params, request, itemTemplate, availableMenuItemContainers = {};
                        itemTemplate = wp.template( 'available-menu-item' );
 
-                       if ( -1 === self.pages[ type + ':' + object ] ) {
+                       if ( _.isString( itemTypes ) && _.isString( deprecated ) ) {
+                               _itemTypes = [ { type: itemTypes, object: deprecated } ];
+                       } else {
+                               _itemTypes = itemTypes;
+                       }
+
+                       _.each( _itemTypes, function( itemType ) {
+                               var container, name = itemType.type + ':' + itemType.object;
+                               if ( -1 === self.pages[ name ] ) {
+                                       return; // Skip types for which there are no more results.
+                               }
+                               container = $( '#available-menu-items-' + itemType.type + '-' + itemType.object );
+                               container.find( '.accordion-section-title' ).addClass( 'loading' );
+                               availableMenuItemContainers[ name ] = container;
+
+                               requestItemTypes.push( {
+                                       object: itemType.object,
+                                       type: itemType.type,
+                                       page: self.pages[ name ]
+                               } );
+                       } );
+
+                       if ( 0 === requestItemTypes.length ) {
                                return;
                        }
-                       availableMenuItemContainer = $( '#available-menu-items-' + type + '-' + object );
-                       availableMenuItemContainer.find( '.accordion-section-title' ).addClass( 'loading' );
+
                        self.loading = true;
-                       params = {
+
+                       params = api.previewer.query( { excludeCustomizedSaved: true } );
+                       _.extend( params, {
                                'customize-menus-nonce': api.settings.nonce['customize-menus'],
                                'wp_customize': 'on',
-                               'type': type,
-                               'object': object,
-                               'page': self.pages[ type + ':' + object ]
-                       };
+                               'item_types': requestItemTypes
+                       } );
+
                        request = wp.ajax.post( 'load-available-menu-items-customizer', params );
 
                        request.done(function( data ) {
-                               var items, typeInner;
-                               items = data.items;
-                               if ( 0 === items.length ) {
-                                       if ( 0 === self.pages[ type + ':' + object ] ) {
-                                               availableMenuItemContainer
-                                                       .addClass( 'cannot-expand' )
-                                                       .removeClass( 'loading' )
-                                                       .find( '.accordion-section-title > button' )
-                                                       .prop( 'tabIndex', -1 );
+                               var typeInner;
+                               _.each( data.items, function( typeItems, name ) {
+                                       if ( 0 === typeItems.length ) {
+                                               if ( 0 === self.pages[ name ] ) {
+                                                       availableMenuItemContainers[ name ].find( '.accordion-section-title' )
+                                                               .addClass( 'cannot-expand' )
+                                                               .removeClass( 'loading' )
+                                                               .find( '.accordion-section-title > button' )
+                                                               .prop( 'tabIndex', -1 );
+                                               }
+                                               self.pages[ name ] = -1;
+                                               return;
+                                       } else if ( ( 'post_type:page' === name ) && ( ! availableMenuItemContainers[ name ].hasClass( 'open' ) ) ) {
+                                               availableMenuItemContainers[ name ].find( '.accordion-section-title > button' ).click();
                                        }
-                                       self.pages[ type + ':' + object ] = -1;
-                                       return;
-                               }
-                               items = new api.Menus.AvailableItemCollection( items ); // @todo Why is this collection created and then thrown away?
-                               self.collection.add( items.models );
-                               typeInner = availableMenuItemContainer.find( '.accordion-section-content' );
-                               items.each(function( menuItem ) {
-                                       typeInner.append( itemTemplate( menuItem.attributes ) );
+                                       typeItems = new api.Menus.AvailableItemCollection( typeItems ); // @todo Why is this collection created and then thrown away?
+                                       self.collection.add( typeItems.models );
+                                       typeInner = availableMenuItemContainers[ name ].find( '.available-menu-items-list' );
+                                       typeItems.each( function( menuItem ) {
+                                               typeInner.append( itemTemplate( menuItem.attributes ) );
+                                       } );
+                                       self.pages[ name ] += 1;
                                });
-                               self.pages[ type + ':' + object ] += 1;
                        });
                        request.fail(function( data ) {
                                if ( typeof console !== 'undefined' && console.error ) {
                                }
                        });
                        request.always(function() {
-                               availableMenuItemContainer.find( '.accordion-section-title' ).removeClass( 'loading' );
+                               _.each( availableMenuItemContainers, function( container ) {
+                                       container.find( '.accordion-section-title' ).removeClass( 'loading' );
+                               } );
                                self.loading = false;
                        });
                },
 
                // Adjust the height of each section of items to fit the screen.
                itemSectionHeight: function() {
-                       var sections, totalHeight, accordionHeight, diff;
+                       var sections, lists, totalHeight, accordionHeight, diff;
                        totalHeight = window.innerHeight;
                        sections = this.$el.find( '.accordion-section:not( #available-menu-items-search ) .accordion-section-content' );
-                       accordionHeight =  46 * ( 2 + sections.length ) - 13; // Magic numbers.
+                       lists = this.$el.find( '.accordion-section:not( #available-menu-items-search ) .available-menu-items-list:not(":only-child")' );
+                       accordionHeight =  46 * ( 1 + sections.length ) + 14; // Magic numbers.
                        diff = totalHeight - accordionHeight;
                        if ( 120 < diff && 290 > diff ) {
                                sections.css( 'max-height', diff );
+                               lists.css( 'max-height', ( diff - 60 ) );
                        }
                },
 
                                'url': itemUrl.val(),
                                'type': 'custom',
                                'type_label': api.Menus.data.l10n.custom_label,
-                               'object': ''
+                               'object': 'custom'
                        };
 
                        this.currentMenuControl.addItemToMenu( menuItem );
                        itemName.val( '' );
                },
 
+               /**
+                * Submit handler for keypress (enter) on field and click on button.
+                *
+                * @since 4.7.0
+                * @private
+                *
+                * @param {jQuery.Event} event Event.
+                * @returns {void}
+                */
+               _submitNew: function( event ) {
+                       var container;
+
+                       // Only proceed with keypress if it is Enter.
+                       if ( 'keypress' === event.type && 13 !== event.which ) {
+                               return;
+                       }
+
+                       if ( this.addingNew ) {
+                               return;
+                       }
+
+                       container = $( event.target ).closest( '.accordion-section' );
+
+                       this.submitNew( container );
+               },
+
+               /**
+                * Creates a new object and adds an associated menu item to the menu.
+                *
+                * @since 4.7.0
+                * @private
+                *
+                * @param {jQuery} container
+                * @returns {void}
+                */
+               submitNew: function( container ) {
+                       var panel = this,
+                               itemName = container.find( '.create-item-input' ),
+                               title = itemName.val(),
+                               dataContainer = container.find( '.available-menu-items-list' ),
+                               itemType = dataContainer.data( 'type' ),
+                               itemObject = dataContainer.data( 'object' ),
+                               itemTypeLabel = dataContainer.data( 'type_label' ),
+                               promise;
+
+                       if ( ! this.currentMenuControl ) {
+                               return;
+                       }
+
+                       // Only posts are supported currently.
+                       if ( 'post_type' !== itemType ) {
+                               return;
+                       }
+
+                       if ( '' === $.trim( itemName.val() ) ) {
+                               itemName.addClass( 'invalid' );
+                               itemName.focus();
+                               return;
+                       } else {
+                               itemName.removeClass( 'invalid' );
+                               container.find( '.accordion-section-title' ).addClass( 'loading' );
+                       }
+
+                       panel.addingNew = true;
+                       itemName.attr( 'disabled', 'disabled' );
+                       promise = api.Menus.insertAutoDraftPost( {
+                               post_title: title,
+                               post_type: itemObject
+                       } );
+                       promise.done( function( data ) {
+                               var availableItem, $content, itemElement;
+                               availableItem = new api.Menus.AvailableItemModel( {
+                                       'id': 'post-' + data.post_id, // Used for available menu item Backbone models.
+                                       'title': itemName.val(),
+                                       'type': itemType,
+                                       'type_label': itemTypeLabel,
+                                       'object': itemObject,
+                                       'object_id': data.post_id,
+                                       'url': data.url
+                               } );
+
+                               // Add new item to menu.
+                               panel.currentMenuControl.addItemToMenu( availableItem.attributes );
+
+                               // Add the new item to the list of available items.
+                               api.Menus.availableMenuItemsPanel.collection.add( availableItem );
+                               $content = container.find( '.available-menu-items-list' );
+                               itemElement = $( wp.template( 'available-menu-item' )( availableItem.attributes ) );
+                               itemElement.find( '.menu-item-handle:first' ).addClass( 'item-added' );
+                               $content.prepend( itemElement );
+                               $content.scrollTop();
+
+                               // Reset the create content form.
+                               itemName.val( '' ).removeAttr( 'disabled' );
+                               panel.addingNew = false;
+                               container.find( '.accordion-section-title' ).removeClass( 'loading' );
+                       } );
+               },
+
                // Opens the panel.
                open: function( menuControl ) {
                        this.currentMenuControl = menuControl;
                },
 
                /**
-                * Show/hide/save screen options (columns). From common.js.
+                * Update field visibility when clicking on the field toggles.
                 */
                ready: function() {
                        var panel = this;
-                       this.container.find( '.hide-column-tog' ).click( function() {
-                               var $t = $( this ), column = $t.val();
-                               if ( $t.prop( 'checked' ) ) {
-                                       panel.checked( column );
-                               } else {
-                                       panel.unchecked( column );
-                               }
-
+                       panel.container.find( '.hide-column-tog' ).click( function() {
                                panel.saveManageColumnsState();
                        });
-                       this.container.find( '.hide-column-tog' ).each( function() {
-                       var $t = $( this ), column = $t.val();
-                               if ( $t.prop( 'checked' ) ) {
-                                       panel.checked( column );
-                               } else {
-                                       panel.unchecked( column );
-                               }
-                       });
                },
 
+               /**
+                * Save hidden column states.
+                *
+                * @since 4.3.0
+                * @private
+                *
+                * @returns {void}
+                */
                saveManageColumnsState: _.debounce( function() {
                        var panel = this;
                        if ( panel._updateHiddenColumnsRequest ) {
                        } );
                }, 2000 ),
 
-               checked: function( column ) {
-                       this.container.addClass( 'field-' + column + '-active' );
-               },
+               /**
+                * @deprecated Since 4.7.0 now that the nav_menu sections are responsible for toggling the classes on their own containers.
+                */
+               checked: function() {},
 
-               unchecked: function( column ) {
-                       this.container.removeClass( 'field-' + column + '-active' );
-               },
+               /**
+                * @deprecated Since 4.7.0 now that the nav_menu sections are responsible for toggling the classes on their own containers.
+                */
+               unchecked: function() {},
 
+               /**
+                * Get hidden fields.
+                *
+                * @since 4.3.0
+                * @private
+                *
+                * @returns {Array} Fields (columns) that are hidden.
+                */
                hidden: function() {
                        return $( '.hide-column-tog' ).not( ':checked' ).map( function() {
                                var id = this.id;
        api.Menus.MenuSection = api.Section.extend({
 
                /**
-                * @since Menu Customizer 0.3
+                * Initialize.
+                *
+                * @since 4.3.0
                 *
                 * @param {String} id
                 * @param {Object} options
                },
 
                /**
-                *
+                * Ready.
                 */
                ready: function() {
-                       var section = this;
+                       var section = this, fieldActiveToggles, handleFieldActiveToggle;
 
                        if ( 'undefined' === typeof section.params.menu_id ) {
                                throw new Error( 'params.menu_id was not defined' );
 
                        api.bind( 'pane-contents-reflowed', function() {
                                // Skip menus that have been removed.
-                               if ( ! section.container.parent().length ) {
+                               if ( ! section.contentContainer.parent().length ) {
                                        return;
                                }
                                section.container.find( '.menu-item .menu-item-reorder-nav button' ).attr({ 'tabindex': '0', 'aria-hidden': 'false' });
                                section.container.find( '.menu-item.move-left-disabled .menus-move-left' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
                                section.container.find( '.menu-item.move-right-disabled .menus-move-right' ).attr({ 'tabindex': '-1', 'aria-hidden': 'true' });
                        } );
+
+                       /**
+                        * Update the active field class for the content container for a given checkbox toggle.
+                        *
+                        * @this {jQuery}
+                        * @returns {void}
+                        */
+                       handleFieldActiveToggle = function() {
+                               var className = 'field-' + $( this ).val() + '-active';
+                               section.contentContainer.toggleClass( className, $( this ).prop( 'checked' ) );
+                       };
+                       fieldActiveToggles = api.panel( 'nav_menus' ).contentContainer.find( '.metabox-prefs:first' ).find( '.hide-column-tog' );
+                       fieldActiveToggles.each( handleFieldActiveToggle );
+                       fieldActiveToggles.on( 'click', handleFieldActiveToggle );
                },
 
                populateControls: function() {
                },
 
                /**
-                * @param {array} themeLocations
+                * @param {Array} themeLocationSlugs Theme location slugs.
                 */
                updateAssignedLocationsInSectionTitle: function( themeLocationSlugs ) {
                        var section = this,
                },
 
                onChangeExpanded: function( expanded, args ) {
-                       var section = this;
+                       var section = this, completeCallback;
 
                        if ( expanded ) {
-                               wpNavMenu.menuList = section.container.find( '.accordion-section-content:first' );
+                               wpNavMenu.menuList = section.contentContainer;
                                wpNavMenu.targetList = wpNavMenu.menuList;
 
                                // Add attributes needed by wpNavMenu
                                        }
                                } );
 
-                               if ( 'resolved' !== section.deferred.initSortables.state() ) {
-                                       wpNavMenu.initSortables(); // Depends on menu-to-edit ID being set above.
-                                       section.deferred.initSortables.resolve( wpNavMenu.menuList ); // Now MenuControl can extend the sortable.
-
-                                       // @todo Note that wp.customize.reflowPaneContents() is debounced, so this immediate change will show a slight flicker while priorities get updated.
-                                       api.control( 'nav_menu[' + String( section.params.menu_id ) + ']' ).reflowMenuItems();
+                               // Make sure Sortables is initialized after the section has been expanded to prevent `offset` issues.
+                               if ( args.completeCallback ) {
+                                       completeCallback = args.completeCallback;
                                }
+                               args.completeCallback = function() {
+                                       if ( 'resolved' !== section.deferred.initSortables.state() ) {
+                                               wpNavMenu.initSortables(); // Depends on menu-to-edit ID being set above.
+                                               section.deferred.initSortables.resolve( wpNavMenu.menuList ); // Now MenuControl can extend the sortable.
+
+                                               // @todo Note that wp.customize.reflowPaneContents() is debounced, so this immediate change will show a slight flicker while priorities get updated.
+                                               api.control( 'nav_menu[' + String( section.params.menu_id ) + ']' ).reflowMenuItems();
+                                       }
+                                       if ( _.isFunction( completeCallback ) ) {
+                                               completeCallback();
+                                       }
+                               };
                        }
                        api.Section.prototype.onChangeExpanded.call( section, expanded, args );
                }
                /**
                 * Add behaviors for the accordion section.
                 *
-                * @since Menu Customizer 0.3
+                * @since 4.3.0
                 */
                attachEvents: function() {
                        var section = this;
                onChangeExpanded: function( expanded ) {
                        var section = this,
                                button = section.container.find( '.add-menu-toggle' ),
-                               content = section.container.find( '.new-menu-section-content' ),
-                               customizer = section.container.closest( '.wp-full-overlay-sidebar-content' );
+                               content = section.contentContainer,
+                               customizer = section.headContainer.closest( '.wp-full-overlay-sidebar-content' );
                        if ( expanded ) {
                                button.addClass( 'open' );
                                button.attr( 'aria-expanded', 'true' );
                                content.slideUp( 'fast' );
                                content.find( '.menu-name-field' ).removeClass( 'invalid' );
                        }
+               },
+
+               /**
+                * Find the content element.
+                *
+                * @since 4.7.0
+                *
+                * @returns {jQuery} Content UL element.
+                */
+               getContent: function() {
+                       return this.container.find( 'ul:first' );
                }
        });
 
                },
 
                /**
-                * @since Menu Customizer 0.3
-                *
                 * Override the embed() method to do nothing,
                 * so that the control isn't embedded on load,
                 * unless the containing section is already expanded.
+                *
+                * @since 4.3.0
                 */
                embed: function() {
                        var control = this,
                 * This function is called in Section.onChangeExpanded() so the control
                 * will only get embedded when the Section is first expanded.
                 *
-                * @since Menu Customizer 0.3
+                * @since 4.3.0
                 */
                actuallyEmbed: function() {
                        var control = this;
                                }
 
                                var titleEl = control.container.find( '.menu-item-title' ),
-                                   titleText = item.title || api.Menus.data.l10n.untitled;
+                                   titleText = item.title || item.original_title || api.Menus.data.l10n.untitled;
 
                                if ( item._invalid ) {
                                        titleText = api.Menus.data.l10n.invalidTitleTpl.replace( '%s', titleText );
                                }
 
                                // Don't update to an empty title.
-                               if ( item.title ) {
+                               if ( item.title || item.original_title ) {
                                        titleEl
                                                .text( titleText )
                                                .removeClass( 'no-title' );
                 */
                expandControlSection: function() {
                        var $section = this.container.closest( '.accordion-section' );
-
                        if ( ! $section.hasClass( 'open' ) ) {
                                $section.find( '.accordion-section-title:first' ).trigger( 'click' );
                        }
                 */
                focus: function( params ) {
                        params = params || {};
-                       var control = this, originalCompleteCallback = params.completeCallback;
+                       var control = this, originalCompleteCallback = params.completeCallback, focusControl;
 
-                       control.expandControlSection();
+                       focusControl = function() {
+                               control.expandControlSection();
 
-                       params.completeCallback = function() {
-                               var focusable;
+                               params.completeCallback = function() {
+                                       var focusable;
 
-                               // Note that we can't use :focusable due to a jQuery UI issue. See: https://github.com/jquery/jquery-ui/pull/1583
-                               focusable = control.container.find( '.menu-item-settings' ).find( 'input, select, textarea, button, object, a[href], [tabindex]' ).filter( ':visible' );
-                               focusable.first().focus();
+                                       // Note that we can't use :focusable due to a jQuery UI issue. See: https://github.com/jquery/jquery-ui/pull/1583
+                                       focusable = control.container.find( '.menu-item-settings' ).find( 'input, select, textarea, button, object, a[href], [tabindex]' ).filter( ':visible' );
+                                       focusable.first().focus();
 
-                               if ( originalCompleteCallback ) {
-                                       originalCompleteCallback();
-                               }
+                                       if ( originalCompleteCallback ) {
+                                               originalCompleteCallback();
+                                       }
+                               };
+
+                               control.expandForm( params );
                        };
 
-                       control.expandForm( params );
+                       if ( api.section.has( control.section() ) ) {
+                               api.section( control.section() ).expand( {
+                                       completeCallback: focusControl
+                               } );
+                       } else {
+                               focusControl();
+                       }
                },
 
                /**
                 */
                ready: function() {
                        var control = this,
+                               section = api.section( control.section() ),
                                menuId = control.params.menu_id,
                                menu = control.setting(),
                                name,
                         * being deactivated.
                         */
                        control.active.validate = function() {
-                               var value, section = api.section( control.section() );
+                               var value;
                                if ( section ) {
                                        value = section.active();
                                } else {
                                return value;
                        };
 
-                       control.$controlSection = control.container.closest( '.control-section' );
+                       control.$controlSection = section.headContainer;
                        control.$sectionContent = control.container.closest( '.accordion-section-content' );
 
                        this._setupModel();
                                        return;
                                }
 
-                               var section = control.container.closest( '.accordion-section' ),
+                               var section = api.section( control.section() ),
                                        menuId = control.params.menu_id,
-                                       controlTitle = section.find( '.accordion-section-title' ),
-                                       sectionTitle = section.find( '.customize-section-title h3' ),
-                                       location = section.find( '.menu-in-location' ),
+                                       controlTitle = section.headContainer.find( '.accordion-section-title' ),
+                                       sectionTitle = section.contentContainer.find( '.customize-section-title h3' ),
+                                       location = section.headContainer.find( '.menu-in-location' ),
                                        action = sectionTitle.find( '.customize-action' ),
                                        name = displayNavMenuName( menu.name );
 
                                } );
 
                                // Update the nav menu name in all location checkboxes.
-                               section.find( '.customize-control-checkbox input' ).each( function() {
+                               section.contentContainer.find( '.customize-control-checkbox input' ).each( function() {
                                        if ( $( this ).prop( 'checked' ) ) {
                                                $( '.current-menu-location-name-' + $( this ).data( 'location-id' ) ).text( name );
                                        }
 
                        // Focus on the new menu section.
                        api.section( customizeId ).focus(); // @todo should we focus on the new menu's control and open the add-items panel? Thinking user flow...
-
-                       // Fix an issue with extra space at top immediately after creating new menu.
-                       $( '#menu-to-edit' ).css( 'margin-top', 0 );
                }
        });
 
                        }
                } );
 
+               /*
+                * Reset the list of posts created in the customizer once published.
+                * The setting is updated quietly (bypassing events being triggered)
+                * so that the customized state doesn't become immediately dirty.
+                */
+               api.state( 'changesetStatus' ).bind( function( status ) {
+                       if ( 'publish' === status ) {
+                               api( 'nav_menus_created_posts' )._value = [];
+                       }
+               } );
+
                // Open and focus menu control.
                api.previewer.bind( 'focus-nav-menu-item-control', api.Menus.focusMenuItemControl );
        } );
         */
        api.Menus.focusMenuItemControl = function( menuItemId ) {
                var control = api.Menus.getMenuItemControl( menuItemId );
-
                if ( control ) {
                        control.focus();
                }